فهرست منبع

Merge branch 'develop' into feature/Repetitions

# Conflicts:
#	demo/index.js
#	package.json
#	src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts
#	src/MusicalScore/VoiceData/Instructions/RepetitionInstruction.ts
Matthias Uiberacker 7 سال پیش
والد
کامیت
12c88d96e9
100فایلهای تغییر یافته به همراه4524 افزوده شده و 3221 حذف شده
  1. 91 0
      .jshintrc
  2. 1 3
      .travis.yml
  3. 26 31
      Gruntfile.js
  4. 12 11
      README.md
  5. 1 1
      bin/publish_gh_page.sh
  6. 8 3
      demo/index.html
  7. 38 25
      demo/index.js
  8. 31 12
      external/vexflow/vexflow.d.ts
  9. 41 21
      package.json
  10. 378 338
      src/Common/DataObjects/Fraction.ts
  11. 13 13
      src/Common/DataObjects/Pitch.ts
  12. 11 11
      src/Common/FileIO/Mxl.ts
  13. 8 8
      src/Common/FileIO/Xml.ts
  14. 4 4
      src/MusicalScore/Graphical/AccidentalCalculator.ts
  15. 75 33
      src/MusicalScore/Graphical/BoundingBox.ts
  16. 39 1
      src/MusicalScore/Graphical/DrawingEnums.ts
  17. 4 1
      src/MusicalScore/Graphical/EngravingRules.ts
  18. 1 2
      src/MusicalScore/Graphical/GraphicalChordSymbolContainer.ts
  19. 5 5
      src/MusicalScore/Graphical/GraphicalLabel.ts
  20. 97 97
      src/MusicalScore/Graphical/GraphicalMusicSheet.ts
  21. 10 5
      src/MusicalScore/Graphical/GraphicalNote.ts
  22. 30 30
      src/MusicalScore/Graphical/GraphicalStaffEntry.ts
  23. 4 4
      src/MusicalScore/Graphical/GraphicalStaffEntryLink.ts
  24. 201 207
      src/MusicalScore/Graphical/MusicSheetCalculator.ts
  25. 87 58
      src/MusicalScore/Graphical/MusicSheetDrawer.ts
  26. 39 44
      src/MusicalScore/Graphical/MusicSystem.ts
  27. 100 105
      src/MusicalScore/Graphical/MusicSystemBuilder.ts
  28. 10 10
      src/MusicalScore/Graphical/SelectionEndSymbol.ts
  29. 7 7
      src/MusicalScore/Graphical/SelectionStartSymbol.ts
  30. 6 10
      src/MusicalScore/Graphical/StaffLine.ts
  31. 1 1
      src/MusicalScore/Graphical/StaffLineActivitySymbol.ts
  32. 18 20
      src/MusicalScore/Graphical/StaffMeasure.ts
  33. 3 3
      src/MusicalScore/Graphical/VerticalGraphicalStaffEntryContainer.ts
  34. 66 0
      src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts
  35. 71 0
      src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts
  36. 62 0
      src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts
  37. 164 56
      src/MusicalScore/Graphical/VexFlow/VexFlowConverter.ts
  38. 1 1
      src/MusicalScore/Graphical/VexFlow/VexFlowGraphicalNote.ts
  39. 16 5
      src/MusicalScore/Graphical/VexFlow/VexFlowGraphicalSymbolFactory.ts
  40. 42 0
      src/MusicalScore/Graphical/VexFlow/VexFlowInstrumentBracket.ts
  41. 69 58
      src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts
  42. 32 35
      src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts
  43. 41 33
      src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts
  44. 12 5
      src/MusicalScore/Graphical/VexFlow/VexFlowMusicSystem.ts
  45. 2 2
      src/MusicalScore/Graphical/VexFlow/VexFlowStaffEntry.ts
  46. 1 1
      src/MusicalScore/Graphical/VexFlow/VexFlowTextMeasurer.ts
  47. 22 22
      src/MusicalScore/Instrument.ts
  48. 37 14
      src/MusicalScore/Interfaces/IGraphicalSymbolFactory.ts
  49. 4 4
      src/MusicalScore/MusicParts/MusicPartManager.ts
  50. 34 34
      src/MusicalScore/MusicParts/MusicPartManagerIterator.ts
  51. 19 19
      src/MusicalScore/MusicSheet.ts
  52. 9 9
      src/MusicalScore/MusicSource/Repetition.ts
  53. 962 961
      src/MusicalScore/ScoreIO/InstrumentReader.ts
  54. 94 94
      src/MusicalScore/ScoreIO/MusicSheetReader.ts
  55. 144 0
      src/MusicalScore/ScoreIO/MusicSymbolModules/ChordSymbolReader.ts
  56. 4 6
      src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionCalculator.ts
  57. 39 39
      src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionInstructionReader.ts
  58. 133 122
      src/MusicalScore/ScoreIO/VoiceGenerator.ts
  59. 36 36
      src/MusicalScore/SubInstrument.ts
  60. 1 1
      src/MusicalScore/VoiceData/Expressions/AbstractExpression.ts
  61. 1 1
      src/MusicalScore/VoiceData/Expressions/AbstractTempoExpression.ts
  62. 3 3
      src/MusicalScore/VoiceData/Expressions/ContinuousExpressions/ContinuousDynamicExpression.ts
  63. 3 3
      src/MusicalScore/VoiceData/Expressions/ContinuousExpressions/ContinuousTempoExpression.ts
  64. 5 5
      src/MusicalScore/VoiceData/Expressions/ContinuousExpressions/Slur.ts
  65. 11 11
      src/MusicalScore/VoiceData/Expressions/InstantaniousDynamicExpression.ts
  66. 2 2
      src/MusicalScore/VoiceData/Expressions/MultiExpression.ts
  67. 1 1
      src/MusicalScore/VoiceData/Expressions/MultiTempoExpression.ts
  68. 3 3
      src/MusicalScore/VoiceData/Instructions/ClefInstruction.ts
  69. 13 6
      src/MusicalScore/VoiceData/Instructions/KeyInstruction.ts
  70. 3 3
      src/MusicalScore/VoiceData/Instructions/RepetitionInstruction.ts
  71. 6 6
      src/MusicalScore/VoiceData/Instructions/RhythmInstruction.ts
  72. 2 2
      src/MusicalScore/VoiceData/Lyrics/LyricsWord.ts
  73. 4 4
      src/MusicalScore/VoiceData/Note.ts
  74. 30 30
      src/MusicalScore/VoiceData/SourceMeasure.ts
  75. 9 9
      src/MusicalScore/VoiceData/SourceStaffEntry.ts
  76. 1 1
      src/MusicalScore/VoiceData/Tie.ts
  77. 1 1
      src/MusicalScore/VoiceData/Tuplet.ts
  78. 0 2
      src/MusicalScore/VoiceData/VerticalSourceStaffEntryContainer.ts
  79. 50 50
      src/MusicalScore/VoiceData/VoiceEntry.ts
  80. 133 133
      src/OSMD/Cursor.ts
  81. 43 34
      src/OSMD/OSMD.ts
  82. 3 3
      src/Util/CollectionUtil.ts
  83. 1 1
      src/Util/PSMath.ts
  84. 2 35
      test/Common/DataObjects/Fraction_Test.ts
  85. 25 25
      test/Common/DataObjects/Pitch_Test.ts
  86. 5 4
      test/Common/FileIO/Mxl_Test.ts
  87. 11 11
      test/Common/FileIO/Xml_Test.ts
  88. 32 32
      test/Common/OSMD/OSMD_Test.ts
  89. 76 0
      test/MusicalScore/Graphical/VexFlow/VexFlowConverter_Clef_Test.ts
  90. 17 16
      test/MusicalScore/Graphical/VexFlow/VexFlowMeasure_Test.ts
  91. 25 18
      test/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer_Test.ts
  92. 8 24
      test/MusicalScore/ScoreCalculation/MusicSheetCalculator_Test.ts
  93. 358 0
      test/MusicalScore/ScoreIO/Key_Test.ts
  94. 12 22
      test/MusicalScore/ScoreIO/MusicSheetReader_Test.ts
  95. 4 4
      test/Util/TestUtils.ts
  96. 37 0
      test/data/HelloWorld.xml
  97. BIN
      test/data/Parlez-moi.mxl
  98. 4 23
      tslint.json
  99. 0 12
      typings.json
  100. 63 0
      webpack.config.js

+ 91 - 0
.jshintrc

@@ -0,0 +1,91 @@
+{
+    // JSHint Default Configuration File (as on JSHint website)
+    // See http://jshint.com/docs/ for more details
+
+    "maxerr"        : 50,       // {int} Maximum error before stopping
+
+    // Enforcing
+    "bitwise"       : true,     // true: Prohibit bitwise operators (&, |, ^, etc.)
+    "camelcase"     : true,     // true: Identifiers must be in camelCase
+    "curly"         : true,     // true: Require {} for every new block or scope
+    "eqeqeq"        : true,     // true: Require triple equals (===) for comparison
+    "forin"         : true,     // true: Require filtering for..in loops with obj.hasOwnProperty()
+    "freeze"        : true,     // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
+    "immed"         : false,    // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
+    "latedef"       : false,    // true: Require variables/functions to be defined before being used
+    "newcap"        : false,    // true: Require capitalization of all constructor functions e.g. `new F()`
+    "noarg"         : true,     // true: Prohibit use of `arguments.caller` and `arguments.callee`
+    "noempty"       : true,     // true: Prohibit use of empty blocks
+    "nonbsp"        : true,     // true: Prohibit "non-breaking whitespace" characters.
+    "nonew"         : false,    // true: Prohibit use of constructors for side-effects (without assignment)
+    "plusplus"      : false,    // true: Prohibit use of `++` and `--`
+    "quotmark"      : true,     // Quotation mark consistency:
+                                //   false    : do nothing (default)
+                                //   true     : ensure whatever is used is consistent
+                                //   "single" : require single quotes
+                                //   "double" : require double quotes
+    "undef"         : true,     // true: Require all non-global variables to be declared (prevents global leaks)
+    "unused"        : true,     // Unused variables:
+                                //   true     : all variables, last function parameter
+                                //   "vars"   : all variables only
+                                //   "strict" : all variables, all function parameters
+    "strict"        : true,     // true: Requires all functions run in ES5 Strict Mode
+    "maxparams"     : false,    // {int} Max number of formal params allowed per function
+    "maxdepth"      : false,    // {int} Max depth of nested blocks (within functions)
+    "maxstatements" : false,    // {int} Max number statements per function
+    "maxcomplexity" : false,    // {int} Max cyclomatic complexity per function
+    "maxlen"        : false,    // {int} Max number of characters per line
+    "varstmt"       : false,    // true: Disallow any var statements. Only `let` and `const` are allowed.
+
+    // Relaxing
+    "asi"           : false,     // true: Tolerate Automatic Semicolon Insertion (no semicolons)
+    "boss"          : false,     // true: Tolerate assignments where comparisons would be expected
+    "debug"         : false,     // true: Allow debugger statements e.g. browser breakpoints.
+    "eqnull"        : false,     // true: Tolerate use of `== null`
+    "esversion"     : 5,         // {int} Specify the ECMAScript version to which the code must adhere.
+    "moz"           : false,     // true: Allow Mozilla specific syntax (extends and overrides esnext features)
+                                 // (ex: `for each`, multiple try/catch, function expression…)
+    "evil"          : false,     // true: Tolerate use of `eval` and `new Function()`
+    "expr"          : false,     // true: Tolerate `ExpressionStatement` as Programs
+    "funcscope"     : false,     // true: Tolerate defining variables inside control statements
+    "globalstrict"  : false,     // true: Allow global "use strict" (also enables 'strict')
+    "iterator"      : false,     // true: Tolerate using the `__iterator__` property
+    "lastsemic"     : false,     // true: Tolerate omitting a semicolon for the last statement of a 1-line block
+    "laxbreak"      : false,     // true: Tolerate possibly unsafe line breakings
+    "laxcomma"      : false,     // true: Tolerate comma-first style coding
+    "loopfunc"      : false,     // true: Tolerate functions being defined in loops
+    "multistr"      : false,     // true: Tolerate multi-line strings
+    "noyield"       : false,     // true: Tolerate generator functions with no yield statement in them.
+    "notypeof"      : false,     // true: Tolerate invalid typeof operator values
+    "proto"         : false,     // true: Tolerate using the `__proto__` property
+    "scripturl"     : false,     // true: Tolerate script-targeted URLs
+    "shadow"        : false,     // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
+    "sub"           : false,     // true: Tolerate using `[]` notation when it can still be expressed in dot notation
+    "supernew"      : false,     // true: Tolerate `new function () { ... };` and `new Object;`
+    "validthis"     : false,     // true: Tolerate using this in a non-constructor function
+
+    // Environments
+    "browser"       : true,     // Web Browser (window, document, etc)
+    "browserify"    : false,    // Browserify (node.js code in the browser)
+    "couch"         : false,    // CouchDB
+    "devel"         : true,     // Development/debugging (alert, confirm, etc)
+    "dojo"          : false,    // Dojo Toolkit
+    "jasmine"       : false,    // Jasmine
+    "jquery"        : false,    // jQuery
+    "mocha"         : true,     // Mocha
+    "mootools"      : false,    // MooTools
+    "node"          : true,    // Node.js
+    "nonstandard"   : false,    // Widely adopted globals (escape, unescape, etc)
+    "phantom"       : false,    // PhantomJS
+    "prototypejs"   : false,    // Prototype and Scriptaculous
+    "qunit"         : false,    // QUnit
+    "rhino"         : false,    // Rhino
+    "shelljs"       : false,    // ShellJS
+    "typed"         : false,    // Globals for typed array constructions
+    "worker"        : false,    // Web Workers
+    "wsh"           : false,    // Windows Scripting Host
+    "yui"           : false,    // Yahoo User Interface
+
+    // Custom Globals
+    "globals"       : {}        // additional predefined global variables
+}

+ 1 - 3
.travis.yml

@@ -17,6 +17,7 @@ deploy:
     branch: master
     repo: opensheetmusicdisplay/opensheetmusicdisplay
 after_deploy:
+- openssl aes-256-cbc -K $encrypted_170846311824_key -iv $encrypted_170846311824_iv -in bin/gh_pages_deploy_key.enc -out bin/gh_pages_deploy_key -d
 - eval "$(ssh-agent -s)"
 - chmod 600 bin/gh_pages_deploy_key
 - ssh-add bin/gh_pages_deploy_key
@@ -24,6 +25,3 @@ after_deploy:
 - git config --global user.name "travis"
 - chmod +x ./bin/publish_gh_page.sh
 - ./bin/publish_gh_page.sh
-before_install:
-- openssl aes-256-cbc -K $encrypted_170846311824_key -iv $encrypted_170846311824_iv
-  -in bin/gh_pages_deploy_key.enc -out bin/gh_pages_deploy_key -d

+ 26 - 31
Gruntfile.js

@@ -1,4 +1,6 @@
 /*global module*/
+var webpackCfg = require('./webpack.config.js');
+
 module.exports = function (grunt) {
     'use strict';
 
@@ -34,7 +36,7 @@ module.exports = function (grunt) {
                 src: ['src/OSMD/OSMD.ts'],
                 dest: '<%= outputDir.build %>/osmd.js',
                 options: {
-                    banner: "<%= banner %>",
+                    banner: '<%= banner %>',
                     browserifyOptions: {
                         standalone: 'opensheetmusicdisplay'
                     }
@@ -44,10 +46,10 @@ module.exports = function (grunt) {
                 src: ['src/OSMD/OSMD.ts'],
                 dest: '<%= outputDir.build %>/osmd-debug.js',
                 options: {
-                    banner: "<%= banner %>",
+                    banner: '<%= banner %>',
                     browserifyOptions: {
                         debug: true,
-                        standalone: 'opensheetmusicdisplay'                        
+                        standalone: 'opensheetmusicdisplay'
                     }
                 }
             },
@@ -55,7 +57,7 @@ module.exports = function (grunt) {
                 src: [].concat(typings, src, test),
                 dest: '<%= outputDir.build %>/osmd-test.js',
                 options: {
-                    banner: "<%= banner %>",
+                    banner: '<%= banner %>',
                     browserifyOptions: {
                         debug: true
                     }
@@ -69,7 +71,7 @@ module.exports = function (grunt) {
         uglify: {
             options: {
                 compress: {
-                    drop_console: true
+                    'drop_console': true
                 },
                 banner: banner,
                 mangle: true,
@@ -81,6 +83,20 @@ module.exports = function (grunt) {
                 }
             }
         },
+        // Webpack
+        webpack: {
+          options: {
+            progress: true,
+          },
+          build: webpackCfg,
+          dev: Object.assign({ watch: true }, webpackCfg)
+        },
+        'webpack-dev-server': {
+          options: {
+              webpack: webpackCfg
+          },
+          start: webpackCfg.devServer,
+        },
         // Karma setup
         karma: {
             // For continuous integration
@@ -105,25 +121,6 @@ module.exports = function (grunt) {
                 }
             }
         },
-        // TSLint setup
-        tslint: {
-            options: {
-                configuration: 'tslint.json'
-            },
-            all: {
-                src: [].concat(src, test)
-            }
-        },
-        // JsHint setup
-        jshint: {
-            all: [
-                'Gruntfile.js', 'karma.conf.js', 'demo/**/*.js'
-            ]
-        },
-        // TypeScript Type Definitions
-        typings: {
-            install: {}
-        },
         // Typescript compilation for ES6 module (npm package)
         ts: {
           default : {
@@ -172,26 +169,24 @@ module.exports = function (grunt) {
     grunt.loadNpmTasks('grunt-browserify');
     grunt.loadNpmTasks('grunt-contrib-clean');
     grunt.loadNpmTasks('grunt-contrib-copy');
-    grunt.loadNpmTasks('grunt-contrib-jshint');
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.loadNpmTasks('grunt-contrib-watch');
     grunt.loadNpmTasks('grunt-http-server');
     grunt.loadNpmTasks('grunt-karma');
     grunt.loadNpmTasks('grunt-ts');
-    grunt.loadNpmTasks('grunt-tslint');
-    grunt.loadNpmTasks('grunt-typings');
-
-    // Code quality
-    grunt.registerTask('lint',        'Lints all JavaScript and TypeScript files.',  ['jshint', 'tslint']);
+    grunt.loadNpmTasks('grunt-webpack');
 
     // Build tasks
     grunt.registerTask('build:demo',  'Builds the demo.',                            ['browserify:debug', 'copy:demo']);
     grunt.registerTask('build:test',  'Builds the tests',                            ['browserify:test']);
     grunt.registerTask('build:dist',  'Builds for distribution on npm and Bower.',   ['browserify:dist', 'uglify', 'ts']);
+    grunt.registerTask('build:pack',  'Builds using webpack',                        ['webpack:build', 'uglify']);
 
     // Tests
     grunt.registerTask('test',        'Runs unit, regression and e2e tests.',        ['build:test', 'karma:ci']);
 
+    // Webpack dev server
+    grunt.registerTask('webpack-server', ['webpack-dev-server:start']);
     // Default task (if grunt is run without any argument, used in contiuous integration)
-    grunt.registerTask('default',     'Default task, running all other tasks. (CI)', ['lint', 'test', 'build:demo', 'build:dist']);
+    grunt.registerTask('default',     'Default task, running all other tasks. (CI)', ['test', 'build:demo', 'build:dist']);
 };

+ 12 - 11
README.md

@@ -1,23 +1,24 @@
-<p align="center">
-  <img alt="OSMD logo" src="http://opensheetmusicdisplay.org/wp-content/uploads/2015/03/OSMD_3_icon.png" width="200"/>
-</p>
+<img alt="OSMD logo" src="http://opensheetmusicdisplay.org/assets/osmd_logo.svg" width="200"/>
 
-# Open Sheet Music Display
+# OpenSheetMusicDisplay
 
 [![Greenkeeper badge](https://badges.greenkeeper.io/opensheetmusicdisplay/opensheetmusicdisplay.svg)](https://greenkeeper.io/)
 [![Build Status](https://travis-ci.org/opensheetmusicdisplay/opensheetmusicdisplay.svg?branch=master)](https://travis-ci.org/opensheetmusicdisplay/opensheetmusicdisplay)
 [![Dependency Status](https://david-dm.org/opensheetmusicdisplay/opensheetmusicdisplay.png)](https://david-dm.org/opensheetmusicdisplay/opensheetmusicdisplay)
-[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/opensheetmusicdisplay/opensheetmusicdisplay?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/opensheetmusicdisplay/opensheetmusicdisplay?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Code Climate](https://codeclimate.com/github/opensheetmusicdisplay/opensheetmusicdisplay/badges/gpa.svg)](https://codeclimate.com/github/opensheetmusicdisplay/opensheetmusicdisplay)
+[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
 
-Display sheet music ([MusicXML](http://www.musicxml.com) files) in the browser.
-Using the [VexFlow](https://github.com/0xfe/vexflow) music notation rendering API.
-Written in [TypeScript](https://www.typescriptlang.org) and released under [MIT license](#license).
+http://www.opensheetmusicdisplay.org/
 
-How to **build**, how to **install**, how to **use**, ...? Have a look at the [GitHub Wiki](https://github.com/opensheetmusicdisplay/opensheetmusicdisplay/wiki)!
+OpenSheeMusicDisplay is the missing link between MusicXML and VexFlow. Built upon many years of experience in both sheet music interactivity and engraving, it is the perfect solution for app developers seeking to build digital sheet music services.
 
-All the code is hosted at [GitHub](https://github.com/opensheetmusicdisplay/opensheetmusicdisplay).
+MusicXML is the de facto standard for sharing sheet music on the internet. VexFlow is widely used for rendering sheet music. It features an extensive note sign library attributable to its open source nature.
+
+OpenSheetMusicDisplay brings the two together and offers an open source turnkey solution for your digital sheet music project.
+
+Written in [TypeScript](https://www.typescriptlang.org) and released under [MIT license](https://github.com/opensheetmusicdisplay/opensheetmusicdisplay/blob/develop/LICENSE).
 
-Go to [opensheetmusicdisplay.org](http://opensheetmusicdisplay.org) for further information.
 
 <!--# <a name="license"></a>License
 The MIT License (MIT)

+ 1 - 1
bin/publish_gh_page.sh

@@ -10,7 +10,7 @@ cd opensheetmusicdisplay.github.io
 git status
 
 # Copy class documentation
-rsync -a ../build/docs/* ./
+rsync -a ../build/docs/* ./classdoc
 
 # Copy demo application
 rsync -a ../build/demo/* ./demo

+ 8 - 3
demo/index.html

@@ -8,11 +8,11 @@
     <meta name="author" content="OpenSheetMusicDisplay contributors">
 
     <!-- Include opensheetmusicdisplay -->
-    <script src="osmd-debug.js"></script>
+    <!-- <script src="./osmd.js" type="text/javascript"></script> -->
 
     <!-- Include code and styles for this demo -->
-    <script src="demo.js"></script>
-    <link href="demo.css" media="all" rel="stylesheet"/>
+    <script src="./demo.js" type="text/javascript"></script>
+    <link href="./demo.css" media="all" rel="stylesheet"/>
     <link rel="icon" href="./favicon.ico?" type="image/x-icon"/>
 </head>
 <body>
@@ -34,6 +34,11 @@
             <p>... or just drop your MusicXML file on this page.</p>
         </td>
         <td valign="top" halign="right">
+            <p>Renderer Backend
+                <select id="backend-select" value="canvas">
+                    <option value="canvas">Canvas</option>>
+                    <option value="svg">SVG</option>
+                </select>
             <p>Cursor controls:
                 <input type="button" value="show" id="show-cursor-btn"/>
                 <input type="button" value="hide" id="hide-cursor-btn"/>

+ 38 - 25
demo/demo.js → demo/index.js

@@ -1,20 +1,14 @@
+import { OSMD } from '../src/OSMD/OSMD';
+
 /*jslint browser:true */
 (function () {
     "use strict";
-    var OSMD;
+    var osmdObj;
     // The folder of the demo files
-    var folder = "sheets/",
+    var folder = "",
     // The available demos
         demos = {
-            "Actor Prelude Sample": "ActorPreludeSample.xml",
-            "Beethoven - An Fie Ferne Geliebte": "AnDieFerneGeliebte_Beethoven.xml",
-            "C. Gounod - Meditation": "CharlesGounod_Meditation.xml",
-            "Debussy - Mandoline": "mandoline - debussy.xml",
-            "Dichterliebe": "Dichterliebe01.xml",
-            "G.P. Telemann - Sonata, TWV 40:102 - 1. Dolce": "TelemannWV40.102_Sonate-Nr.1.1-Dolce.xml",
-            "J. Haydn - Concertante Cello": "JosephHaydn_ConcertanteCello.xml",
-            "J.S. Bach - Air": "JohannSebastianBach_Air.xml",
-            "J.S. Bach - Praeludium In C Dur BWV846 1": "JohannSebastianBach_PraeludiumInCDur_BWV846_1.xml",
+            "Beethoven - AnDieFerneGeliebte": "Beethoven_AnDieFerneGeliebte.xml",
             "M. Clementi - Sonatina Op.36 No.1 Pt.1": "MuzioClementi_SonatinaOpus36No1_Part1.xml",
             "M. Clementi - Sonatina Op.36 No.1 Pt.2": "MuzioClementi_SonatinaOpus36No1_Part2.xml",
             "M. Clementi - Sonatina Op.36 No.3 Pt.1": "MuzioClementi_SonatinaOpus36No3_Part1.xml",
@@ -24,7 +18,14 @@
             "Mozart - Trio": "MozartTrio.mxl",
             "S. Joplin - Elite Syncopations": "ScottJoplin_EliteSyncopations.xml",
             "S. Joplin - The Entertainer": "ScottJoplin_The_Entertainer.xml",
-            "Saltarello": "Saltarello.mxl"
+            "ActorPreludeSample": "ActorPreludeSample.xml",
+            "an chloe - mozart": "an chloe - mozart.xml",
+            "das veilchen - mozart": "das veilchen - mozart.xml",
+            "Dichterliebe01": "Dichterliebe01.xml",
+            "mandoline - debussy": "mandoline - debussy.xml",
+            "MozartTrio": "MozartTrio.mxl",
+            "Cornelius P. Christbaum Opus 8.1": "Cornelius_P_Christbaum_Opus_8_1_1865.mxl",
+            "France Levasseur - Parlez Mois": "Parlez-moi.mxl",
         },
 
         zoom = 1.0,
@@ -41,7 +42,8 @@
         nextCursorBtn,
         resetCursorBtn,
         showCursorBtn,
-        hideCursorBtn;
+        hideCursorBtn,
+        backendSelect;
 
     // Initialization code
     function init() {
@@ -60,6 +62,7 @@
         resetCursorBtn = document.getElementById("reset-cursor-btn");
         showCursorBtn = document.getElementById("show-cursor-btn");
         hideCursorBtn = document.getElementById("hide-cursor-btn");
+        backendSelect = document.getElementById("backend-select");
 
         // Hide error
         error();
@@ -91,8 +94,8 @@
         };
 
         // Create OSMD object and canvas
-        OSMD = new opensheetmusicdisplay.OSMD(canvas);
-        OSMD.setLogLevel('info');
+        osmdObj = new OSMD(canvas, false);
+        osmdObj.setLogLevel('info');
         document.body.appendChild(canvas);
 
         // Set resize event handler
@@ -104,7 +107,7 @@
                 var width = document.body.clientWidth;
                 canvas.width = width;
                 try {
-                OSMD.render();
+                osmdObj.render();
                 } catch (e) {}
                 enable();
             }
@@ -113,20 +116,30 @@
         window.addEventListener("keydown", function(e) {
             var event = window.event ? window.event : e;
             if (event.keyCode === 39) {
-                OSMD.cursor.next();
+                osmdObj.cursor.next();
             }
         });
         nextCursorBtn.addEventListener("click", function() {
-            OSMD.cursor.next();
+            osmdObj.cursor.next();
         });
         resetCursorBtn.addEventListener("click", function() {
-            OSMD.cursor.reset();
+            osmdObj.cursor.reset();
         });
         hideCursorBtn.addEventListener("click", function() {
-            OSMD.cursor.hide();
+            osmdObj.cursor.hide();
         });
         showCursorBtn.addEventListener("click", function() {
-            OSMD.cursor.show();
+            osmdObj.cursor.show();
+        });
+
+        backendSelect.addEventListener("change", function(e) {
+            var value = e.target.value;
+            // clears the canvas element
+            canvas.innerHTML = "";
+            osmdObj = new OSMD(canvas, false, value);
+            osmdObj.setLogLevel('info');
+            selectOnChange();
+
         });
     }
 
@@ -166,9 +179,9 @@
             str = folder + select.value;
         }
         zoom = 1.0;
-        OSMD.load(str).then(
+        osmdObj.load(str).then(
             function() {
-                return OSMD.render();
+                return osmdObj.render();
             },
             function(e) {
                 error("Error reading sheet: " + e);
@@ -200,8 +213,8 @@
     function scale() {
         disable();
         window.setTimeout(function(){
-            OSMD.zoom = zoom;
-            OSMD.render();
+            osmdObj.zoom = zoom;
+            osmdObj.render();
             enable();
         }, 0);
     }

+ 31 - 12
external/vexflow/vexflow.d.ts

@@ -68,7 +68,7 @@ declare namespace Vex {
         export class StaveTie {
             constructor(notes_struct: any);
 
-            public setContext(ctx: CanvasContext): StaveTie;
+            public setContext(ctx: RenderContext): StaveTie;
 
             public draw(): void;
         }
@@ -111,7 +111,7 @@ declare namespace Vex {
             public getLineForY(y: number): number;
 
             public getModifiers(pos: any, cat: any): Clef[]; // FIXME
-            public setContext(ctx: CanvasContext): Stave;
+            public setContext(ctx: RenderContext): Stave;
 
             public addModifier(mod: any, pos: any): void;
 
@@ -148,13 +148,18 @@ declare namespace Vex {
         }
 
         export class Renderer {
-            constructor(canvas: HTMLCanvasElement, backend: any);
+            constructor(canvas: HTMLElement, backend: number);
 
-            public static Backends: any;
+            public static Backends: {
+                CANVAS: number,
+                RAPHAEL: number,
+                SVG: number,
+                VML: number
+            };
 
             public resize(a: number, b: number): void;
 
-            public getContext(): CanvasContext;
+            public getContext(): CanvasContext|SVGContext;
         }
 
         export class TimeSignature {
@@ -175,21 +180,36 @@ declare namespace Vex {
         export class Beam {
             constructor(notes: StaveNote[], auto_stem: boolean);
 
-            public setContext(ctx: CanvasContext): Beam;
+            public setContext(ctx: RenderContext): Beam;
 
             public draw(): void;
         }
 
         export class Tuplet {
-            constructor(notes: StaveNote[]);
+            constructor(notes: StaveNote[], options: any);
 
-            public setContext(ctx: CanvasContext): Tuplet;
+            public setContext(ctx: RenderContext): Tuplet;
 
             public draw(): void;
         }
 
-        export class CanvasContext {
-            public scale(x: number, y: number): CanvasContext;
+        export class RenderContext {
+            public scale(x: number, y: number): RenderContext;
+            public fillRect(x: number, y: number, width: number, height: number): RenderContext
+            public fillText(text: string, x: number, y: number): RenderContext;
+            public setFont(family: string, size: number, weight: string): RenderContext;
+            public save(): RenderContext;
+            public restore(): RenderContext;
+        }
+
+        export class CanvasContext extends RenderContext {
+            public vexFlowCanvasContext: CanvasRenderingContext2D;
+        }
+
+        export class SVGContext extends RenderContext {
+            public svg: SVGElement;
+            public attributes: any;
+            public state: any;
         }
 
         export class StaveConnector {
@@ -199,11 +219,10 @@ declare namespace Vex {
 
             public setType(type: any): StaveConnector;
 
-            public setContext(ctx: CanvasContext): StaveConnector;
+            public setContext(ctx: RenderContext): StaveConnector;
 
             public draw(): void;
         }
-
     }
 }
 

+ 41 - 21
package.json

@@ -1,17 +1,22 @@
 {
   "name": "opensheetmusicdisplay",
-  "version": "0.1.0",
+  "version": "0.2.1",
   "description": "An open source JavaScript engine for displaying MusicXML based on VexFlow.",
   "main": "dist/src/OSMD/OSMD.js",
   "typings": "dist/src/OSMD/OSMD",
   "scripts": {
     "docs": "typedoc --mode file --out build/docs --module commonjs --target ES5 --name opensheetmusicdisplay ./src",
-    "postinstall": "grunt typings",
+    "lint": "npm run jshint && npm run tslint",
+    "jshint": "jshint . --exclude node_modules,dist,build,bin,demo",
+    "test": "npm run lint && grunt test",
+    "tslint": "tslint --project tsconfig.json \"src/**/*.ts\" \"test/**/*.ts\"",
+    "typedoc": "typedoc --out ./build/docs --name OpenSheetMusicDisplay --module commonjs --target ES5 --mode file ./src/**/*.ts",
     "prepublish": "grunt build:dist",
-    "server": "http-server",
-    "start": "npm run server -- build/demo",
-    "test": "grunt test"
+    "start": "http-server build/demo"
   },
+  "pre-commit": [
+    "lint"
+  ],
   "files": [
     "dist",
     "AUTHORS",
@@ -19,12 +24,10 @@
     "README.md",
     "karma.conf.js",
     "src",
-    "test",
     "external",
     "demo",
-    "tsconfig",
+    "tsconfig.json",
     "tslint.json",
-    "typings.json",
     "Gruntfile.js"
   ],
   "repository": {
@@ -46,27 +49,35 @@
   "dependencies": {
     "es6-promise": "^4.0.5",
     "jszip": "^3.0.0",
-    "loglevel": "^1.4.1",
+    "loglevel": "^1.5.0",
     "shortid": "^2.2.6",
     "typescript-collections": "^1.1.2",
     "vexflow": "^1.2.53"
   },
   "devDependencies": {
-    "browserify": "^14.0.0",
-    "chai": "^3.5.0",
+    "@types/chai": "^4.0.3",
+    "@types/loglevel": "^1.4.29",
+    "@types/mocha": "^2.2.40",
+    "babel-core": "^6.26.0",
+    "babel-loader": "^7.1.2",
+    "babel-preset-es2015": "^6.24.1",
+    "browserify": "^16.1.0",
+    "chai": "^4.1.0",
+    "cz-conventional-changelog": "^2.0.0",
     "grunt": "^1.0.1",
     "grunt-browserify": "^5.0.0",
     "grunt-contrib-clean": "^1.0.0",
     "grunt-contrib-copy": "^1.0.0",
-    "grunt-contrib-jshint": "^1.0.0",
-    "grunt-contrib-uglify": "^2.0.0",
+    "grunt-contrib-uglify": "^3.0.0",
     "grunt-contrib-watch": "^1.0.0",
     "grunt-http-server": "",
     "grunt-karma": "^2.0.0",
     "grunt-ts": "^6.0.0-beta.3",
-    "grunt-tslint": "^4.0.0",
-    "grunt-typings": "^0.1.5",
-    "http-server": "^0.9.0",
+    "grunt-webpack": "^3.0.0",
+    "grunt-webpack-server": "^0.1.0",
+    "http-server": "^0.11.0",
+    "jquery": "^3.2.1",
+    "jshint": "^2.9.4",
     "karma": "^1.1.1",
     "karma-base64-to-js-preprocessor": "^0.0.1",
     "karma-chai": "^0.1.0",
@@ -76,12 +87,21 @@
     "karma-mocha-reporter": "^2.0.4",
     "karma-phantomjs-launcher": "^1.0.1",
     "karma-xml2js-preprocessor": "^0.0.3",
-    "mocha": "^3.0.1",
+    "mocha": "^4.0.0",
     "phantomjs-prebuilt": "^2.1.8",
+    "pre-commit": "^1.2.2",
+    "ts-loader": "^3.0.0",
     "tsify": "^3.0.0",
-    "tslint": "^4.3.1",
-    "typedoc": "^0.5.7",
-    "typescript": "^2.2.1",
-    "typings": "^2.0.0"
+    "tslint": "^5.8.0",
+    "typedoc": "^0.10.0",
+    "typescript": "^2.6.1",
+    "uglifyjs-webpack-plugin": "^1.0.1",
+    "webpack": "^3.5.5",
+    "webpack-dev-server": "2.7.1"
+  },
+  "config": {
+    "commitizen": {
+      "path": "./node_modules/cz-conventional-changelog"
+    }
   }
 }

+ 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 {
+    const sum: Fraction = f1.clone();
+    sum.Add(f2);
+    return sum;
+  }
+
+  public static minus(f1: Fraction, f2: Fraction): Fraction {
+    const 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();
+    const 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) {
+      const 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 {
+    const 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;
-    }
+    const 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);
+    const 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) {
+      const 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) {
+      const 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
 }

+ 13 - 13
src/Common/DataObjects/Pitch.ts

@@ -64,7 +64,7 @@ export class Pitch {
      * @constructor
      */
     public static CalculateTransposedHalfTone(pitch: Pitch, transpose: number): { value: number; overflow: number; } {
-        let newHalfTone: number = <number>pitch.fundamentalNote + <number>pitch.accidental + transpose;
+        const newHalfTone: number = <number>pitch.fundamentalNote + <number>pitch.accidental + transpose;
         return Pitch.WrapAroundCheck(newHalfTone, 12);
     }
 
@@ -91,12 +91,12 @@ export class Pitch {
         let halftoneSteps: number;
         if (obj instanceof Pitch) {
             // obj is a pitch
-            let pitch: Pitch = obj;
+            const pitch: Pitch = obj;
             octaveSteps = pitch.octave - 1;
             halftoneSteps = <number>pitch.fundamentalNote - <number>NoteEnum.A + <number>pitch.accidental;
         } else if (typeof obj === "number") {
             // obj is a fractional key
-            let fractionalKey: number = obj;
+            const fractionalKey: number = obj;
             halftoneSteps = fractionalKey - 57.0;
         }
         // Return frequency:
@@ -109,9 +109,9 @@ export class Pitch {
     }
 
     public static fromFrequency(frequency: number): Pitch {
-        let key: number = Pitch.calcFractionalKey(frequency) + 0.5;
-        let octave: number = Math.floor(key / 12) - Pitch.octXmlDiff;
-        let halftone: number = Math.floor(key) % 12;
+        const key: number = Pitch.calcFractionalKey(frequency) + 0.5;
+        const octave: number = Math.floor(key / 12) - Pitch.octXmlDiff;
+        const halftone: number = Math.floor(key) % 12;
         let fundamentalNote: NoteEnum = <NoteEnum>halftone;
         let accidental: AccidentalEnum = AccidentalEnum.NONE;
         if (this.pitchEnumValues.indexOf(fundamentalNote) === -1) {
@@ -122,8 +122,8 @@ export class Pitch {
     }
 
     public static fromHalftone(halftone: number): Pitch {
-        let octave: number = <number>Math.floor(<number>halftone / 12) - Pitch.octXmlDiff;
-        let halftoneInOctave: number = halftone % 12;
+        const octave: number = <number>Math.floor(<number>halftone / 12) - Pitch.octXmlDiff;
+        const halftoneInOctave: number = halftone % 12;
         let fundamentalNote: NoteEnum = <NoteEnum>halftoneInOctave;
         let accidental: AccidentalEnum = AccidentalEnum.NONE;
         if (this.pitchEnumValues.indexOf(fundamentalNote) === -1) {
@@ -222,7 +222,7 @@ export class Pitch {
     }
 
     public OperatorEquals(p2: Pitch): boolean {
-        let p1: Pitch = this;
+        const p1: Pitch = this;
         // if (ReferenceEquals(p1, p2)) {
         //     return true;
         // }
@@ -233,13 +233,13 @@ export class Pitch {
     }
 
     public OperatorNotEqual(p2: Pitch): boolean {
-        let p1: Pitch = this;
+        const p1: Pitch = this;
         return !(p1 === p2);
     }
 
     // This method returns a new Pitch factor-Halftones higher than the current Pitch
     private getHigherPitchByTransposeFactor(factor: number): Pitch {
-        let noteEnumIndex: number = Pitch.pitchEnumValues.indexOf(this.fundamentalNote);
+        const noteEnumIndex: number = Pitch.pitchEnumValues.indexOf(this.fundamentalNote);
         let newOctave: number = this.octave;
         let newNoteEnum: NoteEnum;
         if (noteEnumIndex + factor > Pitch.pitchEnumValues.length - 1) {
@@ -252,7 +252,7 @@ export class Pitch {
     }
 
     private getLowerPitchByTransposeFactor(factor: number): Pitch {
-        let noteEnumIndex: number = Pitch.pitchEnumValues.indexOf(this.fundamentalNote);
+        const noteEnumIndex: number = Pitch.pitchEnumValues.indexOf(this.fundamentalNote);
         let newOctave: number = this.octave;
         let newNoteEnum: NoteEnum;
         if (noteEnumIndex - factor < 0) {
@@ -271,7 +271,7 @@ export class Pitch {
     }
 
     private getPreviousFundamentalNote(fundamental: NoteEnum): NoteEnum {
-        let i: number = Pitch.pitchEnumValues.indexOf(fundamental);
+        const i: number = Pitch.pitchEnumValues.indexOf(fundamental);
         if (i > 0) {
             return Pitch.pitchEnumValues[i - 1];
         } else {

+ 11 - 11
src/Common/FileIO/Mxl.ts

@@ -13,7 +13,7 @@ export class MXLHelper {
      * @constructor
      */
     public static MXLtoIXmlElement(data: string): Promise<IXmlElement> {
-        let zip: JSZip.JSZip = new JSZip();
+        const zip: JSZip.JSZip = new JSZip();
         // asynchronously load zip file and process it - with Promises
         return zip.loadAsync(data).then(
             (_: any) => {
@@ -24,9 +24,9 @@ export class MXLHelper {
             }
         ).then(
             (content: string) => {
-                let parser: DOMParser = new DOMParser();
-                let doc: Document = parser.parseFromString(content, "text/xml");
-                let rootFile: string = doc.getElementsByTagName("rootfile")[0].getAttribute("full-path");
+                const parser: DOMParser = new DOMParser();
+                const doc: Document = parser.parseFromString(content, "text/xml");
+                const rootFile: string = doc.getElementsByTagName("rootfile")[0].getAttribute("full-path");
                 return zip.file(rootFile).async("string");
             },
             (err: any) => {
@@ -34,9 +34,9 @@ export class MXLHelper {
             }
         ).then(
             (content: string) => {
-                let parser: DOMParser = new DOMParser();
-                let xml: Document = parser.parseFromString(content, "text/xml");
-                let doc: IXmlElement = new IXmlElement(xml.documentElement);
+                const parser: DOMParser = new DOMParser();
+                const xml: Document = parser.parseFromString(content, "text/xml");
+                const doc: IXmlElement = new IXmlElement(xml.documentElement);
                 return Promise.resolve(doc);
             },
             (err: any) => {
@@ -53,7 +53,7 @@ export class MXLHelper {
     }
 
     public static MXLtoXMLstring(data: string): Promise<string> {
-        let zip:  JSZip.JSZip = new JSZip();
+        const zip:  JSZip.JSZip = new JSZip();
         // asynchronously load zip file and process it - with Promises
         return zip.loadAsync(data).then(
             (_: any) => {
@@ -64,9 +64,9 @@ export class MXLHelper {
             }
         ).then(
             (content: string) => {
-                let parser: DOMParser = new DOMParser();
-                let doc: Document = parser.parseFromString(content, "text/xml");
-                let rootFile: string = doc.getElementsByTagName("rootfile")[0].getAttribute("full-path");
+                const parser: DOMParser = new DOMParser();
+                const doc: Document = parser.parseFromString(content, "text/xml");
+                const rootFile: string = doc.getElementsByTagName("rootfile")[0].getAttribute("full-path");
                 return zip.file(rootFile).async("string");
             },
             (err: any) => {

+ 8 - 8
src/Common/FileIO/Xml.ts

@@ -56,8 +56,8 @@ export class IXmlElement {
      */
     public attributes(): IXmlAttribute[] {
         if (!this.attrs) {
-            let attributes: NamedNodeMap = this.elem.attributes;
-            let attrs: IXmlAttribute[] = [];
+            const attributes: NamedNodeMap = this.elem.attributes;
+            const attrs: IXmlAttribute[] = [];
             for (let i: number = 0; i < attributes.length; i += 1) {
                 attrs.push(attributes[i]);
             }
@@ -72,9 +72,9 @@ export class IXmlElement {
      * @returns {IXmlElement}
      */
     public element(elementName: string): IXmlElement {
-        let nodes: NodeList = this.elem.childNodes;
+        const nodes: NodeList = this.elem.childNodes;
         for (let i: number = 0, length: number = nodes.length; i < length; i += 1) {
-            let node: Node = nodes[i];
+            const node: Node = nodes[i];
             if (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === elementName) {
                 return new IXmlElement(node as Element);
             }
@@ -87,14 +87,14 @@ export class IXmlElement {
      * @returns {IXmlElement[]}
      */
     public elements(nodeName?: string): IXmlElement[] {
-        let nodes: NodeList = this.elem.childNodes;
-        let ret: IXmlElement[] = [];
-        let nameUnset: boolean = nodeName === undefined;
+        const nodes: NodeList = this.elem.childNodes;
+        const ret: IXmlElement[] = [];
+        const nameUnset: boolean = nodeName === undefined;
         if (!nameUnset) {
             nodeName = nodeName.toLowerCase();
         }
         for (let i: number = 0; i < nodes.length; i += 1) {
-            let node: Node = nodes[i];
+            const node: Node = nodes[i];
             if (node.nodeType === Node.ELEMENT_NODE &&
                 (nameUnset || node.nodeName.toLowerCase() === nodeName)
             ) {

+ 4 - 4
src/MusicalScore/Graphical/AccidentalCalculator.ts

@@ -34,7 +34,7 @@ export class AccidentalCalculator {
      */
     public doCalculationsAtEndOfMeasure(): void {
         this.currentInMeasureNoteAlterationsDict.clear();
-        for (let key of this.keySignatureNoteAlterationsDict.keys()) {
+        for (const key of this.keySignatureNoteAlterationsDict.keys()) {
             this.currentInMeasureNoteAlterationsDict.setValue(key, this.keySignatureNoteAlterationsDict.getValue(key));
         }
     }
@@ -43,7 +43,7 @@ export class AccidentalCalculator {
         if (pitch === undefined) {
             return;
         }
-        let pitchKey: number = <number>pitch.FundamentalNote + pitch.Octave * 12;
+        const pitchKey: number = <number>pitch.FundamentalNote + pitch.Octave * 12;
         /*let pitchKeyGivenInMeasureDict: boolean = this.currentInMeasureNoteAlterationsDict.containsKey(pitchKey);
         if (
             (pitchKeyGivenInMeasureDict && this.currentInMeasureNoteAlterationsDict.getValue(pitchKey) !== pitch.Accidental)
@@ -64,7 +64,7 @@ export class AccidentalCalculator {
             this.symbolFactory.addGraphicalAccidental(graphicalNote, pitch, grace, graceScalingFactor);
         }*/
 
-        let isInCurrentAlterationsToKeyList: boolean = this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey) >= 0;
+        const isInCurrentAlterationsToKeyList: boolean = this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey) >= 0;
         if (this.currentInMeasureNoteAlterationsDict.containsKey(pitchKey)) {
             if (isInCurrentAlterationsToKeyList) {
                 this.currentAlterationsComparedToKeyInstructionList.splice(this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey), 1);
@@ -96,7 +96,7 @@ export class AccidentalCalculator {
     }
 
     private reactOnKeyInstructionChange(): void {
-        let noteEnums: NoteEnum[] = KeyInstruction.getNoteEnumList(this.activeKeyInstruction);
+        const noteEnums: NoteEnum[] = KeyInstruction.getNoteEnumList(this.activeKeyInstruction);
         let keyAccidentalType: AccidentalEnum;
         if (this.activeKeyInstruction.Key > 0) {
             keyAccidentalType = AccidentalEnum.SHARP;

+ 75 - 33
src/MusicalScore/Graphical/BoundingBox.ts

@@ -5,6 +5,9 @@ import {RectangleF2D} from "../../Common/DataObjects/RectangleF2D";
 
 /**
  * A bounding box delimits an area on the 2D plane.
+ * @param dataObject Graphical object where the bounding box will be attached
+ * @param parent Parent bounding box of an object in a higher hierarchy position
+ * @param connectChildToParent Create a child to parent relationship too. Will be true by default
  */
 export class BoundingBox {
     protected isSymbol: boolean = false;
@@ -14,9 +17,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;
@@ -30,12 +33,20 @@ export class BoundingBox {
     protected childElements: BoundingBox[] = [];
     protected parent: BoundingBox;
     protected dataObject: Object;
-
+    /**
+     * Create a bounding box
+     * @param dataObject Graphical object where the bounding box will be attached
+     * @param parent Parent bounding box of an object in a higher hierarchy position
+     * @param connectChildToParent Create a child to parent relationship too. Will be true by default
+     */
     constructor(dataObject: Object = undefined, parent: BoundingBox = undefined) {
         this.parent = parent;
         this.dataObject = dataObject;
         this.xBordersHaveBeenSet = false;
         this.yBordersHaveBeenSet = false;
+        if (parent !== undefined) {
+            this.Parent = parent;
+        }
     }
 
     public get RelativePositionHasBeenSet(): boolean {
@@ -189,6 +200,12 @@ export class BoundingBox {
 
     public set Parent(value: BoundingBox) {
         this.parent = value;
+        if (this.parent.ChildElements.indexOf(this) > -1) {
+            console.error("BoundingBox of " + (this.dataObject.constructor as any).name +
+            " already in children list of " + (this.parent.dataObject.constructor as any).name + "'s BoundingBox");
+        } else {
+            this.parent.ChildElements.push(this);
+        }
     }
 
     public get DataObject(): Object {
@@ -205,19 +222,34 @@ 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 {
         this.absolutePosition.x = 0.0;
         this.absolutePosition.y = 0.0;
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let child: BoundingBox = this.ChildElements[idx];
+            const child: BoundingBox = this.ChildElements[idx];
             child.calculateAbsolutePositionsRecursive(this.absolutePosition.x, this.absolutePosition.y);
         }
     }
 
     /**
      * This method calculates the Absolute Positions recursively
+     * from the root element down to the leaf elements
      * @param x
      * @param y
      */
@@ -225,12 +257,22 @@ export class BoundingBox {
         this.absolutePosition.x = this.relativePosition.x + x;
         this.absolutePosition.y = this.relativePosition.y + y;
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let child: BoundingBox = this.ChildElements[idx];
+            const child: BoundingBox = this.ChildElements[idx];
             child.calculateAbsolutePositionsRecursive(this.absolutePosition.x, this.absolutePosition.y);
         }
     }
 
     /**
+     * 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) {
+        const child: BoundingBox = this.ChildElements[idx];
+        child.calculateAbsolutePositionsRecursive(this.absolutePosition.x, this.absolutePosition.y);
+      }
+    }
+
+    /**
      * This method calculates the BoundingBoxes
      */
     public calculateBoundingBox(): void {
@@ -238,7 +280,7 @@ export class BoundingBox {
             return;
         }
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let childElement: BoundingBox = this.ChildElements[idx];
+            const childElement: BoundingBox = this.ChildElements[idx];
             childElement.calculateBoundingBox();
         }
 
@@ -266,7 +308,7 @@ export class BoundingBox {
 
         // ChildElements will have their borders calculated, so calculate current borders
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let childElement: BoundingBox = this.ChildElements[idx];
+            const childElement: BoundingBox = this.ChildElements[idx];
             minLeft = Math.min(minLeft, childElement.relativePosition.x + childElement.borderLeft);
             maxRight = Math.max(maxRight, childElement.relativePosition.x + childElement.borderRight);
             minTop = Math.min(minTop, childElement.relativePosition.y + childElement.borderTop);
@@ -297,7 +339,7 @@ export class BoundingBox {
             return;
         }
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let childElement: BoundingBox = this.ChildElements[idx];
+            const childElement: BoundingBox = this.ChildElements[idx];
             childElement.calculateTopBottomBorders();
         }
         let minTop: number = Number.MAX_VALUE;
@@ -311,7 +353,7 @@ export class BoundingBox {
             maxMarginBottom = this.borderMarginBottom;
         }
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let childElement: BoundingBox = this.ChildElements[idx];
+            const childElement: BoundingBox = this.ChildElements[idx];
             minTop = Math.min(minTop, childElement.relativePosition.y + childElement.borderTop);
             maxBottom = Math.max(maxBottom, childElement.relativePosition.y + childElement.borderBottom);
             minMarginTop = Math.min(minMarginTop, childElement.relativePosition.y + childElement.borderMarginTop);
@@ -363,9 +405,9 @@ export class BoundingBox {
      * @returns {boolean}
      */
     public collisionDetection(psi: BoundingBox): boolean {
-        let overlapWidth: number = Math.min(this.AbsolutePosition.x + this.borderRight, psi.absolutePosition.x + psi.borderRight)
+        const overlapWidth: number = Math.min(this.AbsolutePosition.x + this.borderRight, psi.absolutePosition.x + psi.borderRight)
             - Math.max(this.AbsolutePosition.x + this.borderLeft, psi.absolutePosition.x + psi.borderLeft);
-        let overlapHeight: number = Math.min(this.AbsolutePosition.y + this.borderBottom, psi.absolutePosition.y + psi.borderBottom)
+        const overlapHeight: number = Math.min(this.AbsolutePosition.y + this.borderBottom, psi.absolutePosition.y + psi.borderBottom)
             - Math.max(this.AbsolutePosition.y + this.borderTop, psi.absolutePosition.y + psi.borderTop);
         if (overlapWidth > 0 && overlapHeight > 0) {
             return true;
@@ -379,14 +421,14 @@ export class BoundingBox {
      * @returns {boolean}
      */
     public liesInsideBorders(psi: BoundingBox): boolean {
-        let leftBorderInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= (psi.absolutePosition.x + psi.borderLeft)
+        const leftBorderInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= (psi.absolutePosition.x + psi.borderLeft)
             && (psi.absolutePosition.x + psi.borderLeft) <= (this.AbsolutePosition.x + this.borderRight);
-        let rightBorderInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= (psi.absolutePosition.x + psi.borderRight)
+        const rightBorderInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= (psi.absolutePosition.x + psi.borderRight)
             && (psi.absolutePosition.x + psi.borderRight) <= (this.AbsolutePosition.x + this.borderRight);
         if (leftBorderInside && rightBorderInside) {
-            let topBorderInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= (psi.absolutePosition.y + psi.borderTop)
+            const topBorderInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= (psi.absolutePosition.y + psi.borderTop)
                 && (psi.absolutePosition.y + psi.borderTop) <= (this.AbsolutePosition.y + this.borderBottom);
-            let bottomBorderInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= (psi.absolutePosition.y + psi.borderBottom)
+            const bottomBorderInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= (psi.absolutePosition.y + psi.borderBottom)
                 && (psi.absolutePosition.y + psi.borderBottom) <= (this.AbsolutePosition.y + this.borderBottom);
             if (topBorderInside && bottomBorderInside) {
                 return true;
@@ -396,9 +438,9 @@ export class BoundingBox {
     }
 
     public pointLiesInsideBorders(position: PointF2D): boolean {
-        let xInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= position.x && position.x <= (this.AbsolutePosition.x + this.borderRight);
+        const xInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= position.x && position.x <= (this.AbsolutePosition.x + this.borderRight);
         if (xInside) {
-            let yInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= position.y && position.y <= (this.AbsolutePosition.y + this.borderBottom);
+            const yInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= position.y && position.y <= (this.AbsolutePosition.y + this.borderBottom);
             if (yInside) {
                 return true;
             }
@@ -412,9 +454,9 @@ export class BoundingBox {
      * @returns {boolean}
      */
     public marginCollisionDetection(psi: BoundingBox): boolean {
-        let overlapWidth: number = Math.min(this.AbsolutePosition.x + this.borderMarginRight, psi.absolutePosition.x + psi.borderMarginRight)
+        const overlapWidth: number = Math.min(this.AbsolutePosition.x + this.borderMarginRight, psi.absolutePosition.x + psi.borderMarginRight)
             - Math.max(this.AbsolutePosition.x + this.borderMarginLeft, psi.absolutePosition.x + psi.borderMarginLeft);
-        let overlapHeight: number = Math.min(this.AbsolutePosition.y + this.borderMarginBottom, psi.absolutePosition.y + psi.borderMarginBottom)
+        const overlapHeight: number = Math.min(this.AbsolutePosition.y + this.borderMarginBottom, psi.absolutePosition.y + psi.borderMarginBottom)
             - Math.max(this.AbsolutePosition.y + this.borderMarginTop, psi.absolutePosition.y + psi.borderMarginTop);
         if (overlapWidth > 0 && overlapHeight > 0) {
             return true;
@@ -428,14 +470,14 @@ export class BoundingBox {
      * @returns {boolean}
      */
     public liesInsideMargins(psi: BoundingBox): boolean {
-        let leftMarginInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= (psi.absolutePosition.x + psi.borderMarginLeft)
+        const leftMarginInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= (psi.absolutePosition.x + psi.borderMarginLeft)
             && (psi.absolutePosition.x + psi.borderMarginLeft) <= (this.AbsolutePosition.x + this.borderMarginRight);
-        let rightMarginInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= (psi.absolutePosition.x + psi.borderMarginRight)
+        const rightMarginInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= (psi.absolutePosition.x + psi.borderMarginRight)
             && (psi.absolutePosition.x + psi.borderMarginRight) <= (this.AbsolutePosition.x + this.borderMarginRight);
         if (leftMarginInside && rightMarginInside) {
-            let topMarginInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= (psi.absolutePosition.y + psi.borderMarginTop)
+            const topMarginInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= (psi.absolutePosition.y + psi.borderMarginTop)
                 && (psi.absolutePosition.y + psi.borderMarginTop) <= (this.AbsolutePosition.y + this.borderMarginBottom);
-            let bottomMarginInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= (psi.absolutePosition.y + psi.borderMarginBottom)
+            const bottomMarginInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= (psi.absolutePosition.y + psi.borderMarginBottom)
                 && (psi.absolutePosition.y + psi.borderMarginBottom) <= (this.AbsolutePosition.y + this.borderMarginBottom);
             if (topMarginInside && bottomMarginInside) {
                 return true;
@@ -445,10 +487,10 @@ export class BoundingBox {
     }
 
     public pointLiesInsideMargins(position: PointF2D): boolean {
-        let xInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= position.x
+        const xInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= position.x
             && position.x <= (this.AbsolutePosition.x + this.borderMarginRight);
         if (xInside) {
-            let yInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= position.y
+            const yInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= position.y
                 && position.y <= (this.AbsolutePosition.y + this.borderMarginBottom);
             if (yInside) {
                 return true;
@@ -489,13 +531,13 @@ export class BoundingBox {
     }
 
     public getClickedObjectOfType<T>(clickPosition: PointF2D): T {
-        let obj: Object = this.dataObject;
+        const obj: Object = this.dataObject;
         if (this.pointLiesInsideBorders(clickPosition) && (<T>obj !== undefined)) {
             return (obj as T);
         }
         for (let idx: number = 0, len: number = this.childElements.length; idx < len; ++idx) {
-            let psi: BoundingBox = this.childElements[idx];
-            let innerObject: Object = psi.getClickedObjectOfType<T>(clickPosition);
+            const psi: BoundingBox = this.childElements[idx];
+            const innerObject: Object = psi.getClickedObjectOfType<T>(clickPosition);
             if (innerObject !== undefined) {
                 return (innerObject as T);
             }
@@ -516,8 +558,8 @@ export class BoundingBox {
             }
             // FIXME Andrea: add here "return []"?
         }
-        let result: T[] = [];
-        for (let child of this.childElements) {
+        const result: T[] = [];
+        for (const child of this.childElements) {
             result.concat(child.getObjectsInRegion<T>(region, liesInside));
         }
         return result;
@@ -582,7 +624,7 @@ export class BoundingBox {
 
         // perform check for all children iteratively and return border from children symbols
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let childElement: BoundingBox = this.ChildElements[idx];
+            const childElement: BoundingBox = this.ChildElements[idx];
             childElement.calculateMarginPositionAlongDirection(toBePlaced, direction);
         }
     }
@@ -633,7 +675,7 @@ export class BoundingBox {
 
         // perform check for all children iteratively and return border from children symbols
         for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
-            let childElement: BoundingBox = this.ChildElements[idx];
+            const childElement: BoundingBox = this.ChildElements[idx];
             childElement.calculatePositionAlongDirection(toBePlaced, direction);
         }
     }

+ 39 - 1
src/MusicalScore/Graphical/DrawingEnums.ts

@@ -1,3 +1,5 @@
+import * as Collections from "typescript-collections";
+
 /**
  * The supported styles to draw a rectangle on the music sheet
  */
@@ -37,13 +39,49 @@ export enum OutlineAndFillStyleEnum {
     Comment10
 }
 
+// tslint:disable-next-line:max-line-length A linebreak would be more confusing here
+export const OUTLINE_AND_FILL_STYLE_DICT: Collections.Dictionary<OutlineAndFillStyleEnum, string> = new Collections.Dictionary<OutlineAndFillStyleEnum, string>();
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.BaseWritingColor, "Thistle");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.FollowingCursor, "Aqua");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.AlternativeFollowingCursor, "Azure");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.PlaybackCursor, "Bisque");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Highlighted, "CadetBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.ErrorUnderlay, "DarkBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Selected, "DarkGoldenRod");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.SelectionSymbol, "BlanchedAlmond");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.DebugColor1, "Chartreuse");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.DebugColor2, "DarkGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.DebugColor3, "DarkOrange");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.SplitScreenDivision, "FireBrick");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.GreyTransparentOverlay, "DarkSalmon");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea1, "DarkSeaGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea2, "DarkOrchid");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea3, "Aquamarine");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea4, "DarkKhaki");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea5, "ForestGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea6, "AliceBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea7, "DeepPink");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea8, "Coral");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea9, "DarkOliveGreen");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.MarkedArea10, "Chocolate");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment1, "DodgerBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment2, "Blue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment3, "Beige");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment4, "Crimson");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment5, "Fuchsia");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment6, "Brown");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment7, "BlanchedAlmond");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment8, "CornflowerBlue");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment9, "Cornsilk");
+OUTLINE_AND_FILL_STYLE_DICT.setValue(OutlineAndFillStyleEnum.Comment10, "DarkGrey");
+
 export enum StyleSets {
     MarkedArea,
     Comment
 }
 
 /**
- * The layers which one can draw on (not suppoerted)
+ * The layers which one can draw on (not supported)
  */
 export enum GraphicalLayers {
     Background,

+ 4 - 1
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;
     }
@@ -1162,7 +1165,7 @@ export class EngravingRules {
         this.factorOne = new Array(this.bezierCurveStepSize);
         this.factorTwo = new Array(this.bezierCurveStepSize);
         for (let i: number = 0; i < this.bezierCurveStepSize; i++) {
-            let t: number = i / this.bezierCurveStepSize;
+            const t: number = i / this.bezierCurveStepSize;
             this.tPower3[i] = Math.pow(t, 3);
             this.oneMinusTPower3[i] = Math.pow((1 - t), 3);
             this.factorOne[i] = 3 * Math.pow((1 - t), 2) * t;

+ 1 - 2
src/MusicalScore/Graphical/GraphicalChordSymbolContainer.ts

@@ -22,9 +22,8 @@ export class GraphicalChordSymbolContainer extends GraphicalObject {
         return this.graphicalLabel;
     }
     private calculateLabel(textHeight: number, transposeHalftones: number): void {
-        let text: string = ChordSymbolContainer.calculateChordText(this.chordSymbolContainer, transposeHalftones);
+        const text: string = ChordSymbolContainer.calculateChordText(this.chordSymbolContainer, transposeHalftones);
         this.graphicalLabel = new GraphicalLabel(new Label(text), textHeight, TextAlignment.CenterBottom, this.boundingBox);
         this.graphicalLabel.PositionAndShape.RelativePosition = new PointF2D(0.0, 0.0);
-        this.boundingBox.ChildElements.push(this.graphicalLabel.PositionAndShape);
     }
 }

+ 5 - 5
src/MusicalScore/Graphical/GraphicalLabel.ts

@@ -33,13 +33,13 @@ export class GraphicalLabel extends Clickable {
         if (this.Label.text.trim() === "") {
             return;
         }
-        let labelMarginBorderFactor: number = EngravingRules.Rules.LabelMarginBorderFactor;
+        const labelMarginBorderFactor: number = EngravingRules.Rules.LabelMarginBorderFactor;
 
-        let widthToHeightRatio: number =
+        const widthToHeightRatio: number =
             MusicSheetCalculator.TextMeasurer.computeTextWidthToHeightRatio(this.Label.text, this.Label.font, this.Label.fontStyle);
-        let height: number = this.Label.fontHeight;
-        let width: number = height * widthToHeightRatio;
-        let psi: BoundingBox = this.PositionAndShape;
+        const height: number = this.Label.fontHeight;
+        const width: number = height * widthToHeightRatio;
+        const psi: BoundingBox = this.PositionAndShape;
 
         switch (this.Label.textAlignment) {
             case TextAlignment.CenterBottom:

+ 97 - 97
src/MusicalScore/Graphical/GraphicalMusicSheet.ts

@@ -167,8 +167,8 @@ export class GraphicalMusicSheet {
      */
     public static transformRelativeToAbsolutePosition(graphicalMusicSheet: GraphicalMusicSheet): void {
         for (let i: number = 0; i < graphicalMusicSheet.MusicPages.length; i++) {
-            let pageAbsolute: PointF2D = graphicalMusicSheet.MusicPages[i].setMusicPageAbsolutePosition(i, graphicalMusicSheet.ParentMusicSheet.rules);
-            let page: GraphicalMusicPage = graphicalMusicSheet.MusicPages[i];
+            const pageAbsolute: PointF2D = graphicalMusicSheet.MusicPages[i].setMusicPageAbsolutePosition(i, graphicalMusicSheet.ParentMusicSheet.rules);
+            const page: GraphicalMusicPage = graphicalMusicSheet.MusicPages[i];
             page.PositionAndShape.calculateAbsolutePositionsRecursive(pageAbsolute.x, pageAbsolute.y);
         }
     }
@@ -189,9 +189,9 @@ export class GraphicalMusicSheet {
 
     public EnforceRedrawOfMusicSystems(): void {
         for (let idx: number = 0, len: number = this.musicPages.length; idx < len; ++idx) {
-            let graphicalMusicPage: GraphicalMusicPage = this.musicPages[idx];
+            const graphicalMusicPage: GraphicalMusicPage = this.musicPages[idx];
             for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) {
-                let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
+                const musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
                 musicSystem.needsToBeRedrawn = true;
             }
         }
@@ -199,7 +199,7 @@ export class GraphicalMusicSheet {
 
     public getClickedObject<T>(positionOnMusicSheet: PointF2D): T {
         for (let idx: number = 0, len: number = this.MusicPages.length; idx < len; ++idx) {
-            let graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
+            const graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
             return graphicalMusicPage.PositionAndShape.getClickedObjectOfType<T>(positionOnMusicSheet);
         }
         return undefined;
@@ -215,9 +215,9 @@ export class GraphicalMusicSheet {
      */
     public findGraphicalStaffEntryFromMeasureList(staffIndex: number, measureIndex: number, sourceStaffEntry: SourceStaffEntry): GraphicalStaffEntry {
         for (let i: number = measureIndex; i < this.measureList.length; i++) {
-            let graphicalMeasure: StaffMeasure = this.measureList[i][staffIndex];
+            const graphicalMeasure: StaffMeasure = this.measureList[i][staffIndex];
             for (let idx: number = 0, len: number = graphicalMeasure.staffEntries.length; idx < len; ++idx) {
-                let graphicalStaffEntry: GraphicalStaffEntry = graphicalMeasure.staffEntries[idx];
+                const graphicalStaffEntry: GraphicalStaffEntry = graphicalMeasure.staffEntries[idx];
                 if (graphicalStaffEntry.sourceStaffEntry === sourceStaffEntry) {
                     return graphicalStaffEntry;
                 }
@@ -234,12 +234,12 @@ export class GraphicalMusicSheet {
      * @returns {any}
      */
     public findNextGraphicalStaffEntry(staffIndex: number, measureIndex: number, graphicalStaffEntry: GraphicalStaffEntry): GraphicalStaffEntry {
-        let graphicalMeasure: StaffMeasure = graphicalStaffEntry.parentMeasure;
-        let graphicalStaffEntryIndex: number = graphicalMeasure.staffEntries.indexOf(graphicalStaffEntry);
+        const graphicalMeasure: StaffMeasure = graphicalStaffEntry.parentMeasure;
+        const graphicalStaffEntryIndex: number = graphicalMeasure.staffEntries.indexOf(graphicalStaffEntry);
         if (graphicalStaffEntryIndex < graphicalMeasure.staffEntries.length - 1) {
             return graphicalMeasure.staffEntries[graphicalStaffEntryIndex + 1];
         } else if (measureIndex < this.measureList.length - 1) {
-            let nextMeasure: StaffMeasure = this.measureList[measureIndex + 1][staffIndex];
+            const nextMeasure: StaffMeasure = this.measureList[measureIndex + 1][staffIndex];
             if (nextMeasure.staffEntries.length > 0) {
                 return nextMeasure.staffEntries[0];
             }
@@ -248,8 +248,8 @@ export class GraphicalMusicSheet {
     }
 
     public getFirstVisibleMeasuresListFromIndeces(start: number, end: number): StaffMeasure[] {
-        let graphicalMeasures: StaffMeasure[] = [];
-        let numberOfStaves: number = this.measureList[0].length;
+        const graphicalMeasures: StaffMeasure[] = [];
+        const numberOfStaves: number = this.measureList[0].length;
         for (let i: number = start; i <= end; i++) {
             for (let j: number = 0; j < numberOfStaves; j++) {
                 if (this.measureList[i][j].isVisible()) {
@@ -262,7 +262,7 @@ export class GraphicalMusicSheet {
     }
 
     public orderMeasuresByStaffLine(measures: StaffMeasure[]): StaffMeasure[][] {
-        let orderedMeasures: StaffMeasure[][] = [];
+        const orderedMeasures: StaffMeasure[][] = [];
         let mList: StaffMeasure[] = [];
         orderedMeasures.push(mList);
         for (let i: number = 0; i < measures.length; i++) {
@@ -289,14 +289,14 @@ export class GraphicalMusicSheet {
      * @returns {ClefInstruction[]}
      */
     public initializeActiveClefs(): ClefInstruction[] {
-        let activeClefs: ClefInstruction[] = [];
-        let firstSourceMeasure: SourceMeasure = this.musicSheet.getFirstSourceMeasure();
+        const activeClefs: ClefInstruction[] = [];
+        const firstSourceMeasure: SourceMeasure = this.musicSheet.getFirstSourceMeasure();
         if (firstSourceMeasure !== undefined) {
             for (let i: number = 0; i < firstSourceMeasure.CompleteNumberOfStaves; i++) {
                 let clef: ClefInstruction = new ClefInstruction();
                 if (firstSourceMeasure.FirstInstructionsStaffEntries[i] !== undefined) {
                     for (let idx: number = 0, len: number = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions.length; idx < len; ++idx) {
-                        let abstractNotationInstruction: AbstractNotationInstruction = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions[idx];
+                        const abstractNotationInstruction: AbstractNotationInstruction = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions[idx];
                         if (abstractNotationInstruction instanceof ClefInstruction) {
                             clef = <ClefInstruction>abstractNotationInstruction;
 
@@ -310,11 +310,11 @@ export class GraphicalMusicSheet {
     }
 
     public GetMainKey(): KeyInstruction {
-        let firstSourceMeasure: SourceMeasure = this.musicSheet.getFirstSourceMeasure();
+        const firstSourceMeasure: SourceMeasure = this.musicSheet.getFirstSourceMeasure();
         if (firstSourceMeasure !== undefined) {
             for (let i: number = 0; i < firstSourceMeasure.CompleteNumberOfStaves; i++) {
                 for (let idx: number = 0, len: number = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions.length; idx < len; ++idx) {
-                    let abstractNotationInstruction: AbstractNotationInstruction = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions[idx];
+                    const abstractNotationInstruction: AbstractNotationInstruction = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions[idx];
                     if (abstractNotationInstruction instanceof KeyInstruction) {
                         return <KeyInstruction>abstractNotationInstruction;
                     }
@@ -332,14 +332,14 @@ export class GraphicalMusicSheet {
     public getOrCreateVerticalContainer(timestamp: Fraction): VerticalGraphicalStaffEntryContainer {
         if (this.verticalGraphicalStaffEntryContainers.length === 0 ||
             (CollectionUtil.getLastElement(this.verticalGraphicalStaffEntryContainers).AbsoluteTimestamp).lt(timestamp)) {
-            let verticalGraphicalStaffEntryContainer: VerticalGraphicalStaffEntryContainer =
+            const verticalGraphicalStaffEntryContainer: VerticalGraphicalStaffEntryContainer =
                 new VerticalGraphicalStaffEntryContainer(this.numberOfStaves, timestamp);
             this.verticalGraphicalStaffEntryContainers.push(verticalGraphicalStaffEntryContainer);
             return verticalGraphicalStaffEntryContainer;
         }
         for (let i: number = this.verticalGraphicalStaffEntryContainers.length - 1; i >= 0; i--) {
             if (this.verticalGraphicalStaffEntryContainers[i].AbsoluteTimestamp.lt(timestamp)) {
-                let verticalGraphicalStaffEntryContainer: VerticalGraphicalStaffEntryContainer =
+                const verticalGraphicalStaffEntryContainer: VerticalGraphicalStaffEntryContainer =
                     new VerticalGraphicalStaffEntryContainer(this.numberOfStaves, timestamp);
                 this.verticalGraphicalStaffEntryContainers.splice(i + 1, 0, verticalGraphicalStaffEntryContainer);
                 return verticalGraphicalStaffEntryContainer;
@@ -361,10 +361,10 @@ export class GraphicalMusicSheet {
      * @constructor
      */
     public GetVerticalContainerFromTimestamp(timestamp: Fraction, startIndex: number = 0): VerticalGraphicalStaffEntryContainer {
-        let index: number = CollectionUtil.binarySearch(this.verticalGraphicalStaffEntryContainers,
-                                                        new VerticalGraphicalStaffEntryContainer(0, timestamp),
-                                                        VerticalGraphicalStaffEntryContainer.compareByTimestamp,
-                                                        startIndex);
+        const index: number = CollectionUtil.binarySearch(this.verticalGraphicalStaffEntryContainers,
+                                                          new VerticalGraphicalStaffEntryContainer(0, timestamp),
+                                                          VerticalGraphicalStaffEntryContainer.compareByTimestamp,
+                                                          startIndex);
         if (index >= 0) {
             return this.verticalGraphicalStaffEntryContainers[index];
         }
@@ -378,7 +378,7 @@ export class GraphicalMusicSheet {
      * @constructor
      */
     public GetInterpolatedIndexInVerticalContainers(musicTimestamp: Fraction): number {
-        let containers: VerticalGraphicalStaffEntryContainer[] = this.verticalGraphicalStaffEntryContainers;
+        const containers: VerticalGraphicalStaffEntryContainer[] = this.verticalGraphicalStaffEntryContainers;
         let leftIndex: number = 0;
         let rightIndex: number = containers.length - 1;
         let foundIndex: number;
@@ -386,7 +386,7 @@ export class GraphicalMusicSheet {
         let rightTS: Fraction = undefined;
         if (musicTimestamp.lte(containers[containers.length - 1].AbsoluteTimestamp)) {
             while (rightIndex - leftIndex > 1) {
-                let middleIndex: number = Math.floor((rightIndex + leftIndex) / 2);
+                const middleIndex: number = Math.floor((rightIndex + leftIndex) / 2);
                 if (containers[leftIndex].AbsoluteTimestamp.Equals(musicTimestamp)) {
                     rightIndex = leftIndex;
                     break;
@@ -413,8 +413,8 @@ export class GraphicalMusicSheet {
             rightTS = Fraction.plus(this.getLongestStaffEntryDuration(containers.length - 1), leftTS);
             rightIndex = containers.length;
         }
-        let diff: number = rightTS.RealValue - leftTS.RealValue;
-        let diffTS: number = rightTS.RealValue - musicTimestamp.RealValue;
+        const diff: number = rightTS.RealValue - leftTS.RealValue;
+        const diffTS: number = rightTS.RealValue - musicTimestamp.RealValue;
 
         // estimate the interpolated index
         foundIndex = rightIndex - (diffTS / diff);
@@ -428,18 +428,18 @@ export class GraphicalMusicSheet {
      * @returns {number[]}
      */
     public getVisibleStavesIndecesFromSourceMeasure(visibleMeasures: StaffMeasure[]): number[] {
-        let visibleInstruments: Instrument[] = [];
-        let visibleStavesIndeces: number[] = [];
+        const visibleInstruments: Instrument[] = [];
+        const visibleStavesIndeces: number[] = [];
         for (let idx: number = 0, len: number = visibleMeasures.length; idx < len; ++idx) {
-            let graphicalMeasure: StaffMeasure = visibleMeasures[idx];
-            let instrument: Instrument = graphicalMeasure.ParentStaff.ParentInstrument;
+            const graphicalMeasure: StaffMeasure = visibleMeasures[idx];
+            const instrument: Instrument = graphicalMeasure.ParentStaff.ParentInstrument;
             if (visibleInstruments.indexOf(instrument) === -1) {
                 visibleInstruments.push(instrument);
             }
         }
         for (let idx: number = 0, len: number = visibleInstruments.length; idx < len; ++idx) {
-            let instrument: Instrument = visibleInstruments[idx];
-            let index: number = this.musicSheet.getGlobalStaffIndexOfFirstStaff(instrument);
+            const instrument: Instrument = visibleInstruments[idx];
+            const index: number = this.musicSheet.getGlobalStaffIndexOfFirstStaff(instrument);
             for (let j: number = 0; j < instrument.Staves.length; j++) {
                 visibleStavesIndeces.push(index + j);
             }
@@ -467,7 +467,7 @@ export class GraphicalMusicSheet {
         inListIndex = 0;
         for (; measureIndex < this.measureList.length; measureIndex++) {
             for (let idx: number = 0, len: number = this.measureList[measureIndex].length; idx < len; ++idx) {
-                let measure: StaffMeasure = this.measureList[measureIndex][idx];
+                const measure: StaffMeasure = this.measureList[measureIndex][idx];
                 if (measure === graphicalMeasure) {
                     return true;
                 }
@@ -477,11 +477,11 @@ export class GraphicalMusicSheet {
     }
 
     public GetNearesNote(clickPosition: PointF2D, maxClickDist: PointF2D): GraphicalNote {
-        let initialSearchArea: number = 10;
-        let foundNotes: GraphicalNote[] = [];
+        const initialSearchArea: number = 10;
+        const foundNotes: GraphicalNote[] = [];
 
         // Prepare search area
-        let region: BoundingBox = new BoundingBox();
+        const region: BoundingBox = new BoundingBox();
         region.BorderLeft = clickPosition.x - initialSearchArea;
         region.BorderTop = clickPosition.y - initialSearchArea;
         region.BorderRight = clickPosition.x + initialSearchArea;
@@ -490,14 +490,14 @@ export class GraphicalMusicSheet {
 
         // Search for StaffEntries in region
         for (let idx: number = 0, len: number = this.MusicPages.length; idx < len; ++idx) {
-            let graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
-            let entries: GraphicalNote[] = graphicalMusicPage.PositionAndShape.getObjectsInRegion<GraphicalNote>(region);
+            const graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
+            const entries: GraphicalNote[] = graphicalMusicPage.PositionAndShape.getObjectsInRegion<GraphicalNote>(region);
             //let entriesArr: GraphicalNote[] = __as__<GraphicalNote[]>(entries, GraphicalNote[]) ? ? entries;
             if (entries === undefined) {
                 continue;
             } else {
                 for (let idx2: number = 0, len2: number = entries.length; idx2 < len2; ++idx2) {
-                    let note: GraphicalNote = entries[idx2];
+                    const note: GraphicalNote = entries[idx2];
                     if (Math.abs(note.PositionAndShape.AbsolutePosition.x - clickPosition.x) < maxClickDist.x
                         && Math.abs(note.PositionAndShape.AbsolutePosition.y - clickPosition.y) < maxClickDist.y) {
                         foundNotes.push(note);
@@ -509,15 +509,15 @@ export class GraphicalMusicSheet {
         // Get closest entry
         let closest: GraphicalNote = undefined;
         for (let idx: number = 0, len: number = foundNotes.length; idx < len; ++idx) {
-            let note: GraphicalNote = foundNotes[idx];
+            const note: GraphicalNote = foundNotes[idx];
             if (closest === undefined) {
                 closest = note;
             } else {
                 if (note.parentStaffEntry.relInMeasureTimestamp === undefined) {
                     continue;
                 }
-                let deltaNew: number = this.CalculateDistance(note.PositionAndShape.AbsolutePosition, clickPosition);
-                let deltaOld: number = this.CalculateDistance(closest.PositionAndShape.AbsolutePosition, clickPosition);
+                const deltaNew: number = this.CalculateDistance(note.PositionAndShape.AbsolutePosition, clickPosition);
+                const deltaOld: number = this.CalculateDistance(closest.PositionAndShape.AbsolutePosition, clickPosition);
                 if (deltaNew < deltaOld) {
                     closest = note;
                 }
@@ -532,23 +532,23 @@ export class GraphicalMusicSheet {
     }
 
     public GetClickableLabel(clickPosition: PointF2D): GraphicalLabel {
-        let initialSearchAreaX: number = 4;
-        let initialSearchAreaY: number = 4;
+        const initialSearchAreaX: number = 4;
+        const initialSearchAreaY: number = 4;
         // Prepare search area
-        let region: BoundingBox = new BoundingBox();
+        const region: BoundingBox = new BoundingBox();
         region.BorderLeft = clickPosition.x - initialSearchAreaX;
         region.BorderTop = clickPosition.y - initialSearchAreaY;
         region.BorderRight = clickPosition.x + initialSearchAreaX;
         region.BorderBottom = clickPosition.y + initialSearchAreaY;
         region.AbsolutePosition = new PointF2D(0, 0);
         for (let idx: number = 0, len: number = this.MusicPages.length; idx < len; ++idx) {
-            let graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
-            let entries: GraphicalLabel[] = graphicalMusicPage.PositionAndShape.getObjectsInRegion<GraphicalLabel>(region);
+            const graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
+            const entries: GraphicalLabel[] = graphicalMusicPage.PositionAndShape.getObjectsInRegion<GraphicalLabel>(region);
             if (entries.length !== 1) {
                 continue;
             } else {
                 for (let idx2: number = 0, len2: number = entries.length; idx2 < len2; ++idx2) {
-                    let clickedLabel: GraphicalLabel = entries[idx2];
+                    const clickedLabel: GraphicalLabel = entries[idx2];
                     return clickedLabel;
                 }
             }
@@ -557,10 +557,10 @@ export class GraphicalMusicSheet {
     }
 
     public GetNearestStaffEntry(clickPosition: PointF2D): GraphicalStaffEntry {
-        let initialSearchArea: number = 10;
-        let foundEntries: GraphicalStaffEntry[] = [];
+        const initialSearchArea: number = 10;
+        const foundEntries: GraphicalStaffEntry[] = [];
         // Prepare search area
-        let region: BoundingBox = new BoundingBox(undefined);
+        const region: BoundingBox = new BoundingBox(undefined);
         region.BorderLeft = clickPosition.x - initialSearchArea;
         region.BorderTop = clickPosition.y - initialSearchArea;
         region.BorderRight = clickPosition.x + initialSearchArea;
@@ -568,13 +568,13 @@ export class GraphicalMusicSheet {
         region.AbsolutePosition = new PointF2D(0, 0);
         // Search for StaffEntries in region
         for (let idx: number = 0, len: number = this.MusicPages.length; idx < len; ++idx) {
-            let graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
-            let entries: GraphicalStaffEntry[] = graphicalMusicPage.PositionAndShape.getObjectsInRegion<GraphicalStaffEntry>(region, false);
+            const graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
+            const entries: GraphicalStaffEntry[] = graphicalMusicPage.PositionAndShape.getObjectsInRegion<GraphicalStaffEntry>(region, false);
             if (entries === undefined || entries.length === 0) {
                 continue;
             } else {
                 for (let idx2: number = 0, len2: number = entries.length; idx2 < len2; ++idx2) {
-                    let gse: GraphicalStaffEntry = entries[idx2];
+                    const gse: GraphicalStaffEntry = entries[idx2];
                     foundEntries.push(gse);
                 }
             }
@@ -582,15 +582,15 @@ export class GraphicalMusicSheet {
         // Get closest entry
         let closest: GraphicalStaffEntry = undefined;
         for (let idx: number = 0, len: number = foundEntries.length; idx < len; ++idx) {
-            let gse: GraphicalStaffEntry = foundEntries[idx];
+            const gse: GraphicalStaffEntry = foundEntries[idx];
             if (closest === undefined) {
                 closest = gse;
             } else {
                 if (gse.relInMeasureTimestamp === undefined) {
                     continue;
                 }
-                let deltaNew: number = this.CalculateDistance(gse.PositionAndShape.AbsolutePosition, clickPosition);
-                let deltaOld: number = this.CalculateDistance(closest.PositionAndShape.AbsolutePosition, clickPosition);
+                const deltaNew: number = this.CalculateDistance(gse.PositionAndShape.AbsolutePosition, clickPosition);
+                const deltaOld: number = this.CalculateDistance(closest.PositionAndShape.AbsolutePosition, clickPosition);
                 if (deltaNew < deltaOld) {
                     closest = gse;
                 }
@@ -605,7 +605,7 @@ export class GraphicalMusicSheet {
     }
 
     public GetPossibleCommentAnchor(clickPosition: PointF2D): SourceStaffEntry {
-        let entry: GraphicalStaffEntry = this.GetNearestStaffEntry(clickPosition);
+        const entry: GraphicalStaffEntry = this.GetNearestStaffEntry(clickPosition);
         if (entry === undefined) {
             return undefined;
         }
@@ -614,8 +614,8 @@ export class GraphicalMusicSheet {
 
     public getClickedObjectOfType<T>(positionOnMusicSheet: PointF2D): T {
         for (let idx: number = 0, len: number = this.musicPages.length; idx < len; ++idx) {
-            let page: GraphicalMusicPage = this.musicPages[idx];
-            let o: Object = page.PositionAndShape.getClickedObjectOfType<T>(positionOnMusicSheet);
+            const page: GraphicalMusicPage = this.musicPages[idx];
+            const o: Object = page.PositionAndShape.getClickedObjectOfType<T>(positionOnMusicSheet);
             if (o !== undefined) {
                 return (o as T);
             }
@@ -624,7 +624,7 @@ export class GraphicalMusicSheet {
     }
 
     public tryGetTimestampFromPosition(positionOnMusicSheet: PointF2D): Fraction {
-        let entry: GraphicalStaffEntry = this.getClickedObjectOfType<GraphicalStaffEntry>(positionOnMusicSheet);
+        const entry: GraphicalStaffEntry = this.getClickedObjectOfType<GraphicalStaffEntry>(positionOnMusicSheet);
         if (entry === undefined) {
             return undefined;
         }
@@ -643,7 +643,7 @@ export class GraphicalMusicSheet {
 
     public tryGetTimeStampFromPosition(positionOnMusicSheet: PointF2D): Fraction {
         try {
-            let entry: GraphicalStaffEntry = this.GetNearestStaffEntry(positionOnMusicSheet);
+            const entry: GraphicalStaffEntry = this.GetNearestStaffEntry(positionOnMusicSheet);
             if (entry === undefined) {
                 return undefined;
             }
@@ -664,11 +664,11 @@ export class GraphicalMusicSheet {
      * @returns {GraphicalStaffEntry}
      */
     public getStaffEntry(index: number): GraphicalStaffEntry {
-        let container: VerticalGraphicalStaffEntryContainer = this.VerticalGraphicalStaffEntryContainers[index];
+        const container: VerticalGraphicalStaffEntryContainer = this.VerticalGraphicalStaffEntryContainers[index];
         let staffEntry: GraphicalStaffEntry = undefined;
         try {
             for (let idx: number = 0, len: number = container.StaffEntries.length; idx < len; ++idx) {
-                let entry: GraphicalStaffEntry = container.StaffEntries[idx];
+                const entry: GraphicalStaffEntry = container.StaffEntries[idx];
                 if (entry === undefined || !entry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
                     continue;
                 }
@@ -695,9 +695,9 @@ export class GraphicalMusicSheet {
      */
     public GetPreviousVisibleContainerIndex(index: number): number {
         for (let i: number = index - 1; i >= 0; i--) {
-            let entries: GraphicalStaffEntry[] = this.verticalGraphicalStaffEntryContainers[i].StaffEntries;
+            const entries: GraphicalStaffEntry[] = this.verticalGraphicalStaffEntryContainers[i].StaffEntries;
             for (let idx: number = 0, len: number = entries.length; idx < len; ++idx) {
-                let entry: GraphicalStaffEntry = entries[idx];
+                const entry: GraphicalStaffEntry = entries[idx];
                 if (entry !== undefined && entry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
                     return i;
                 }
@@ -714,9 +714,9 @@ export class GraphicalMusicSheet {
      */
     public GetNextVisibleContainerIndex(index: number): number {
         for (let i: number = index + 1; i < this.verticalGraphicalStaffEntryContainers.length; ++i) {
-            let entries: GraphicalStaffEntry[] = this.verticalGraphicalStaffEntryContainers[i].StaffEntries;
+            const entries: GraphicalStaffEntry[] = this.verticalGraphicalStaffEntryContainers[i].StaffEntries;
             for (let idx: number = 0, len: number = entries.length; idx < len; ++idx) {
-                let entry: GraphicalStaffEntry = entries[idx];
+                const entry: GraphicalStaffEntry = entries[idx];
                 if (entry !== undefined && entry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
                     return i;
                 }
@@ -746,7 +746,7 @@ export class GraphicalMusicSheet {
 
     public findClosestRightStaffEntry(fractionalIndex: number, returnOnlyVisibleEntries: boolean): GraphicalStaffEntry {
         let foundEntry: GraphicalStaffEntry = undefined;
-        let rightIndex: number = <number>Math.max(0, Math.ceil(fractionalIndex));
+        const rightIndex: number = <number>Math.max(0, Math.ceil(fractionalIndex));
         for (let i: number = rightIndex; i < this.VerticalGraphicalStaffEntryContainers.length; i++) {
             foundEntry = this.getStaffEntry(i);
             if (foundEntry !== undefined) {
@@ -763,23 +763,23 @@ export class GraphicalMusicSheet {
     }
 
     public calculateCursorLineAtTimestamp(musicTimestamp: Fraction, styleEnum: OutlineAndFillStyleEnum): GraphicalLine {
-        let result: [number, MusicSystem] = this.calculateXPositionFromTimestamp(musicTimestamp);
-        let xPos: number = result[0];
-        let correspondingMusicSystem: MusicSystem = result[1];
+        const result: [number, MusicSystem] = this.calculateXPositionFromTimestamp(musicTimestamp);
+        const xPos: number = result[0];
+        const correspondingMusicSystem: MusicSystem = result[1];
         if (correspondingMusicSystem === undefined || correspondingMusicSystem.StaffLines.length === 0) {
             return undefined;
         }
-        let yCoordinate: number = correspondingMusicSystem.PositionAndShape.AbsolutePosition.y;
-        let height: number = CollectionUtil.last(correspondingMusicSystem.StaffLines).PositionAndShape.RelativePosition.y + 4;
+        const yCoordinate: number = correspondingMusicSystem.PositionAndShape.AbsolutePosition.y;
+        const height: number = CollectionUtil.last(correspondingMusicSystem.StaffLines).PositionAndShape.RelativePosition.y + 4;
         return new GraphicalLine(new PointF2D(xPos, yCoordinate), new PointF2D(xPos, yCoordinate + height), 3, styleEnum);
     }
 
     public calculateXPositionFromTimestamp(timeStamp: Fraction): [number, MusicSystem] {
         let currentMusicSystem: MusicSystem = undefined;
-        let fractionalIndex: number = this.GetInterpolatedIndexInVerticalContainers(timeStamp);
-        let previousStaffEntry: GraphicalStaffEntry = this.findClosestLeftStaffEntry(fractionalIndex, true);
-        let nextStaffEntry: GraphicalStaffEntry = this.findClosestRightStaffEntry(fractionalIndex, true);
-        let currentTimeStamp: number = timeStamp.RealValue;
+        const fractionalIndex: number = this.GetInterpolatedIndexInVerticalContainers(timeStamp);
+        const previousStaffEntry: GraphicalStaffEntry = this.findClosestLeftStaffEntry(fractionalIndex, true);
+        const nextStaffEntry: GraphicalStaffEntry = this.findClosestRightStaffEntry(fractionalIndex, true);
+        const currentTimeStamp: number = timeStamp.RealValue;
         if (previousStaffEntry === undefined && nextStaffEntry === undefined) {
             return [0, undefined];
         }
@@ -806,7 +806,7 @@ export class GraphicalMusicSheet {
             } else if (nextStaffEntry === undefined) {
                 previousStaffEntryPositionX = previousStaffEntry.PositionAndShape.AbsolutePosition.x;
                 nextStaffEntryPositionX = currentMusicSystem.GetRightBorderAbsoluteXPosition();
-                let sm: SourceMeasure = previousStaffEntry.parentMeasure.parentSourceMeasure;
+                const sm: SourceMeasure = previousStaffEntry.parentMeasure.parentSourceMeasure;
                 fraction = (currentTimeStamp - previousStaffEntry.getAbsoluteTimestamp().RealValue) / (
                     Fraction.plus(sm.AbsoluteTimestamp, sm.Duration).RealValue - previousStaffEntry.getAbsoluteTimestamp().RealValue);
             } else {
@@ -820,24 +820,24 @@ export class GraphicalMusicSheet {
                 }
             }
             fraction = Math.min(1, Math.max(0, fraction));
-            let interpolatedXPosition: number = previousStaffEntryPositionX + fraction * (nextStaffEntryPositionX - previousStaffEntryPositionX);
+            const interpolatedXPosition: number = previousStaffEntryPositionX + fraction * (nextStaffEntryPositionX - previousStaffEntryPositionX);
             return [interpolatedXPosition, currentMusicSystem];
         } else {
-            let nextSystemLeftBorderTimeStamp: number = nextStaffEntry.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.RealValue;
+            const nextSystemLeftBorderTimeStamp: number = nextStaffEntry.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.RealValue;
             let fraction: number;
             let interpolatedXPosition: number;
             if (currentTimeStamp < nextSystemLeftBorderTimeStamp) {
                 currentMusicSystem = previousStaffEntryMusicSystem;
-                let previousStaffEntryPositionX: number = previousStaffEntry.PositionAndShape.AbsolutePosition.x;
-                let previousSystemRightBorderX: number = currentMusicSystem.GetRightBorderAbsoluteXPosition();
+                const previousStaffEntryPositionX: number = previousStaffEntry.PositionAndShape.AbsolutePosition.x;
+                const previousSystemRightBorderX: number = currentMusicSystem.GetRightBorderAbsoluteXPosition();
                 fraction = (currentTimeStamp - previousStaffEntry.getAbsoluteTimestamp().RealValue) /
                     (nextSystemLeftBorderTimeStamp - previousStaffEntry.getAbsoluteTimestamp().RealValue);
                 fraction = Math.min(1, Math.max(0, fraction));
                 interpolatedXPosition = previousStaffEntryPositionX + fraction * (previousSystemRightBorderX - previousStaffEntryPositionX);
             } else {
                 currentMusicSystem = nextStaffEntryMusicSystem;
-                let nextStaffEntryPositionX: number = nextStaffEntry.PositionAndShape.AbsolutePosition.x;
-                let nextSystemLeftBorderX: number = currentMusicSystem.GetLeftBorderAbsoluteXPosition();
+                const nextStaffEntryPositionX: number = nextStaffEntry.PositionAndShape.AbsolutePosition.x;
+                const nextSystemLeftBorderX: number = currentMusicSystem.GetLeftBorderAbsoluteXPosition();
                 fraction = (currentTimeStamp - nextSystemLeftBorderTimeStamp) /
                     (nextStaffEntry.getAbsoluteTimestamp().RealValue - nextSystemLeftBorderTimeStamp);
                 fraction = Math.min(1, Math.max(0, fraction));
@@ -850,7 +850,7 @@ export class GraphicalMusicSheet {
     public GetNumberOfVisibleInstruments(): number {
         let visibleInstrumentCount: number = 0;
         for (let idx: number = 0, len: number = this.musicSheet.Instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = this.musicSheet.Instruments[idx];
+            const instrument: Instrument = this.musicSheet.Instruments[idx];
             if (instrument.Visible === true) {
                 visibleInstrumentCount++;
             }
@@ -861,7 +861,7 @@ export class GraphicalMusicSheet {
     public GetNumberOfFollowedInstruments(): number {
         let followedInstrumentCount: number = 0;
         for (let idx: number = 0, len: number = this.musicSheet.Instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = this.musicSheet.Instruments[idx];
+            const instrument: Instrument = this.musicSheet.Instruments[idx];
             if (instrument.Following === true) {
                 followedInstrumentCount++;
             }
@@ -874,16 +874,16 @@ export class GraphicalMusicSheet {
     }
 
     public GetGraphicalFromSourceStaffEntry(sourceStaffEntry: SourceStaffEntry): GraphicalStaffEntry {
-        let graphicalMeasure: StaffMeasure = this.GetGraphicalFromSourceMeasure(sourceStaffEntry.VerticalContainerParent.ParentMeasure)
+        const graphicalMeasure: StaffMeasure = this.GetGraphicalFromSourceMeasure(sourceStaffEntry.VerticalContainerParent.ParentMeasure)
             [sourceStaffEntry.ParentStaff.idInMusicSheet];
         return graphicalMeasure.findGraphicalStaffEntryFromTimestamp(sourceStaffEntry.Timestamp);
     }
 
     public GetGraphicalNoteFromSourceNote(note: Note, containingGse: GraphicalStaffEntry): GraphicalNote {
         for (let idx: number = 0, len: number = containingGse.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = containingGse.notes[idx];
+            const graphicalNotes: GraphicalNote[] = containingGse.notes[idx];
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                let graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
                 if (graphicalNote.sourceNote === note) {
                     return graphicalNote;
                 }
@@ -893,8 +893,8 @@ export class GraphicalMusicSheet {
     }
 
     private CalculateDistance(pt1: PointF2D, pt2: PointF2D): number {
-        let deltaX: number = pt1.x - pt2.x;
-        let deltaY: number = pt1.y - pt2.y;
+        const deltaX: number = pt1.x - pt2.x;
+        const deltaY: number = pt1.y - pt2.y;
         return (deltaX * deltaX) + (deltaY * deltaY);
     }
 
@@ -906,14 +906,14 @@ export class GraphicalMusicSheet {
     private getLongestStaffEntryDuration(index: number): Fraction {
         let maxLength: Fraction = new Fraction(0, 1);
         for (let idx: number = 0, len: number = this.verticalGraphicalStaffEntryContainers[index].StaffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: GraphicalStaffEntry = this.verticalGraphicalStaffEntryContainers[index].StaffEntries[idx];
+            const graphicalStaffEntry: GraphicalStaffEntry = this.verticalGraphicalStaffEntryContainers[index].StaffEntries[idx];
             if (graphicalStaffEntry === undefined) {
                 continue;
             }
             for (let idx2: number = 0, len2: number = graphicalStaffEntry.notes.length; idx2 < len2; ++idx2) {
-                let graphicalNotes: GraphicalNote[] = graphicalStaffEntry.notes[idx2];
+                const graphicalNotes: GraphicalNote[] = graphicalStaffEntry.notes[idx2];
                 for (let idx3: number = 0, len3: number = graphicalNotes.length; idx3 < len3; ++idx3) {
-                    let note: GraphicalNote = graphicalNotes[idx3];
+                    const note: GraphicalNote = graphicalNotes[idx3];
                     if (maxLength.lt(note.graphicalNoteLength)) {
                         maxLength = note.graphicalNoteLength;
                     }

+ 10 - 5
src/MusicalScore/Graphical/GraphicalNote.ts

@@ -38,7 +38,7 @@ export class GraphicalNote extends GraphicalObject {
 
     public get ParentList(): GraphicalNote[] {
         for (let idx: number = 0, len: number = this.parentStaffEntry.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.parentStaffEntry.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.parentStaffEntry.notes[idx];
             if (graphicalNotes.indexOf(this) !== -1) {
                 return graphicalNotes;
             }
@@ -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;
+      const 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);
     }
 }

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

@@ -74,7 +74,7 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
      * @returns {Fraction}
      */
     public getAbsoluteTimestamp(): Fraction {
-        let result: Fraction = this.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.clone();
+        const result: Fraction = this.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.clone();
         if (this.relInMeasureTimestamp !== undefined) {
             result.Add(this.relInMeasureTimestamp);
         }
@@ -88,10 +88,10 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
      */
     public findEndTieGraphicalNoteFromNote(tieNote: Note): GraphicalNote {
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                let graphicalNote: GraphicalNote = graphicalNotes[idx2];
-                let note: Note = graphicalNote.sourceNote;
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const note: Note = graphicalNote.sourceNote;
                 if (note.Pitch !== undefined && note.Pitch.FundamentalNote === tieNote.Pitch.FundamentalNote
                     && note.Pitch.Octave === tieNote.Pitch.Octave && note.getAbsoluteTimestamp().Equals(tieNote.getAbsoluteTimestamp())) {
                     return graphicalNote;
@@ -109,10 +109,10 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
      */
     public findEndTieGraphicalNoteFromNoteWithStartingSlur(tieNote: Note, slur: Slur): GraphicalNote {
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                let graphicalNote: GraphicalNote = graphicalNotes[idx2];
-                let note: Note = graphicalNote.sourceNote;
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const note: Note = graphicalNote.sourceNote;
                 if (note.NoteTie !== undefined && note.NoteSlurs.indexOf(slur) !== -1) {
                     return graphicalNote;
                 }
@@ -128,10 +128,10 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
      */
     public findEndTieGraphicalNoteFromNoteWithEndingSlur(tieNote: Note): GraphicalNote {
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                let graphicalNote: GraphicalNote = graphicalNotes[idx2];
-                let note: Note = graphicalNote.sourceNote;
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const note: Note = graphicalNote.sourceNote;
                 if (
                     note.Pitch !== undefined && note.Pitch.FundamentalNote === tieNote.Pitch.FundamentalNote
                     && note.Pitch.Octave === tieNote.Pitch.Octave && this.getAbsoluteTimestamp().Equals(tieNote.getAbsoluteTimestamp())
@@ -145,9 +145,9 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
 
     public findGraphicalNoteFromGraceNote(graceNote: Note): GraphicalNote {
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                let graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
                 if (graphicalNote.sourceNote === graceNote) {
                     return graphicalNote;
                 }
@@ -158,9 +158,9 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
 
     public findGraphicalNoteFromNote(baseNote: Note): GraphicalNote {
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                let graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
                 if (graphicalNote.sourceNote === baseNote && this.getAbsoluteTimestamp().Equals(baseNote.getAbsoluteTimestamp())) {
                     return graphicalNote;
                 }
@@ -171,7 +171,7 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
 
     public getGraphicalNoteDurationFromVoice(voice: Voice): Fraction {
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             if (graphicalNotes[0].sourceNote.ParentVoiceEntry.ParentVoice === voice) {
                 return graphicalNotes[0].graphicalNoteLength;
             }
@@ -186,9 +186,9 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
     public findLinkedNotes(notLinkedNotes: GraphicalNote[]): void {
         if (this.sourceStaffEntry !== undefined && this.sourceStaffEntry.Link !== undefined) {
             for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-                let graphicalNotes: GraphicalNote[] = this.notes[idx];
+                const graphicalNotes: GraphicalNote[] = this.notes[idx];
                 for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                    let graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                    const graphicalNote: GraphicalNote = graphicalNotes[idx2];
                     if (graphicalNote.parentStaffEntry === this) {
                         notLinkedNotes.push(graphicalNote);
                     }
@@ -204,9 +204,9 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
      */
     public findVoiceEntryGraphicalNotes(voiceEntry: VoiceEntry): GraphicalNote[] {
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             for (let idx2: number = 0, len2: number = graphicalNotes.length; idx2 < len2; ++idx2) {
-                let graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
                 if (graphicalNote.sourceNote.ParentVoiceEntry === voiceEntry) {
                     return graphicalNotes;
                 }
@@ -223,7 +223,7 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
     public isVoiceEntryPartOfLinkedVoiceEntry(voiceEntry: VoiceEntry): boolean {
         if (this.sourceStaffEntry.Link !== undefined) {
             for (let idx: number = 0, len: number = this.sourceStaffEntry.Link.LinkStaffEntries.length; idx < len; ++idx) {
-                let sEntry: SourceStaffEntry = this.sourceStaffEntry.Link.LinkStaffEntries[idx];
+                const sEntry: SourceStaffEntry = this.sourceStaffEntry.Link.LinkStaffEntries[idx];
                 if (sEntry.VoiceEntries.indexOf(voiceEntry) !== -1 && sEntry !== this.sourceStaffEntry) {
                     return true;
                 }
@@ -234,7 +234,7 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
 
     public getMainVoice(): Voice {
         for (let idx: number = 0, len: number = this.sourceStaffEntry.VoiceEntries.length; idx < len; ++idx) {
-            let voiceEntry: VoiceEntry = this.sourceStaffEntry.VoiceEntries[idx];
+            const voiceEntry: VoiceEntry = this.sourceStaffEntry.VoiceEntries[idx];
             if (!(voiceEntry.ParentVoice instanceof LinkedVoice)) {
                 return voiceEntry.ParentVoice;
             }
@@ -249,11 +249,11 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
     public findStaffEntryMinNoteLength(): Fraction {
         let minLength: Fraction = new Fraction(Number.MAX_VALUE, 1);
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             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) {
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
+                if (calNoteLen.lt(minLength) && calNoteLen.GetExpandedNumerator() > 0) {
                     minLength = calNoteLen;
                 }
             }
@@ -264,11 +264,11 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
     public findStaffEntryMaxNoteLength(): Fraction {
         let maxLength: Fraction = new Fraction(0, 1);
         for (let idx: number = 0, len: number = this.notes.length; idx < len; ++idx) {
-            let graphicalNotes: GraphicalNote[] = this.notes[idx];
+            const graphicalNotes: GraphicalNote[] = this.notes[idx];
             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) {
+                const graphicalNote: GraphicalNote = graphicalNotes[idx2];
+                const calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
+                if (maxLength.lt(calNoteLen)  && calNoteLen.GetExpandedNumerator() > 0) {
                     maxLength = calNoteLen;
                 }
             }
@@ -305,7 +305,7 @@ export abstract class GraphicalStaffEntry extends GraphicalObject {
      */
     public findOrCreateGraphicalNotesListFromGraphicalNote(graphicalNote: GraphicalNote): GraphicalNote[] {
         let graphicalNotes: GraphicalNote[];
-        let tieStartSourceStaffEntry: SourceStaffEntry = graphicalNote.sourceNote.ParentStaffEntry;
+        const tieStartSourceStaffEntry: SourceStaffEntry = graphicalNote.sourceNote.ParentStaffEntry;
         if (this.sourceStaffEntry !== tieStartSourceStaffEntry) {
             graphicalNotes = this.findOrCreateGraphicalNotesListFromVoiceEntry(graphicalNote.sourceNote.ParentVoiceEntry);
         } else {

+ 4 - 4
src/MusicalScore/Graphical/GraphicalStaffEntryLink.ts

@@ -38,13 +38,13 @@ export class GraphicalStaffEntryLink {
      */
     public getLinkedStaffEntriesGraphicalNotes(graphicalStaffEntry: GraphicalStaffEntry): GraphicalNote[] {
         if (this.graphicalLinkedStaffEntries.indexOf(graphicalStaffEntry) !== -1) {
-            let notes: GraphicalNote[] = [];
+            const notes: GraphicalNote[] = [];
             for (let idx: number = 0, len: number = this.graphicalLinkedStaffEntries.length; idx < len; ++idx) {
-                let graphicalLinkedStaffEntry: GraphicalStaffEntry = this.graphicalLinkedStaffEntries[idx];
+                const graphicalLinkedStaffEntry: GraphicalStaffEntry = this.graphicalLinkedStaffEntries[idx];
                 for (let idx2: number = 0, len2: number = graphicalLinkedStaffEntry.notes.length; idx2 < len2; ++idx2) {
-                    let graphicalNotes: GraphicalNote[] = graphicalLinkedStaffEntry.notes[idx2];
+                    const graphicalNotes: GraphicalNote[] = graphicalLinkedStaffEntry.notes[idx2];
                     for (let idx3: number = 0, len3: number = graphicalNotes.length; idx3 < len3; ++idx3) {
-                        let graphicalNote: GraphicalNote = graphicalNotes[idx3];
+                        const graphicalNote: GraphicalNote = graphicalNotes[idx3];
                         if (graphicalNote.sourceNote.ParentStaffEntry.Link !== undefined
                             && graphicalNote.sourceNote.ParentVoiceEntry === this.staffEntryLink.GetVoiceEntry) {
                             notes.push(graphicalNote);

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 201 - 207
src/MusicalScore/Graphical/MusicSheetCalculator.ts


+ 87 - 58
src/MusicalScore/Graphical/MusicSheetDrawer.ts

@@ -67,8 +67,8 @@ export abstract class MusicSheetDrawer {
         this.rules = graphicalMusicSheet.ParentMusicSheet.Rules;
         this.drawSplitScreenLine();
         if (this.drawingParameters.drawCursors) {
-            for (let line of graphicalMusicSheet.Cursors) {
-                let psi: BoundingBox = new BoundingBox(line);
+            for (const line of graphicalMusicSheet.Cursors) {
+                const psi: BoundingBox = new BoundingBox(line);
                 psi.AbsolutePosition = line.Start;
                 psi.BorderBottom = line.End.y - line.Start.y;
                 psi.BorderRight = line.Width / 2.0;
@@ -83,7 +83,7 @@ export abstract class MusicSheetDrawer {
             this.drawScrollIndicator();
         }
         // Draw all the pages
-        for (let page of this.graphicalMusicSheet.MusicPages) {
+        for (const page of this.graphicalMusicSheet.MusicPages) {
             this.drawPage(page);
         }
     }
@@ -95,33 +95,33 @@ export abstract class MusicSheetDrawer {
     }
 
     public drawLineAsVerticalRectangle(line: GraphicalLine, layer: number): void {
-        let lineStart: PointF2D = line.Start;
-        let lineWidth: number = line.Width;
+        const lineStart: PointF2D = line.Start;
+        const lineWidth: number = line.Width;
         let rectangle: RectangleF2D = new RectangleF2D(lineStart.x - lineWidth / 2, lineStart.y, lineWidth, line.End.y - lineStart.y);
         rectangle = this.applyScreenTransformationForRect(rectangle);
         this.renderRectangle(rectangle, layer, line.styleId);
     }
 
     public drawLineAsHorizontalRectangleWithOffset(line: GraphicalLine, offset: PointF2D, layer: number): void {
-        let start: PointF2D = new PointF2D(line.Start.x + offset.x, line.Start.y + offset.y);
-        let end: PointF2D = new PointF2D(line.End.x + offset.x, line.End.y + offset.y);
-        let width: number = line.Width;
+        const start: PointF2D = new PointF2D(line.Start.x + offset.x, line.Start.y + offset.y);
+        const end: PointF2D = new PointF2D(line.End.x + offset.x, line.End.y + offset.y);
+        const width: number = line.Width;
         let rectangle: RectangleF2D = new RectangleF2D(start.x, end.y - width / 2, end.x - start.x, width);
         rectangle = this.applyScreenTransformationForRect(rectangle);
         this.renderRectangle(rectangle, layer, line.styleId);
     }
 
     public drawLineAsVerticalRectangleWithOffset(line: GraphicalLine, offset: PointF2D, layer: number): void {
-        let start: PointF2D = new PointF2D(line.Start.x + offset.x, line.Start.y + offset.y);
-        let end: PointF2D = new PointF2D(line.End.x + offset.x, line.End.y + offset.y);
-        let width: number = line.Width;
+        const start: PointF2D = new PointF2D(line.Start.x + offset.x, line.Start.y + offset.y);
+        const end: PointF2D = new PointF2D(line.End.x + offset.x, line.End.y + offset.y);
+        const width: number = line.Width;
         let rectangle: RectangleF2D = new RectangleF2D(start.x, start.y, width, end.y - start.y);
         rectangle = this.applyScreenTransformationForRect(rectangle);
         this.renderRectangle(rectangle, layer, line.styleId);
     }
 
     public drawRectangle(rect: GraphicalRectangle, layer: number): void {
-        let psi: BoundingBox = rect.PositionAndShape;
+        const psi: BoundingBox = rect.PositionAndShape;
         let rectangle: RectangleF2D = new RectangleF2D(psi.AbsolutePosition.x, psi.AbsolutePosition.y, psi.BorderRight, psi.BorderBottom);
         rectangle = this.applyScreenTransformationForRect(rectangle);
         this.renderRectangle(rectangle, layer, <number>rect.style);
@@ -135,15 +135,15 @@ export abstract class MusicSheetDrawer {
         if (!this.isVisible(graphicalLabel.PositionAndShape)) {
             return;
         }
-        let label: Label = graphicalLabel.Label;
+        const label: Label = graphicalLabel.Label;
         if (label.text.trim() === "") {
             return;
         }
-        let screenPosition: PointF2D = this.applyScreenTransformation(graphicalLabel.PositionAndShape.AbsolutePosition);
-        let heightInPixel: number = this.calculatePixelDistance(label.fontHeight);
-        let widthInPixel: number = heightInPixel * this.textMeasurer.computeTextWidthToHeightRatio(label.text, label.font, label.fontStyle);
-        let bitmapWidth: number = <number>Math.ceil(widthInPixel);
-        let bitmapHeight: number = <number>Math.ceil(heightInPixel * 1.2);
+        const screenPosition: PointF2D = this.applyScreenTransformation(graphicalLabel.PositionAndShape.AbsolutePosition);
+        const heightInPixel: number = this.calculatePixelDistance(label.fontHeight);
+        const widthInPixel: number = heightInPixel * this.textMeasurer.computeTextWidthToHeightRatio(label.text, label.font, label.fontStyle);
+        const bitmapWidth: number = <number>Math.ceil(widthInPixel);
+        const bitmapHeight: number = <number>Math.ceil(heightInPixel * 1.2);
         switch (label.textAlignment) {
             case TextAlignment.LeftTop:
                 break;
@@ -186,8 +186,8 @@ export abstract class MusicSheetDrawer {
     }
 
     protected applyScreenTransformations(points: PointF2D[]): PointF2D[] {
-        let transformedPoints: PointF2D[] = [];
-        for (let point of points) {
+        const transformedPoints: PointF2D[] = [];
+        for (const point of points) {
             transformedPoints.push(this.applyScreenTransformation(point));
         }
         return transformedPoints;
@@ -201,7 +201,7 @@ export abstract class MusicSheetDrawer {
         // empty
     }
 
-    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number): void {
+    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number, alpha: number = 1): void {
         throw new Error("not implemented");
     }
 
@@ -239,7 +239,7 @@ export abstract class MusicSheetDrawer {
         // empty
     }
 
-    protected drawInstrumentBracket(bracket: GraphicalObject, system: MusicSystem): void {
+    protected drawInstrumentBrace(brace: GraphicalObject, system: MusicSystem): void {
         // empty
     }
 
@@ -252,21 +252,21 @@ export abstract class MusicSheetDrawer {
     }
 
     protected drawMusicSystem(system: MusicSystem): void {
-        let absBoundingRectWithMargin: RectangleF2D = this.getSystemAbsBoundingRect(system);
-        let systemBoundingBoxInPixels: RectangleF2D = this.getSytemBoundingBoxInPixels(absBoundingRectWithMargin);
+        const absBoundingRectWithMargin: RectangleF2D = this.getSystemAbsBoundingRect(system);
+        const systemBoundingBoxInPixels: RectangleF2D = this.getSytemBoundingBoxInPixels(absBoundingRectWithMargin);
         this.drawMusicSystemComponents(system, systemBoundingBoxInPixels, absBoundingRectWithMargin);
     }
 
     protected getSytemBoundingBoxInPixels(absBoundingRectWithMargin: RectangleF2D): RectangleF2D {
-        let systemBoundingBoxInPixels: RectangleF2D = this.applyScreenTransformationForRect(absBoundingRectWithMargin);
+        const systemBoundingBoxInPixels: RectangleF2D = this.applyScreenTransformationForRect(absBoundingRectWithMargin);
         systemBoundingBoxInPixels.x = Math.round(systemBoundingBoxInPixels.x);
         systemBoundingBoxInPixels.y = Math.round(systemBoundingBoxInPixels.y);
         return systemBoundingBoxInPixels;
     }
 
     protected getSystemAbsBoundingRect(system: MusicSystem): RectangleF2D {
-        let relBoundingRect: RectangleF2D = system.PositionAndShape.BoundingRectangle;
-        let absBoundingRectWithMargin: RectangleF2D = new RectangleF2D(
+        const relBoundingRect: RectangleF2D = system.PositionAndShape.BoundingRectangle;
+        const absBoundingRectWithMargin: RectangleF2D = new RectangleF2D(
             system.PositionAndShape.AbsolutePosition.x + system.PositionAndShape.BorderLeft - 1,
             system.PositionAndShape.AbsolutePosition.y + system.PositionAndShape.BorderTop - 1,
             (relBoundingRect.width + 6), (relBoundingRect.height + 2)
@@ -276,8 +276,8 @@ export abstract class MusicSheetDrawer {
 
     protected drawMusicSystemComponents(musicSystem: MusicSystem, systemBoundingBoxInPixels: RectangleF2D,
                                         absBoundingRectWithMargin: RectangleF2D): void {
-        let selectStartSymb: SelectionStartSymbol = this.graphicalMusicSheet.SelectionStartSymbol;
-        let selectEndSymb: SelectionEndSymbol = this.graphicalMusicSheet.SelectionEndSymbol;
+        const selectStartSymb: SelectionStartSymbol = this.graphicalMusicSheet.SelectionStartSymbol;
+        const selectEndSymb: SelectionEndSymbol = this.graphicalMusicSheet.SelectionEndSymbol;
         if (this.drawingParameters.drawSelectionStartSymbol) {
             if (selectStartSymb !== undefined && this.isVisible(selectStartSymb.PositionAndShape)) {
                 this.drawSelectionStartSymbol(selectStartSymb);
@@ -288,29 +288,29 @@ export abstract class MusicSheetDrawer {
                 this.drawSelectionEndSymbol(selectEndSymb);
             }
         }
-        for (let staffLine of musicSystem.StaffLines) {
+        for (const staffLine of musicSystem.StaffLines) {
             this.drawStaffLine(staffLine);
         }
-        for (let systemLine of musicSystem.SystemLines) {
+        for (const systemLine of musicSystem.SystemLines) {
             this.drawSystemLineObject(systemLine);
         }
         if (musicSystem === musicSystem.Parent.MusicSystems[0] && musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
-            for (let label of musicSystem.Labels) {
+            for (const label of musicSystem.Labels) {
                 this.drawLabel(label, <number>GraphicalLayers.Notes);
             }
         }
-        for (let bracket of musicSystem.InstrumentBrackets) {
-            this.drawInstrumentBracket(bracket, musicSystem);
+        for (const bracket of musicSystem.InstrumentBrackets) {
+            this.drawInstrumentBrace(bracket, musicSystem);
         }
-        for (let bracket of musicSystem.GroupBrackets) {
+        for (const bracket of musicSystem.GroupBrackets) {
             this.drawGroupBracket(bracket, musicSystem);
         }
         if (!this.leadSheet) {
-            for (let measureNumberLabel of musicSystem.MeasureNumberLabels) {
+            for (const measureNumberLabel of musicSystem.MeasureNumberLabels) {
                 this.drawLabel(measureNumberLabel, <number>GraphicalLayers.Notes);
             }
         }
-        for (let staffLine of musicSystem.StaffLines) {
+        for (const staffLine of musicSystem.StaffLines) {
             this.drawStaffLineSymbols(staffLine);
         }
         if (this.drawingParameters.drawMarkedAreas) {
@@ -331,7 +331,7 @@ export abstract class MusicSheetDrawer {
     }
 
     protected drawStaffLine(staffLine: StaffLine): void {
-        for (let measure of staffLine.Measures) {
+        for (const measure of staffLine.Measures) {
             this.drawMeasure(measure);
         }
     }
@@ -342,17 +342,17 @@ export abstract class MusicSheetDrawer {
 
     protected drawOctaveShift(staffLine: StaffLine, graphicalOctaveShift: GraphicalOctaveShift): void {
         this.drawSymbol(graphicalOctaveShift.octaveSymbol, MusicSymbolDrawingStyle.Normal, graphicalOctaveShift.PositionAndShape.AbsolutePosition);
-        let absolutePos: PointF2D = staffLine.PositionAndShape.AbsolutePosition;
+        const absolutePos: PointF2D = staffLine.PositionAndShape.AbsolutePosition;
         if (graphicalOctaveShift.dashesStart.x < graphicalOctaveShift.dashesEnd.x) {
-            let horizontalLine: GraphicalLine = new GraphicalLine(graphicalOctaveShift.dashesStart, graphicalOctaveShift.dashesEnd,
-                                                                  this.rules.OctaveShiftLineWidth);
+            const horizontalLine: GraphicalLine = new GraphicalLine(graphicalOctaveShift.dashesStart, graphicalOctaveShift.dashesEnd,
+                                                                    this.rules.OctaveShiftLineWidth);
             this.drawLineAsHorizontalRectangleWithOffset(horizontalLine, absolutePos, <number>GraphicalLayers.Notes);
         }
         if (!graphicalOctaveShift.endsOnDifferentStaffLine || graphicalOctaveShift.isSecondPart) {
             let verticalLine: GraphicalLine;
-            let dashEnd: PointF2D = graphicalOctaveShift.dashesEnd;
-            let octShiftVertLineLength: number = this.rules.OctaveShiftVerticalLineLength;
-            let octShiftLineWidth: number = this.rules.OctaveShiftLineWidth;
+            const dashEnd: PointF2D = graphicalOctaveShift.dashesEnd;
+            const octShiftVertLineLength: number = this.rules.OctaveShiftVerticalLineLength;
+            const octShiftLineWidth: number = this.rules.OctaveShiftLineWidth;
             if (graphicalOctaveShift.octaveSymbol === MusicSymbol.VA8 || graphicalOctaveShift.octaveSymbol === MusicSymbol.MA15) {
                 verticalLine = new GraphicalLine(dashEnd, new PointF2D(dashEnd.x, dashEnd.y + octShiftVertLineLength), octShiftLineWidth);
             } else {
@@ -364,7 +364,7 @@ export abstract class MusicSheetDrawer {
 
     protected drawStaffLines(staffLine: StaffLine): void {
         if (staffLine.StaffLines !== undefined) {
-            let position: PointF2D = staffLine.PositionAndShape.AbsolutePosition;
+            const position: PointF2D = staffLine.PositionAndShape.AbsolutePosition;
             for (let i: number = 0; i < 5; i++) {
                 this.drawLineAsHorizontalRectangleWithOffset(staffLine.StaffLines[i], position, <number>GraphicalLayers.Notes);
             }
@@ -407,20 +407,49 @@ export abstract class MusicSheetDrawer {
         if (!this.isVisible(page.PositionAndShape)) {
             return;
         }
-        for (let system of page.MusicSystems) {
+
+        for (const system of page.MusicSystems) {
             if (this.isVisible(system.PositionAndShape)) {
                 this.drawMusicSystem(system);
             }
         }
         if (page === page.Parent.MusicPages[0]) {
-            for (let label of page.Labels) {
+            for (const label of page.Labels) {
                 this.drawLabel(label, <number>GraphicalLayers.Notes);
             }
         }
+        // Draw bounding boxes for debug purposes. This has to be at the end because only
+        // then all the calculations and recalculations are done
+        if (process.env.DRAW_BOUNDING_BOX_ELEMENT) {
+            this.drawBoundingBoxes(page.PositionAndShape, 0, process.env.DRAW_BOUNDING_BOX_ELEMENT);
+        }
+
+    }
+
+    /**
+     * Draw bounding boxes aroung GraphicalObjects
+     * @param startBox Bounding Box that is used as a staring point to recursively go through all child elements
+     * @param layer Layer to draw to
+     * @param type Type of element to show bounding boxes for as string.
+     */
+    private drawBoundingBoxes(startBox: BoundingBox, layer: number = 0, type: string = "all"): void {
+        const dataObjectString: string = (startBox.DataObject.constructor as any).name;
+        if (startBox.BoundingRectangle !== undefined && (dataObjectString === type || type === "all")) {
+            const relBoundingRect: RectangleF2D = startBox.BoundingRectangle;
+            let tmpRect: RectangleF2D = new RectangleF2D(startBox.AbsolutePosition.x + startBox.BorderLeft,
+                                                         startBox.AbsolutePosition.y + startBox.BorderTop ,
+                                                         (relBoundingRect.width + 0), (relBoundingRect.height + 0));
+            tmpRect = this.applyScreenTransformationForRect(tmpRect);
+            this.renderRectangle(tmpRect, <number>GraphicalLayers.Background, layer, 0.5);
+            this.renderLabel(new GraphicalLabel(new Label(dataObjectString), 1.2, TextAlignment.CenterCenter),
+                             layer, tmpRect.width, tmpRect.height, tmpRect.height, new PointF2D(tmpRect.x, tmpRect.y + 12));
+        }
+        layer++;
+        startBox.ChildElements.forEach(bb => this.drawBoundingBoxes(bb, layer, type));
     }
 
     private drawMarkedAreas(system: MusicSystem): void {
-        for (let markedArea of system.GraphicalMarkedAreas) {
+        for (const markedArea of system.GraphicalMarkedAreas) {
             if (markedArea !== undefined) {
                 if (markedArea.systemRectangle !== undefined) {
                     this.drawRectangle(markedArea.systemRectangle, <number>GraphicalLayers.Background);
@@ -439,7 +468,7 @@ export abstract class MusicSheetDrawer {
     }
 
     private drawComment(system: MusicSystem): void {
-        for (let comment of system.GraphicalComments) {
+        for (const comment of system.GraphicalComments) {
             if (comment !== undefined) {
                 if (comment.settings !== undefined) {
                     this.drawLabel(comment.settings, <number>GraphicalLayers.Comment);
@@ -452,10 +481,10 @@ export abstract class MusicSheetDrawer {
     }
 
     private drawStaffLineSymbols(staffLine: StaffLine): void {
-        let parentInst: Instrument = staffLine.ParentStaff.ParentInstrument;
-        let absX: number = staffLine.PositionAndShape.AbsolutePosition.x;
-        let absY: number = staffLine.PositionAndShape.AbsolutePosition.y + 2;
-        let borderRight: number = staffLine.PositionAndShape.BorderRight;
+        const parentInst: Instrument = staffLine.ParentStaff.ParentInstrument;
+        const absX: number = staffLine.PositionAndShape.AbsolutePosition.x;
+        const absY: number = staffLine.PositionAndShape.AbsolutePosition.y + 2;
+        const borderRight: number = staffLine.PositionAndShape.BorderRight;
         if (parentInst.highlight && this.drawingParameters.drawHighlights) {
             this.drawLineAsHorizontalRectangle(
                 new GraphicalLine(
@@ -488,14 +517,14 @@ export abstract class MusicSheetDrawer {
                 break;
         }
         if (drawSymbols) {
-            let p: PointF2D = new PointF2D(absX + borderRight + 2, absY);
+            const p: PointF2D = new PointF2D(absX + borderRight + 2, absY);
             this.drawSymbol(symbol, style, p);
         }
         if (this.drawingParameters.drawErrors) {
-            for (let measure of staffLine.Measures) {
-                let measurePSI: BoundingBox = measure.PositionAndShape;
-                let absXPSI: number = measurePSI.AbsolutePosition.x;
-                let absYPSI: number = measurePSI.AbsolutePosition.y + 2;
+            for (const measure of staffLine.Measures) {
+                const measurePSI: BoundingBox = measure.PositionAndShape;
+                const absXPSI: number = measurePSI.AbsolutePosition.x;
+                const absYPSI: number = measurePSI.AbsolutePosition.y + 2;
                 if (measure.hasError && this.graphicalMusicSheet.ParentMusicSheet.DrawErroneousMeasures) {
                     this.drawLineAsHorizontalRectangle(
                         new GraphicalLine(

+ 39 - 44
src/MusicalScore/Graphical/MusicSystem.ts

@@ -14,7 +14,6 @@ import {PointF2D} from "../../Common/DataObjects/PointF2D";
 import {GraphicalStaffEntry} from "./GraphicalStaffEntry";
 import {SystemLinesEnum} from "./SystemLinesEnum";
 import Dictionary from "typescript-collections/dist/lib/Dictionary";
-import {CollectionUtil} from "../../Util/CollectionUtil";
 import {GraphicalComment} from "./GraphicalComment";
 import {GraphicalMarkedArea} from "./GraphicalMarkedArea";
 import {SystemLine} from "./SystemLine";
@@ -112,15 +111,14 @@ export abstract class MusicSystem extends GraphicalObject {
         if (this === this.parent.MusicSystems[0] && this.parent === this.parent.Parent.MusicPages[0]) {
             xPosition = this.maxLabelLength + systemLabelsRightMargin - lineWidth / 2;
         }
-        let top: StaffMeasure = this.staffLines[0].Measures[0];
+        const top: StaffMeasure = this.staffLines[0].Measures[0];
         let bottom: StaffMeasure = undefined;
         if (this.staffLines.length > 1) {
             bottom = this.staffLines[this.staffLines.length - 1].Measures[0];
         }
-        let leftSystemLine: SystemLine = this.createSystemLine(xPosition, lineWidth, SystemLinesEnum.SingleThin,
-                                                               SystemLinePosition.MeasureBegin, this, top, bottom);
+        const leftSystemLine: SystemLine = this.createSystemLine(xPosition, lineWidth, SystemLinesEnum.SingleThin,
+                                                                 SystemLinePosition.MeasureBegin, this, top, bottom);
         this.SystemLines.push(leftSystemLine);
-        this.boundingBox.ChildElements.push(leftSystemLine.PositionAndShape);
         leftSystemLine.PositionAndShape.RelativePosition = new PointF2D(xPosition, 0);
         leftSystemLine.PositionAndShape.BorderLeft = 0;
         leftSystemLine.PositionAndShape.BorderRight = lineWidth;
@@ -140,22 +138,22 @@ export abstract class MusicSystem extends GraphicalObject {
      */
     public createVerticalLineForMeasure(xPosition: number, lineWidth: number, lineType: SystemLinesEnum, linePosition: SystemLinePosition,
                                         measureIndex: number, measure: StaffMeasure): void {
-        let staffLine: StaffLine = measure.ParentStaffLine;
-        let staffLineRelative: PointF2D = new PointF2D(staffLine.PositionAndShape.RelativePosition.x,
-                                                       staffLine.PositionAndShape.RelativePosition.y);
-        let staves: Staff[] = staffLine.ParentStaff.ParentInstrument.Staves;
+        const staffLine: StaffLine = measure.ParentStaffLine;
+        const staffLineRelative: PointF2D = new PointF2D(staffLine.PositionAndShape.RelativePosition.x,
+                                                         staffLine.PositionAndShape.RelativePosition.y);
+        const staves: Staff[] = staffLine.ParentStaff.ParentInstrument.Staves;
         if (staffLine.ParentStaff === staves[0]) {
             let bottomMeasure: StaffMeasure = undefined;
             if (staves.length > 1) {
                 bottomMeasure = this.getBottomStaffLine(staffLine).Measures[measureIndex];
             }
-            let singleVerticalLineAfterMeasure: SystemLine = this.createSystemLine(xPosition, lineWidth, lineType, linePosition, this, measure, bottomMeasure);
-            let systemXPosition: number = staffLineRelative.x + xPosition;
+            const singleVerticalLineAfterMeasure: SystemLine = this.createSystemLine(xPosition, lineWidth, lineType,
+                                                                                     linePosition, this, measure, bottomMeasure);
+            const systemXPosition: number = staffLineRelative.x + xPosition;
             singleVerticalLineAfterMeasure.PositionAndShape.RelativePosition = new PointF2D(systemXPosition, 0);
             singleVerticalLineAfterMeasure.PositionAndShape.BorderLeft = 0;
             singleVerticalLineAfterMeasure.PositionAndShape.BorderRight = lineWidth;
             this.SystemLines.push(singleVerticalLineAfterMeasure);
-            this.boundingBox.ChildElements.push(singleVerticalLineAfterMeasure.PositionAndShape);
         }
     }
 
@@ -185,7 +183,7 @@ export abstract class MusicSystem extends GraphicalObject {
 
     public AddStaffMeasures(graphicalMeasures: StaffMeasure[]): void {
         for (let idx: number = 0, len: number = graphicalMeasures.length; idx < len; ++idx) {
-            let graphicalMeasure: StaffMeasure = graphicalMeasures[idx];
+            const graphicalMeasure: StaffMeasure = graphicalMeasures[idx];
             graphicalMeasure.parentMusicSystem = this;
         }
         this.graphicalMeasures.push(graphicalMeasures);
@@ -196,7 +194,7 @@ export abstract class MusicSystem extends GraphicalObject {
     }
 
     public GetSystemsLastTimeStamp(): Fraction {
-        let m: SourceMeasure = this.graphicalMeasures[this.graphicalMeasures.length - 1][0].parentSourceMeasure;
+        const m: SourceMeasure = this.graphicalMeasures[this.graphicalMeasures.length - 1][0].parentSourceMeasure;
         return Fraction.plus(m.AbsoluteTimestamp, m.Duration);
     }
 
@@ -207,11 +205,11 @@ export abstract class MusicSystem extends GraphicalObject {
      */
     public createInstrumentBrackets(instruments: Instrument[], staffHeight: number): void {
         for (let idx: number = 0, len: number = instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = instruments[idx];
+            const instrument: Instrument = instruments[idx];
             if (instrument.Staves.length > 1) {
                 let firstStaffLine: StaffLine = undefined, lastStaffLine: StaffLine = undefined;
                 for (let idx2: number = 0, len2: number = this.staffLines.length; idx2 < len2; ++idx2) {
-                    let staffLine: StaffLine = this.staffLines[idx2];
+                    const staffLine: StaffLine = this.staffLines[idx2];
                     if (staffLine.ParentStaff === instrument.Staves[0]) {
                         firstStaffLine = staffLine;
                     }
@@ -234,24 +232,21 @@ export abstract class MusicSystem extends GraphicalObject {
      */
     public createGroupBrackets(instrumentGroups: InstrumentalGroup[], staffHeight: number, recursionDepth: number): void {
         for (let idx: number = 0, len: number = instrumentGroups.length; idx < len; ++idx) {
-            let instrumentGroup: InstrumentalGroup = instrumentGroups[idx];
+            const instrumentGroup: InstrumentalGroup = instrumentGroups[idx];
             if (instrumentGroup.InstrumentalGroups.length < 1) {
                 continue;
             }
-            let instrument1: Instrument = this.findFirstVisibleInstrumentInInstrumentalGroup(instrumentGroup);
-            let instrument2: Instrument = this.findLastVisibleInstrumentInInstrumentalGroup(instrumentGroup);
+            const instrument1: Instrument = this.findFirstVisibleInstrumentInInstrumentalGroup(instrumentGroup);
+            const instrument2: Instrument = this.findLastVisibleInstrumentInInstrumentalGroup(instrumentGroup);
             if (instrument1 === undefined || instrument2 === undefined) {
                 continue;
             }
-            let firstStaffLine: StaffLine = undefined, lastStaffLine: StaffLine = undefined;
+            let firstStaffLine: StaffLine = undefined;
             for (let idx2: number = 0, len2: number = this.staffLines.length; idx2 < len2; ++idx2) {
-                let staffLine: StaffLine = this.staffLines[idx2];
+                const staffLine: StaffLine = this.staffLines[idx2];
                 if (staffLine.ParentStaff === instrument1.Staves[0]) {
                     firstStaffLine = staffLine;
                 }
-                if (staffLine.ParentStaff === CollectionUtil.last(instrument2.Staves)) {
-                    lastStaffLine = staffLine;
-                }
             }
             if (firstStaffLine !== undefined && firstStaffLine !== undefined) {
                 this.createGroupBracket(firstStaffLine, firstStaffLine, recursionDepth);
@@ -271,15 +266,15 @@ export abstract class MusicSystem extends GraphicalObject {
      */
     public createMusicSystemLabel(instrumentLabelTextHeight: number, systemLabelsRightMargin: number, labelMarginBorderFactor: number): void {
         if (this.parent === this.parent.Parent.MusicPages[0] && this === this.parent.MusicSystems[0]) {
-            let instruments: Instrument[] = this.parent.Parent.ParentMusicSheet.getVisibleInstruments();
+            const instruments: Instrument[] = this.parent.Parent.ParentMusicSheet.getVisibleInstruments();
             for (let idx: number = 0, len: number = instruments.length; idx < len; ++idx) {
-                let instrument: Instrument = instruments[idx];
-                let graphicalLabel: GraphicalLabel = new GraphicalLabel(
+                const instrument: Instrument = instruments[idx];
+                const graphicalLabel: GraphicalLabel = new GraphicalLabel(
                     instrument.NameLabel, instrumentLabelTextHeight, TextAlignment.LeftCenter, this.boundingBox
                 );
                 graphicalLabel.setLabelPositionAndShapeBorders();
                 this.labels.setValue(graphicalLabel, instrument);
-                this.boundingBox.ChildElements.push(graphicalLabel.PositionAndShape);
+                //graphicalLabel.PositionAndShape.Parent = this.PositionAndShape;
 
                 // X-Position will be 0 (Label starts at the same PointF_2D with MusicSystem)
                 // Y-Position will be calculated after the y-Spacing
@@ -288,9 +283,9 @@ export abstract class MusicSystem extends GraphicalObject {
 
             // calculate maxLabelLength (needed for X-Spacing)
             this.maxLabelLength = 0.0;
-            let labels: GraphicalLabel[] = this.labels.keys();
+            const labels: GraphicalLabel[] = this.labels.keys();
             for (let idx: number = 0, len: number = labels.length; idx < len; ++idx) {
-                let label: GraphicalLabel = labels[idx];
+                const label: GraphicalLabel = labels[idx];
                 if (label.PositionAndShape.Size.width > this.maxLabelLength) {
                     this.maxLabelLength = label.PositionAndShape.Size.width;
                 }
@@ -310,7 +305,7 @@ export abstract class MusicSystem extends GraphicalObject {
                 for (let i: number = 0; i < this.staffLines.length; i++) {
                     if (this.staffLines[i].ParentStaff.ParentInstrument === value) {
                         for (let j: number = i; j < this.staffLines.length; j++) {
-                            let staffLine: StaffLine = this.staffLines[j];
+                            const staffLine: StaffLine = this.staffLines[j];
                             if (staffLine.ParentStaff.ParentInstrument !== value) {
                                 break;
                             }
@@ -337,18 +332,18 @@ export abstract class MusicSystem extends GraphicalObject {
         let second: boolean = false;
         for (let i: number = 0; i < this.staffLines.length - 1; i++) {
             for (let idx: number = 0, len: number = this.staffLines[i].Measures.length; idx < len; ++idx) {
-                let measure: StaffMeasure = this.staffLines[i].Measures[idx];
+                const measure: StaffMeasure = this.staffLines[i].Measures[idx];
                 for (let idx2: number = 0, len2: number = measure.staffEntries.length; idx2 < len2; ++idx2) {
-                    let staffEntry: GraphicalStaffEntry = measure.staffEntries[idx2];
+                    const staffEntry: GraphicalStaffEntry = measure.staffEntries[idx2];
                     if (staffEntry.sourceStaffEntry.Link !== undefined) {
                         first = true;
                     }
                 }
             }
             for (let idx: number = 0, len: number = this.staffLines[i + 1].Measures.length; idx < len; ++idx) {
-                let measure: StaffMeasure = this.staffLines[i + 1].Measures[idx];
+                const measure: StaffMeasure = this.staffLines[i + 1].Measures[idx];
                 for (let idx2: number = 0, len2: number = measure.staffEntries.length; idx2 < len2; ++idx2) {
-                    let staffEntry: GraphicalStaffEntry = measure.staffEntries[idx2];
+                    const staffEntry: GraphicalStaffEntry = measure.staffEntries[idx2];
                     if (staffEntry.sourceStaffEntry.Link !== undefined) {
                         second = true;
                     }
@@ -362,9 +357,9 @@ export abstract class MusicSystem extends GraphicalObject {
     }
 
     public getBottomStaffLine(topStaffLine: StaffLine): StaffLine {
-        let staves: Staff[] = topStaffLine.ParentStaff.ParentInstrument.Staves;
-        let last: Staff = staves[staves.length - 1];
-        for (let line of topStaffLine.ParentMusicSystem.staffLines) {
+        const staves: Staff[] = topStaffLine.ParentStaff.ParentInstrument.Staves;
+        const last: Staff = staves[staves.length - 1];
+        for (const line of topStaffLine.ParentMusicSystem.staffLines) {
             if (line.ParentStaff === last) {
                 return line;
             }
@@ -403,11 +398,11 @@ export abstract class MusicSystem extends GraphicalObject {
     protected calcBracketsWidth(): number {
         let width: number = 0;
         for (let idx: number = 0, len: number = this.GroupBrackets.length; idx < len; ++idx) {
-            let groupBracket: GraphicalObject = this.GroupBrackets[idx];
+            const groupBracket: GraphicalObject = this.GroupBrackets[idx];
             width = Math.max(width, groupBracket.PositionAndShape.Size.width);
         }
         for (let idx2: number = 0, len2: number = this.InstrumentBrackets.length; idx2 < len2; ++idx2) {
-            let instrumentBracket: GraphicalObject = this.InstrumentBrackets[idx2];
+            const instrumentBracket: GraphicalObject = this.InstrumentBrackets[idx2];
             width = Math.max(width, instrumentBracket.PositionAndShape.Size.width);
         }
         return width;
@@ -423,7 +418,7 @@ export abstract class MusicSystem extends GraphicalObject {
 
     private findFirstVisibleInstrumentInInstrumentalGroup(instrumentalGroup: InstrumentalGroup): Instrument {
         for (let idx: number = 0, len: number = instrumentalGroup.InstrumentalGroups.length; idx < len; ++idx) {
-            let groupOrInstrument: InstrumentalGroup = instrumentalGroup.InstrumentalGroups[idx];
+            const groupOrInstrument: InstrumentalGroup = instrumentalGroup.InstrumentalGroups[idx];
             if (groupOrInstrument instanceof Instrument) {
                 if ((<Instrument>groupOrInstrument).Visible === true) {
                     return <Instrument>groupOrInstrument;
@@ -456,13 +451,13 @@ export abstract class MusicSystem extends GraphicalObject {
      */
     private updateMusicSystemStaffLineXPosition(systemLabelsRightMargin: number): void {
         for (let idx: number = 0, len: number = this.StaffLines.length; idx < len; ++idx) {
-            let staffLine: StaffLine = this.StaffLines[idx];
-            let relative: PointF2D = staffLine.PositionAndShape.RelativePosition;
+            const staffLine: StaffLine = this.StaffLines[idx];
+            const relative: PointF2D = staffLine.PositionAndShape.RelativePosition;
             relative.x = this.maxLabelLength + systemLabelsRightMargin;
             staffLine.PositionAndShape.RelativePosition = relative;
             staffLine.PositionAndShape.BorderRight = this.boundingBox.Size.width - this.maxLabelLength - systemLabelsRightMargin;
             for (let i: number = 0; i < staffLine.StaffLines.length; i++) {
-                let lineEnd: PointF2D = new PointF2D(staffLine.PositionAndShape.Size.width, staffLine.StaffLines[i].End.y);
+                const lineEnd: PointF2D = new PointF2D(staffLine.PositionAndShape.Size.width, staffLine.StaffLines[i].End.y);
                 staffLine.StaffLines[i].End = lineEnd;
             }
         }

+ 100 - 105
src/MusicalScore/Graphical/MusicSystemBuilder.ts

@@ -62,7 +62,7 @@ export class MusicSystemBuilder {
 
     public buildMusicSystems(): void {
         let previousMeasureEndsSystem: boolean = false;
-        let systemMaxWidth: number = this.getFullPageSystemWidth();
+        const systemMaxWidth: number = this.getFullPageSystemWidth();
         this.measureListIndex = 0;
         this.currentSystemParams = new SystemBuildParameters();
 
@@ -85,14 +85,14 @@ export class MusicSystemBuilder {
 
         // go through measures and add to system until system gets too long -> finish system and start next system.
         while (this.measureListIndex < numberOfMeasures) {
-            let staffMeasures: StaffMeasure[] = this.measureList[this.measureListIndex];
+            const staffMeasures: StaffMeasure[] = this.measureList[this.measureListIndex];
             for (let idx: number = 0, len: number = staffMeasures.length; idx < len; ++idx) {
                 staffMeasures[idx].resetLayout();
             }
-            let sourceMeasure: SourceMeasure = staffMeasures[0].parentSourceMeasure;
-            let sourceMeasureEndsSystem: boolean = sourceMeasure.BreakSystemAfter;
-            let isSystemStartMeasure: boolean = this.currentSystemParams.IsSystemStartMeasure();
-            let isFirstSourceMeasure: boolean = sourceMeasure === this.graphicalMusicSheet.ParentMusicSheet.getFirstSourceMeasure();
+            const sourceMeasure: SourceMeasure = staffMeasures[0].parentSourceMeasure;
+            const sourceMeasureEndsSystem: boolean = sourceMeasure.BreakSystemAfter;
+            const isSystemStartMeasure: boolean = this.currentSystemParams.IsSystemStartMeasure();
+            const isFirstSourceMeasure: boolean = sourceMeasure === this.graphicalMusicSheet.ParentMusicSheet.getFirstSourceMeasure();
             let currentMeasureBeginInstructionsWidth: number = this.rules.MeasureLeftMargin;
             let currentMeasureEndInstructionsWidth: number = 0;
 
@@ -101,7 +101,7 @@ export class MusicSystemBuilder {
             // 1. the begin instructions (clef, Key, Rhythm),
             // 2. the staff entries (= notes) and
             // 3. the end instructions (actually only clefs)
-            let measureStartLine: SystemLinesEnum = this.getMeasureStartLine();
+            const measureStartLine: SystemLinesEnum = this.getMeasureStartLine();
             currentMeasureBeginInstructionsWidth += this.getLineWidth(staffMeasures[0], measureStartLine, isSystemStartMeasure);
             if (!this.leadSheet) {
                 currentMeasureBeginInstructionsWidth += this.addBeginInstructions(staffMeasures, isSystemStartMeasure, isFirstSourceMeasure);
@@ -113,20 +113,20 @@ export class MusicSystemBuilder {
             }
 
             // take into account the LineWidth after each Measure
-            let measureEndLine: SystemLinesEnum = this.getMeasureEndLine();
+            const measureEndLine: SystemLinesEnum = this.getMeasureEndLine();
             currentMeasureEndInstructionsWidth += this.getLineWidth(staffMeasures[0], measureEndLine, isSystemStartMeasure);
             let nextMeasureBeginInstructionWidth: number = this.rules.MeasureLeftMargin;
 
             // Check if there are key or rhythm change instructions within the next measure:
             if (this.measureListIndex + 1 < this.measureList.length) {
-                let nextStaffMeasures: StaffMeasure[] = this.measureList[this.measureListIndex + 1];
-                let nextSourceMeasure: SourceMeasure = nextStaffMeasures[0].parentSourceMeasure;
+                const nextStaffMeasures: StaffMeasure[] = this.measureList[this.measureListIndex + 1];
+                const nextSourceMeasure: SourceMeasure = nextStaffMeasures[0].parentSourceMeasure;
                 if (nextSourceMeasure.hasBeginInstructions()) {
                     nextMeasureBeginInstructionWidth += this.addBeginInstructions(nextStaffMeasures, false, false);
                 }
             }
-            let totalMeasureWidth: number = currentMeasureBeginInstructionsWidth + currentMeasureEndInstructionsWidth + currentMeasureVarWidth;
-            let measureFitsInSystem: boolean = this.currentSystemParams.currentWidth + totalMeasureWidth + nextMeasureBeginInstructionWidth < systemMaxWidth;
+            const totalMeasureWidth: number = currentMeasureBeginInstructionsWidth + currentMeasureEndInstructionsWidth + currentMeasureVarWidth;
+            const measureFitsInSystem: boolean = this.currentSystemParams.currentWidth + totalMeasureWidth + nextMeasureBeginInstructionWidth < systemMaxWidth;
             if (isSystemStartMeasure || measureFitsInSystem) {
                 this.addMeasureToSystem(
                     staffMeasures, measureStartLine, measureEndLine, totalMeasureWidth,
@@ -153,7 +153,7 @@ export class MusicSystemBuilder {
      */
     private setMeasureWidth(staffMeasures: StaffMeasure[], width: number, beginInstrWidth: number, endInstrWidth: number): void {
         for (let idx: number = 0, len: number = staffMeasures.length; idx < len; ++idx) {
-            let measure: StaffMeasure = staffMeasures[idx];
+            const measure: StaffMeasure = staffMeasures[idx];
             measure.setWidth(width);
             if (beginInstrWidth > 0) {
                 measure.beginInstructionsWidth = beginInstrWidth;
@@ -203,11 +203,11 @@ export class MusicSystemBuilder {
      * (this should be refactored at some point to not use a combined end/start line but always separated lines)
      */
     private adaptRepetitionLineWithIfNeeded(): void {
-        let systemMeasures: MeasureBuildParameters[] = this.currentSystemParams.systemMeasures;
+        const systemMeasures: MeasureBuildParameters[] = this.currentSystemParams.systemMeasures;
         if (systemMeasures.length >= 1) {
-            let measures: StaffMeasure[] =
+            const measures: StaffMeasure[] =
                 this.currentSystemParams.currentSystem.GraphicalMeasures[this.currentSystemParams.currentSystem.GraphicalMeasures.length - 1];
-            let measureParams: MeasureBuildParameters = systemMeasures[systemMeasures.length - 1];
+            const measureParams: MeasureBuildParameters = systemMeasures[systemMeasures.length - 1];
             let diff: number = 0.0;
             if (measureParams.endLine === SystemLinesEnum.DotsBoldBoldDots) {
                 measureParams.endLine = SystemLinesEnum.DotsThinBold;
@@ -215,7 +215,7 @@ export class MusicSystemBuilder {
             }
             this.currentSystemParams.currentSystemFixWidth -= diff;
             for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
-                let measure: StaffMeasure = measures[idx];
+                const measure: StaffMeasure = measures[idx];
                 measure.endInstructionsWidth -= diff;
             }
         }
@@ -242,7 +242,7 @@ export class MusicSystemBuilder {
      * @returns {GraphicalMusicPage}
      */
     private createMusicPage(): GraphicalMusicPage {
-        let page: GraphicalMusicPage = new GraphicalMusicPage(this.graphicalMusicSheet);
+        const page: GraphicalMusicPage = new GraphicalMusicPage(this.graphicalMusicSheet);
         this.graphicalMusicSheet.MusicPages.push(page);
         page.PositionAndShape.BorderLeft = 0.0;
         page.PositionAndShape.BorderRight = this.graphicalMusicSheet.ParentMusicSheet.pageWidth;
@@ -257,10 +257,8 @@ export class MusicSystemBuilder {
      * @returns {MusicSystem}
      */
     private initMusicSystem(): MusicSystem {
-        let musicSystem: MusicSystem = this.symbolFactory.createMusicSystem(this.currentMusicPage, this.globalSystemIndex++);
+        const musicSystem: MusicSystem = this.symbolFactory.createMusicSystem(this.currentMusicPage, this.globalSystemIndex++);
         this.currentMusicPage.MusicSystems.push(musicSystem);
-        let boundingBox: BoundingBox = musicSystem.PositionAndShape;
-        this.currentMusicPage.PositionAndShape.ChildElements.push(boundingBox);
         return musicSystem;
     }
 
@@ -274,28 +272,28 @@ export class MusicSystemBuilder {
     }
 
     private layoutSystemStaves(): void {
-        let systemWidth: number = this.getFullPageSystemWidth();
-        let musicSystem: MusicSystem = this.currentSystemParams.currentSystem;
-        let boundingBox: BoundingBox = musicSystem.PositionAndShape;
+        const systemWidth: number = this.getFullPageSystemWidth();
+        const musicSystem: MusicSystem = this.currentSystemParams.currentSystem;
+        const boundingBox: BoundingBox = musicSystem.PositionAndShape;
         boundingBox.BorderLeft = 0.0;
         boundingBox.BorderRight = systemWidth;
         boundingBox.BorderTop = 0.0;
-        let staffList: Staff[] = [];
-        let instruments: Instrument[] = this.graphicalMusicSheet.ParentMusicSheet.Instruments;
+        const staffList: Staff[] = [];
+        const instruments: Instrument[] = this.graphicalMusicSheet.ParentMusicSheet.Instruments;
         for (let idx: number = 0, len: number = instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = instruments[idx];
+            const instrument: Instrument = instruments[idx];
             if (instrument.Voices.length === 0 || !instrument.Visible) {
                 continue;
             }
             for (let idx2: number = 0, len2: number = instrument.Staves.length; idx2 < len2; ++idx2) {
-                let staff: Staff = instrument.Staves[idx2];
+                const staff: Staff = instrument.Staves[idx2];
                 staffList.push(staff);
             }
         }
         let multiLyrics: boolean = false;
         if (this.leadSheet) {
             for (let idx: number = 0, len: number = staffList.length; idx < len; ++idx) {
-                let staff: Staff = staffList[idx];
+                const staff: Staff = staffList[idx];
                 if (staff.ParentInstrument.LyricVersesNumbers.length > 1) {
                     multiLyrics = true;
                     break;
@@ -331,11 +329,10 @@ export class MusicSystemBuilder {
      */
     private addStaffLineToMusicSystem(musicSystem: MusicSystem, relativeYPosition: number, staff: Staff): void {
         if (musicSystem !== undefined) {
-            let staffLine: StaffLine = this.symbolFactory.createStaffLine(musicSystem, staff);
+            const staffLine: StaffLine = this.symbolFactory.createStaffLine(musicSystem, staff);
             musicSystem.StaffLines.push(staffLine);
-            let boundingBox: BoundingBox = staffLine.PositionAndShape;
-            musicSystem.PositionAndShape.ChildElements.push(boundingBox);
-            let relativePosition: PointF2D = new PointF2D();
+            const boundingBox: BoundingBox = staffLine.PositionAndShape;
+            const relativePosition: PointF2D = new PointF2D();
             if (musicSystem.Parent.MusicSystems[0] === musicSystem && musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
                 relativePosition.x = this.rules.FirstSystemMargin;
             } else {
@@ -352,10 +349,10 @@ export class MusicSystemBuilder {
             boundingBox.BorderTop = 0.0;
             boundingBox.BorderBottom = this.rules.StaffHeight;
             for (let i: number = 0; i < 5; i++) {
-                let start: PointF2D = new PointF2D();
+                const start: PointF2D = new PointF2D();
                 start.x = 0.0;
                 start.y = i * this.rules.StaffHeight / 4;
-                let end: PointF2D = new PointF2D();
+                const end: PointF2D = new PointF2D();
                 end.x = staffLine.PositionAndShape.Size.width;
                 end.y = i * this.rules.StaffHeight / 4;
                 if (this.leadSheet) {
@@ -371,12 +368,12 @@ export class MusicSystemBuilder {
      * @param measureList
      */
     private initializeActiveInstructions(measureList: StaffMeasure[]): void {
-        let firstSourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.getFirstSourceMeasure();
+        const firstSourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.getFirstSourceMeasure();
         if (firstSourceMeasure !== undefined) {
             this.visibleStaffIndices = this.graphicalMusicSheet.getVisibleStavesIndecesFromSourceMeasure(measureList);
             for (let i: number = 0, len: number = this.visibleStaffIndices.length; i < len; i++) {
-                let staffIndex: number = this.visibleStaffIndices[i];
-                let graphicalMeasure: StaffMeasure = this.graphicalMusicSheet.getGraphicalMeasureFromSourceMeasureAndIndex(firstSourceMeasure, staffIndex);
+                const staffIndex: number = this.visibleStaffIndices[i];
+                const graphicalMeasure: StaffMeasure = this.graphicalMusicSheet.getGraphicalMeasureFromSourceMeasureAndIndex(firstSourceMeasure, staffIndex);
                 this.activeClefs[i] = <ClefInstruction>firstSourceMeasure.FirstInstructionsStaffEntries[staffIndex].Instructions[0];
                 let keyInstruction: KeyInstruction = KeyInstruction.copy(
                     <KeyInstruction>firstSourceMeasure.FirstInstructionsStaffEntries[staffIndex].Instructions[1]);
@@ -408,17 +405,17 @@ export class MusicSystemBuilder {
      * @returns {number}
      */
     private addBeginInstructions(measures: StaffMeasure[], isSystemFirstMeasure: boolean, isFirstSourceMeasure: boolean): number {
-        let measureCount: number = measures.length;
+        const measureCount: number = measures.length;
         if (measureCount === 0) {
             return 0;
         }
         let totalBeginInstructionLengthX: number = 0.0;
-        let sourceMeasure: SourceMeasure = measures[0].parentSourceMeasure;
+        const sourceMeasure: SourceMeasure = measures[0].parentSourceMeasure;
         for (let idx: number = 0; idx < measureCount; ++idx) {
-            let measure: StaffMeasure = measures[idx];
-            let staffIndex: number = this.visibleStaffIndices[idx];
-            let beginInstructionsStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[staffIndex];
-            let beginInstructionLengthX: number = this.AddInstructionsAtMeasureBegin(
+            const measure: StaffMeasure = measures[idx];
+            const staffIndex: number = this.visibleStaffIndices[idx];
+            const beginInstructionsStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[staffIndex];
+            const beginInstructionLengthX: number = this.AddInstructionsAtMeasureBegin(
                 beginInstructionsStaffEntry, measure,
                 idx, isFirstSourceMeasure,
                 isSystemFirstMeasure
@@ -434,17 +431,17 @@ export class MusicSystemBuilder {
      * @returns {number}
      */
     private addEndInstructions(measures: StaffMeasure[]): number {
-        let measureCount: number = measures.length;
+        const measureCount: number = measures.length;
         if (measureCount === 0) {
             return 0;
         }
         let totalEndInstructionLengthX: number = 0.5;
-        let sourceMeasure: SourceMeasure = measures[0].parentSourceMeasure;
+        const sourceMeasure: SourceMeasure = measures[0].parentSourceMeasure;
         for (let idx: number = 0; idx < measureCount; idx++) {
-            let measure: StaffMeasure = measures[idx];
-            let staffIndex: number = this.visibleStaffIndices[idx];
-            let endInstructionsStaffEntry: SourceStaffEntry = sourceMeasure.LastInstructionsStaffEntries[staffIndex];
-            let endInstructionLengthX: number = this.addInstructionsAtMeasureEnd(endInstructionsStaffEntry, measure);
+            const measure: StaffMeasure = measures[idx];
+            const staffIndex: number = this.visibleStaffIndices[idx];
+            const endInstructionsStaffEntry: SourceStaffEntry = sourceMeasure.LastInstructionsStaffEntries[staffIndex];
+            const endInstructionLengthX: number = this.addInstructionsAtMeasureEnd(endInstructionsStaffEntry, measure);
             totalEndInstructionLengthX = Math.max(totalEndInstructionLengthX, endInstructionLengthX);
         }
         return totalEndInstructionLengthX;
@@ -458,7 +455,7 @@ export class MusicSystemBuilder {
         let currentRhythm: RhythmInstruction = undefined;
         if (firstEntry !== undefined) {
             for (let idx: number = 0, len: number = firstEntry.Instructions.length; idx < len; ++idx) {
-                let abstractNotationInstruction: AbstractNotationInstruction = firstEntry.Instructions[idx];
+                const abstractNotationInstruction: AbstractNotationInstruction = firstEntry.Instructions[idx];
                 if (abstractNotationInstruction instanceof ClefInstruction) {
                     currentClef = <ClefInstruction>abstractNotationInstruction;
                 } else if (abstractNotationInstruction instanceof KeyInstruction) {
@@ -490,7 +487,7 @@ export class MusicSystemBuilder {
         }
         if (currentKey !== undefined) {
             currentKey = this.transposeKeyInstruction(currentKey, measure);
-            let previousKey: KeyInstruction = isSystemStartMeasure ? undefined : this.activeKeys[visibleStaffIdx];
+            const previousKey: KeyInstruction = isSystemStartMeasure ? undefined : this.activeKeys[visibleStaffIdx];
             measure.addKeyAtBegin(currentKey, previousKey, currentClef);
             keyAdded = true;
         }
@@ -512,9 +509,9 @@ export class MusicSystemBuilder {
             return 0;
         }
         for (let idx: number = 0, len: number = lastEntry.Instructions.length; idx < len; ++idx) {
-            let abstractNotationInstruction: AbstractNotationInstruction = lastEntry.Instructions[idx];
+            const abstractNotationInstruction: AbstractNotationInstruction = lastEntry.Instructions[idx];
             if (abstractNotationInstruction instanceof ClefInstruction) {
-                let activeClef: ClefInstruction = <ClefInstruction>abstractNotationInstruction;
+                const activeClef: ClefInstruction = <ClefInstruction>abstractNotationInstruction;
                 measure.addClefAtEnd(activeClef);
             }
         }
@@ -530,11 +527,11 @@ export class MusicSystemBuilder {
      */
     private updateActiveClefs(measure: SourceMeasure, staffMeasures: StaffMeasure[]): void {
         for (let visStaffIdx: number = 0, len: number = staffMeasures.length; visStaffIdx < len; visStaffIdx++) {
-            let staffIndex: number = this.visibleStaffIndices[visStaffIdx];
-            let firstEntry: SourceStaffEntry = measure.FirstInstructionsStaffEntries[staffIndex];
+            const staffIndex: number = this.visibleStaffIndices[visStaffIdx];
+            const firstEntry: SourceStaffEntry = measure.FirstInstructionsStaffEntries[staffIndex];
             if (firstEntry !== undefined) {
                 for (let idx: number = 0, len2: number = firstEntry.Instructions.length; idx < len2; ++idx) {
-                    let abstractNotationInstruction: AbstractNotationInstruction = firstEntry.Instructions[idx];
+                    const abstractNotationInstruction: AbstractNotationInstruction = firstEntry.Instructions[idx];
                     if (abstractNotationInstruction instanceof ClefInstruction) {
                         this.activeClefs[visStaffIdx] = <ClefInstruction>abstractNotationInstruction;
                     } else if (abstractNotationInstruction instanceof KeyInstruction) {
@@ -544,23 +541,23 @@ export class MusicSystemBuilder {
                     }
                 }
             }
-            let entries: SourceStaffEntry[] = measure.getEntriesPerStaff(staffIndex);
+            const entries: SourceStaffEntry[] = measure.getEntriesPerStaff(staffIndex);
             for (let idx: number = 0, len2: number = entries.length; idx < len2; ++idx) {
-                let staffEntry: SourceStaffEntry = entries[idx];
+                const staffEntry: SourceStaffEntry = entries[idx];
                 if (staffEntry.Instructions !== undefined) {
                     for (let idx2: number = 0, len3: number = staffEntry.Instructions.length; idx2 < len3; ++idx2) {
-                        let abstractNotationInstruction: AbstractNotationInstruction = staffEntry.Instructions[idx2];
+                        const abstractNotationInstruction: AbstractNotationInstruction = staffEntry.Instructions[idx2];
                         if (abstractNotationInstruction instanceof ClefInstruction) {
                             this.activeClefs[visStaffIdx] = <ClefInstruction>abstractNotationInstruction;
                         }
                     }
                 }
             }
-            let lastEntry: SourceStaffEntry = measure.LastInstructionsStaffEntries[staffIndex];
+            const lastEntry: SourceStaffEntry = measure.LastInstructionsStaffEntries[staffIndex];
             if (lastEntry !== undefined) {
-                let instructions: AbstractNotationInstruction[] = lastEntry.Instructions;
+                const instructions: AbstractNotationInstruction[] = lastEntry.Instructions;
                 for (let idx: number = 0, len3: number = instructions.length; idx < len3; ++idx) {
-                    let abstractNotationInstruction: AbstractNotationInstruction = instructions[idx];
+                    const abstractNotationInstruction: AbstractNotationInstruction = instructions[idx];
                     if (abstractNotationInstruction instanceof ClefInstruction) {
                         this.activeClefs[visStaffIdx] = <ClefInstruction>abstractNotationInstruction;
                     }
@@ -574,23 +571,23 @@ export class MusicSystemBuilder {
      * @param measures
      */
     private checkAndCreateExtraInstructionMeasure(measures: StaffMeasure[]): void {
-        let firstStaffEntries: SourceStaffEntry[] = measures[0].parentSourceMeasure.FirstInstructionsStaffEntries;
-        let visibleInstructionEntries: SourceStaffEntry[] = [];
+        const firstStaffEntries: SourceStaffEntry[] = measures[0].parentSourceMeasure.FirstInstructionsStaffEntries;
+        const visibleInstructionEntries: SourceStaffEntry[] = [];
         for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
-            let measure: StaffMeasure = measures[idx];
+            const measure: StaffMeasure = measures[idx];
             visibleInstructionEntries.push(firstStaffEntries[measure.ParentStaff.idInMusicSheet]);
         }
         let maxMeasureWidth: number = 0;
         for (let visStaffIdx: number = 0, len: number = visibleInstructionEntries.length; visStaffIdx < len; ++visStaffIdx) {
-            let sse: SourceStaffEntry = visibleInstructionEntries[visStaffIdx];
+            const sse: SourceStaffEntry = visibleInstructionEntries[visStaffIdx];
             if (sse === undefined) {
                 continue;
             }
-            let instructions: AbstractNotationInstruction[] = sse.Instructions;
+            const instructions: AbstractNotationInstruction[] = sse.Instructions;
             let keyInstruction: KeyInstruction = undefined;
             let rhythmInstruction: RhythmInstruction = undefined;
             for (let idx2: number = 0, len2: number = instructions.length; idx2 < len2; ++idx2) {
-                let instruction: AbstractNotationInstruction = instructions[idx2];
+                const instruction: AbstractNotationInstruction = instructions[idx2];
                 if (instruction instanceof KeyInstruction && (<KeyInstruction>instruction).Key !== this.activeKeys[visStaffIdx].Key) {
                     keyInstruction = <KeyInstruction>instruction;
                 }
@@ -599,7 +596,7 @@ export class MusicSystemBuilder {
                 }
             }
             if (keyInstruction !== undefined || rhythmInstruction !== undefined) {
-                let measureWidth: number = this.addExtraInstructionMeasure(visStaffIdx, keyInstruction, rhythmInstruction);
+                const measureWidth: number = this.addExtraInstructionMeasure(visStaffIdx, keyInstruction, rhythmInstruction);
                 maxMeasureWidth = Math.max(maxMeasureWidth, measureWidth);
             }
         }
@@ -614,9 +611,9 @@ export class MusicSystemBuilder {
     }
 
     private addExtraInstructionMeasure(visStaffIdx: number, keyInstruction: KeyInstruction, rhythmInstruction: RhythmInstruction): number {
-        let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
-        let measures: StaffMeasure[] = [];
-        let measure: StaffMeasure = this.symbolFactory.createExtraStaffMeasure(currentSystem.StaffLines[visStaffIdx]);
+        const currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
+        const measures: StaffMeasure[] = [];
+        const measure: StaffMeasure = this.symbolFactory.createExtraStaffMeasure(currentSystem.StaffLines[visStaffIdx]);
         measures.push(measure);
         if (keyInstruction !== undefined) {
             measure.addKeyAtBegin(keyInstruction, this.activeKeys[visStaffIdx], this.activeClefs[visStaffIdx]);
@@ -627,11 +624,10 @@ export class MusicSystemBuilder {
         measure.PositionAndShape.BorderLeft = 0.0;
         measure.PositionAndShape.BorderTop = 0.0;
         measure.PositionAndShape.BorderBottom = this.rules.StaffHeight;
-        let width: number = this.rules.MeasureLeftMargin + measure.beginInstructionsWidth + this.rules.MeasureRightMargin;
+        const width: number = this.rules.MeasureLeftMargin + measure.beginInstructionsWidth + this.rules.MeasureRightMargin;
         measure.PositionAndShape.BorderRight = width;
         currentSystem.StaffLines[visStaffIdx].Measures.push(measure);
         measure.ParentStaffLine = currentSystem.StaffLines[visStaffIdx];
-        currentSystem.StaffLines[visStaffIdx].PositionAndShape.ChildElements.push(measure.PositionAndShape);
         return width;
     }
 
@@ -641,16 +637,15 @@ export class MusicSystemBuilder {
      */
     private addStaveMeasuresToSystem(staffMeasures: StaffMeasure[]): void {
         if (staffMeasures[0] !== undefined) {
-            let gmeasures: StaffMeasure[] = [];
+            const gmeasures: StaffMeasure[] = [];
             for (let i: number = 0; i < staffMeasures.length; i++) {
                 gmeasures.push(staffMeasures[i]);
             }
-            let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
+            const currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
             for (let visStaffIdx: number = 0; visStaffIdx < this.numberOfVisibleStaffLines; visStaffIdx++) {
-                let measure: StaffMeasure = gmeasures[visStaffIdx];
+                const measure: StaffMeasure = gmeasures[visStaffIdx];
                 currentSystem.StaffLines[visStaffIdx].Measures.push(measure);
                 measure.ParentStaffLine = currentSystem.StaffLines[visStaffIdx];
-                currentSystem.StaffLines[visStaffIdx].PositionAndShape.ChildElements.push(measure.PositionAndShape);
             }
             currentSystem.AddStaffMeasures(gmeasures);
         }
@@ -661,10 +656,10 @@ export class MusicSystemBuilder {
      * @returns {SystemLinesEnum}
      */
     private getMeasureStartLine(): SystemLinesEnum {
-        let thisMeasureBeginsLineRep: boolean = this.thisMeasureBeginsLineRepetition();
+        const thisMeasureBeginsLineRep: boolean = this.thisMeasureBeginsLineRepetition();
         if (thisMeasureBeginsLineRep) {
-            let isSystemStartMeasure: boolean = this.currentSystemParams.IsSystemStartMeasure();
-            let isGlobalFirstMeasure: boolean = this.measureListIndex === 0;
+            const isSystemStartMeasure: boolean = this.currentSystemParams.IsSystemStartMeasure();
+            const isGlobalFirstMeasure: boolean = this.measureListIndex === 0;
             if (this.previousMeasureEndsLineRepetition() && !isSystemStartMeasure) {
                 return SystemLinesEnum.DotsBoldBoldDots;
             }
@@ -714,7 +709,7 @@ export class MusicSystemBuilder {
             return false;
         }
         for (let idx: number = 0, len: number = this.measureList[this.measureListIndex - 1].length; idx < len; ++idx) {
-            let measure: StaffMeasure = this.measureList[this.measureListIndex - 1][idx];
+            const measure: StaffMeasure = this.measureList[this.measureListIndex - 1][idx];
             if (measure.endsWithLineRepetition()) {
                 return true;
             }
@@ -728,7 +723,7 @@ export class MusicSystemBuilder {
      */
     private thisMeasureBeginsLineRepetition(): boolean {
         for (let idx: number = 0, len: number = this.measureList[this.measureListIndex].length; idx < len; ++idx) {
-            let measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
+            const measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
             if (measure.beginsWithLineRepetition()) {
                 return true;
             }
@@ -741,12 +736,12 @@ export class MusicSystemBuilder {
      * @returns {boolean}
      */
     private nextMeasureBeginsLineRepetition(): boolean {
-        let nextMeasureIndex: number = this.measureListIndex + 1;
+        const nextMeasureIndex: number = this.measureListIndex + 1;
         if (nextMeasureIndex >= this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length) {
             return false;
         }
         for (let idx: number = 0, len: number = this.measureList[nextMeasureIndex].length; idx < len; ++idx) {
-            let measure: StaffMeasure = this.measureList[nextMeasureIndex][idx];
+            const measure: StaffMeasure = this.measureList[nextMeasureIndex][idx];
             if (measure.beginsWithLineRepetition()) {
                 return true;
             }
@@ -760,7 +755,7 @@ export class MusicSystemBuilder {
      */
     private thisMeasureEndsLineRepetition(): boolean {
         for (let idx: number = 0, len: number = this.measureList[this.measureListIndex].length; idx < len; ++idx) {
-            let measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
+            const measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
             if (measure.endsWithLineRepetition()) {
                 return true;
             }
@@ -773,12 +768,12 @@ export class MusicSystemBuilder {
      * @returns {boolean}
      */
     private nextMeasureBeginsWordRepetition(): boolean {
-        let nextMeasureIndex: number = this.measureListIndex + 1;
+        const nextMeasureIndex: number = this.measureListIndex + 1;
         if (nextMeasureIndex >= this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length) {
             return false;
         }
         for (let idx: number = 0, len: number = this.measureList[nextMeasureIndex].length; idx < len; ++idx) {
-            let measure: StaffMeasure = this.measureList[nextMeasureIndex][idx];
+            const measure: StaffMeasure = this.measureList[nextMeasureIndex][idx];
             if (measure.beginsWithWordRepetition()) {
                 return true;
             }
@@ -792,7 +787,7 @@ export class MusicSystemBuilder {
      */
     private thisMeasureEndsWordRepetition(): boolean {
         for (let idx: number = 0, len: number = this.measureList[this.measureListIndex].length; idx < len; ++idx) {
-            let measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
+            const measure: StaffMeasure = this.measureList[this.measureListIndex][idx];
             if (measure.endsWithWordRepetition()) {
                 return true;
             }
@@ -811,7 +806,7 @@ export class MusicSystemBuilder {
     private getNextMeasureKeyInstruction(): KeyInstruction {
         if (this.measureListIndex < this.measureList.length - 1) {
             for (let visIndex: number = 0; visIndex < this.measureList[this.measureListIndex].length; visIndex++) {
-                let sourceMeasure: SourceMeasure = this.measureList[this.measureListIndex + 1][visIndex].parentSourceMeasure;
+                const sourceMeasure: SourceMeasure = this.measureList[this.measureListIndex + 1][visIndex].parentSourceMeasure;
                 if (sourceMeasure === undefined) {
                     return undefined;
                 }
@@ -832,9 +827,9 @@ export class MusicSystemBuilder {
             return 1.0;
         }
         let systemEndX: number;
-        let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
+        const currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
         systemEndX = currentSystem.StaffLines[0].PositionAndShape.Size.width;
-        let scalingFactor: number = (systemEndX - systemFixWidth) / systemVarWidth;
+        const scalingFactor: number = (systemEndX - systemFixWidth) / systemVarWidth;
         return scalingFactor;
     }
 
@@ -849,17 +844,17 @@ export class MusicSystemBuilder {
         if (isPartEndingSystem) {
             scalingFactor = Math.min(scalingFactor, this.rules.LastSystemMaxScalingFactor);
         }
-        let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
+        const currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
         for (let visStaffIdx: number = 0, len: number = currentSystem.StaffLines.length; visStaffIdx < len; ++visStaffIdx) {
-            let staffLine: StaffLine = currentSystem.StaffLines[visStaffIdx];
+            const staffLine: StaffLine = currentSystem.StaffLines[visStaffIdx];
             let currentXPosition: number = 0.0;
             for (let measureIndex: number = 0; measureIndex < staffLine.Measures.length; measureIndex++) {
-                let measure: StaffMeasure = staffLine.Measures[measureIndex];
+                const measure: StaffMeasure = staffLine.Measures[measureIndex];
                 measure.setPositionInStaffline(currentXPosition);
                 measure.setWidth(measure.beginInstructionsWidth + measure.minimumStaffEntriesWidth * scalingFactor + measure.endInstructionsWidth);
                 if (measureIndex < this.currentSystemParams.systemMeasures.length) {
-                    let startLine: SystemLinesEnum = this.currentSystemParams.systemMeasures[measureIndex].beginLine;
-                    let lineWidth: number = measure.getLineWidth(SystemLinesEnum.BoldThinDots);
+                    const startLine: SystemLinesEnum = this.currentSystemParams.systemMeasures[measureIndex].beginLine;
+                    const lineWidth: number = measure.getLineWidth(SystemLinesEnum.BoldThinDots);
                     switch (startLine) {
                         case SystemLinesEnum.BoldThinDots:
                             let xPosition: number = currentXPosition;
@@ -874,14 +869,14 @@ export class MusicSystemBuilder {
                 }
                 measure.staffEntriesScaleFactor = scalingFactor;
                 measure.layoutSymbols();
-                let nextMeasureHasRepStartLine: boolean = measureIndex + 1 < this.currentSystemParams.systemMeasures.length
+                const nextMeasureHasRepStartLine: boolean = measureIndex + 1 < this.currentSystemParams.systemMeasures.length
                     && this.currentSystemParams.systemMeasures[measureIndex + 1].beginLine === SystemLinesEnum.BoldThinDots;
                 if (!nextMeasureHasRepStartLine) {
                     let endLine: SystemLinesEnum = SystemLinesEnum.SingleThin;
                     if (measureIndex < this.currentSystemParams.systemMeasures.length) {
                         endLine = this.currentSystemParams.systemMeasures[measureIndex].endLine;
                     }
-                    let lineWidth: number = measure.getLineWidth(endLine);
+                    const lineWidth: number = measure.getLineWidth(endLine);
                     let xPos: number = measure.PositionAndShape.RelativePosition.x + measure.PositionAndShape.BorderRight - lineWidth;
                     if (endLine === SystemLinesEnum.DotsBoldBoldDots) {
                         xPos -= lineWidth / 2;
@@ -901,14 +896,14 @@ export class MusicSystemBuilder {
      * the [[StaffLine]]'s Width and the 5 [[StaffLine]]s length.
      */
     private decreaseMusicSystemBorders(): void {
-        let currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
-        let bb: BoundingBox = CollectionUtil.last(currentSystem.StaffLines[0].Measures).PositionAndShape;
-        let width: number = bb.RelativePosition.x + bb.Size.width;
+        const currentSystem: MusicSystem = this.currentSystemParams.currentSystem;
+        const bb: BoundingBox = CollectionUtil.last(currentSystem.StaffLines[0].Measures).PositionAndShape;
+        const width: number = bb.RelativePosition.x + bb.Size.width;
         for (let idx: number = 0, len: number = currentSystem.StaffLines.length; idx < len; ++idx) {
-            let staffLine: StaffLine = currentSystem.StaffLines[idx];
+            const staffLine: StaffLine = currentSystem.StaffLines[idx];
             staffLine.PositionAndShape.BorderRight = width;
             for (let idx2: number = 0, len2: number = staffLine.StaffLines.length; idx2 < len2; ++idx2) {
-                let graphicalLine: GraphicalLine = staffLine.StaffLines[idx2];
+                const graphicalLine: GraphicalLine = staffLine.StaffLines[idx2];
                 graphicalLine.End = new PointF2D(width, graphicalLine.End.y);
             }
         }

+ 10 - 10
src/MusicalScore/Graphical/SelectionEndSymbol.ts

@@ -11,10 +11,10 @@ export class SelectionEndSymbol extends GraphicalObject {
 
     constructor(system: MusicSystem, xPosition: number) {
         super();
-        let xCoordinate: number = xPosition;
-        let yCoordinate: number = system.PositionAndShape.AbsolutePosition.y;
-        let lineThickness: number = 0.4;
-        let height: number = CollectionUtil.last(system.StaffLines).PositionAndShape.RelativePosition.y + 4;
+        const xCoordinate: number = xPosition;
+        const yCoordinate: number = system.PositionAndShape.AbsolutePosition.y;
+        const lineThickness: number = 0.4;
+        const height: number = CollectionUtil.last(system.StaffLines).PositionAndShape.RelativePosition.y + 4;
         this.verticalLine = new GraphicalLine(
             new PointF2D(xCoordinate, yCoordinate),
             new PointF2D(xCoordinate, yCoordinate + height),
@@ -22,9 +22,9 @@ export class SelectionEndSymbol extends GraphicalObject {
             OutlineAndFillStyleEnum.SelectionSymbol
         );
         for (let idx: number = 0, len: number = system.StaffLines.length; idx < len; ++idx) {
-            let staffLine: StaffLine = system.StaffLines[idx];
-            let anchor: PointF2D = new PointF2D(xCoordinate, yCoordinate + staffLine.PositionAndShape.RelativePosition.y);
-            let arrowPoints: PointF2D[] = new Array(3);
+            const staffLine: StaffLine = system.StaffLines[idx];
+            const anchor: PointF2D = new PointF2D(xCoordinate, yCoordinate + staffLine.PositionAndShape.RelativePosition.y);
+            const arrowPoints: PointF2D[] = new Array(3);
             anchor.y -= .2;
             arrowPoints[0].x = anchor.x - 3;
             arrowPoints[0].y = anchor.y + 1.2;
@@ -33,11 +33,11 @@ export class SelectionEndSymbol extends GraphicalObject {
             arrowPoints[2].x = anchor.x - 2;
             arrowPoints[2].y = anchor.y + 2;
             this.arrows.push(arrowPoints);
-            let linePoints: PointF2D[] = new Array(8);
-            let arrowThickness: number = .8;
+            const linePoints: PointF2D[] = new Array(8);
+            const arrowThickness: number = .8;
             anchor.x -= .1;
             anchor.y += .3;
-            let hilfsVar: number = .2;
+            const hilfsVar: number = .2;
             linePoints[0].x = anchor.x - 2;
             linePoints[0].y = anchor.y + 1.5 - hilfsVar;
             linePoints[1].x = anchor.x - 1;

+ 7 - 7
src/MusicalScore/Graphical/SelectionStartSymbol.ts

@@ -11,10 +11,10 @@ export class SelectionStartSymbol extends GraphicalObject {
 
     constructor(system: MusicSystem, xPosition: number) {
         super();
-        let xCoordinate: number = xPosition;
-        let yCoordinate: number = system.PositionAndShape.AbsolutePosition.y;
-        let lineThickness: number = 0.4;
-        let height: number = CollectionUtil.last(system.StaffLines).PositionAndShape.RelativePosition.y + 4;
+        const xCoordinate: number = xPosition;
+        const yCoordinate: number = system.PositionAndShape.AbsolutePosition.y;
+        const lineThickness: number = 0.4;
+        const height: number = CollectionUtil.last(system.StaffLines).PositionAndShape.RelativePosition.y + 4;
         this.verticalLine = new GraphicalLine(
             new PointF2D(xCoordinate, yCoordinate),
             new PointF2D(xCoordinate, yCoordinate + height),
@@ -22,9 +22,9 @@ export class SelectionStartSymbol extends GraphicalObject {
             OutlineAndFillStyleEnum.SelectionSymbol
         );
         for (let idx: number = 0, len: number = system.StaffLines.length; idx < len; ++idx) {
-            let staffLine: StaffLine = system.StaffLines[idx];
-            let anchor: PointF2D = new PointF2D(xCoordinate, yCoordinate + staffLine.PositionAndShape.RelativePosition.y);
-            let arrowPoints: PointF2D[] = new Array(7);
+            const staffLine: StaffLine = system.StaffLines[idx];
+            const anchor: PointF2D = new PointF2D(xCoordinate, yCoordinate + staffLine.PositionAndShape.RelativePosition.y);
+            const arrowPoints: PointF2D[] = new Array(7);
             arrowPoints[0].x = anchor.x + 4;
             arrowPoints[0].y = anchor.y + 2;
             arrowPoints[1].x = anchor.x + 2.5;

+ 6 - 10
src/MusicalScore/Graphical/StaffLine.ts

@@ -77,11 +77,11 @@ export abstract class StaffLine extends GraphicalObject {
     }
 
     public addActivitySymbolClickArea(): void {
-        let activitySymbol: StaffLineActivitySymbol = new StaffLineActivitySymbol(this);
-        let staffLinePsi: BoundingBox = this.PositionAndShape;
+        const activitySymbol: StaffLineActivitySymbol = new StaffLineActivitySymbol(this);
+        const staffLinePsi: BoundingBox = this.PositionAndShape;
         activitySymbol.PositionAndShape.RelativePosition =
             new PointF2D(staffLinePsi.RelativePosition.x + staffLinePsi.BorderRight + 0.5, staffLinePsi.RelativePosition.y + 0.5);
-        this.parentMusicSystem.PositionAndShape.ChildElements.push(activitySymbol.PositionAndShape);
+        activitySymbol.PositionAndShape.Parent = this.parentMusicSystem.PositionAndShape;
     }
 
     /**
@@ -89,7 +89,7 @@ export abstract class StaffLine extends GraphicalObject {
      * @returns {boolean}
      */
     public isPartOfMultiStaffInstrument(): boolean {
-        let instrument: Instrument = this.parentStaff.ParentInstrument;
+        const instrument: Instrument = this.parentStaff.ParentInstrument;
         if (instrument.Staves.length > 1) {
             return true;
         }
@@ -103,17 +103,13 @@ export abstract class StaffLine extends GraphicalObject {
      */
     public findClosestStaffEntry(xPosition: number): GraphicalStaffEntry {
         let closestStaffentry: GraphicalStaffEntry = undefined;
-        let difference: number = Number.MAX_VALUE;
         for (let idx: number = 0, len: number = this.Measures.length; idx < len; ++idx) {
-            let graphicalMeasure: StaffMeasure = this.Measures[idx];
+            const graphicalMeasure: StaffMeasure = this.Measures[idx];
             for (let idx2: number = 0, len2: number = graphicalMeasure.staffEntries.length; idx2 < len2; ++idx2) {
-                let graphicalStaffEntry: GraphicalStaffEntry = graphicalMeasure.staffEntries[idx2];
+                const graphicalStaffEntry: GraphicalStaffEntry = graphicalMeasure.staffEntries[idx2];
                 if (
                     Math.abs(graphicalStaffEntry.PositionAndShape.RelativePosition.x - xPosition + graphicalMeasure.PositionAndShape.RelativePosition.x) < 5.0
                 ) {
-                    difference = Math.abs(
-                        graphicalStaffEntry.PositionAndShape.RelativePosition.x - xPosition + graphicalMeasure.PositionAndShape.RelativePosition.x
-                    );
                     closestStaffentry = graphicalStaffEntry;
                 }
             }

+ 1 - 1
src/MusicalScore/Graphical/StaffLineActivitySymbol.ts

@@ -7,7 +7,7 @@ export class StaffLineActivitySymbol extends GraphicalObject {
     constructor(staffLine: StaffLine) {
         super();
         this.parentStaffLine = staffLine;
-        let staffLinePsi: BoundingBox = staffLine.PositionAndShape;
+        const staffLinePsi: BoundingBox = staffLine.PositionAndShape;
         this.boundingBox = new BoundingBox(this, staffLinePsi);
         this.boundingBox.BorderRight = 6;
         this.boundingBox.BorderBottom = 4.5;

+ 18 - 20
src/MusicalScore/Graphical/StaffMeasure.ts

@@ -182,7 +182,7 @@ export abstract class StaffMeasure extends GraphicalObject {
 
     public findGraphicalStaffEntryFromTimestamp(relativeTimestamp: Fraction): GraphicalStaffEntry {
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
             if (graphicalStaffEntry.relInMeasureTimestamp.Equals(relativeTimestamp)) {
                 return graphicalStaffEntry;
             }
@@ -197,7 +197,7 @@ export abstract class StaffMeasure extends GraphicalObject {
      */
     public findGraphicalStaffEntryFromVerticalContainerTimestamp(absoluteTimestamp: Fraction): GraphicalStaffEntry {
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
             if (graphicalStaffEntry.sourceStaffEntry.VerticalContainerParent.getAbsoluteTimestamp().Equals(absoluteTimestamp)) {
                 return graphicalStaffEntry;
             }
@@ -210,9 +210,9 @@ export abstract class StaffMeasure extends GraphicalObject {
      * @returns {boolean}
      */
     public hasSameDurationWithSourceMeasureParent(): boolean {
-        let duration: Fraction = new Fraction(0, 1);
+        const duration: Fraction = new Fraction(0, 1);
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
             duration.Add(graphicalStaffEntry.findStaffEntryMinNoteLength());
         }
         return duration.Equals(this.parentSourceMeasure.Duration);
@@ -226,11 +226,11 @@ export abstract class StaffMeasure extends GraphicalObject {
         if (this.staffEntries.length === 0) {
             return false;
         }
-        let voices: Voice[] = [];
+        const voices: Voice[] = [];
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let staffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            const staffEntry: GraphicalStaffEntry = this.staffEntries[idx];
             for (let idx2: number = 0, len2: number = staffEntry.sourceStaffEntry.VoiceEntries.length; idx2 < len2; ++idx2) {
-                let voiceEntry: VoiceEntry = staffEntry.sourceStaffEntry.VoiceEntries[idx2];
+                const voiceEntry: VoiceEntry = staffEntry.sourceStaffEntry.VoiceEntries[idx2];
                 if (voices.indexOf(voiceEntry.ParentVoice) < 0) {
                     voices.push(voiceEntry.ParentVoice);
                 }
@@ -248,23 +248,23 @@ export abstract class StaffMeasure extends GraphicalObject {
 
     public getGraphicalMeasureDurationFromStaffEntries(): Fraction {
         let duration: Fraction = new Fraction(0, 1);
-        let voices: Voice[] = [];
+        const voices: Voice[] = [];
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
             for (let idx2: number = 0, len2: number = graphicalStaffEntry.sourceStaffEntry.VoiceEntries.length; idx2 < len2; ++idx2) {
-                let voiceEntry: VoiceEntry = graphicalStaffEntry.sourceStaffEntry.VoiceEntries[idx2];
+                const voiceEntry: VoiceEntry = graphicalStaffEntry.sourceStaffEntry.VoiceEntries[idx2];
                 if (voices.indexOf(voiceEntry.ParentVoice) < 0) {
                     voices.push(voiceEntry.ParentVoice);
                 }
             }
         }
         for (let idx: number = 0, len: number = voices.length; idx < len; ++idx) {
-            let voice: Voice = voices[idx];
-            let voiceDuration: Fraction = new Fraction(0, 1);
+            const voice: Voice = voices[idx];
+            const voiceDuration: Fraction = new Fraction(0, 1);
             for (let idx2: number = 0, len2: number = this.staffEntries.length; idx2 < len2; ++idx2) {
-                let graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx2];
+                const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx2];
                 for (let idx3: number = 0, len3: number = graphicalStaffEntry.notes.length; idx3 < len3; ++idx3) {
-                    let graphicalNotes: GraphicalNote[] = graphicalStaffEntry.notes[idx3];
+                    const graphicalNotes: GraphicalNote[] = graphicalStaffEntry.notes[idx3];
                     if (graphicalNotes.length > 0 && graphicalNotes[0].sourceNote.ParentVoiceEntry.ParentVoice === voice) {
                         voiceDuration.Add(graphicalNotes[0].graphicalNoteLength);
                     }
@@ -279,7 +279,6 @@ export abstract class StaffMeasure extends GraphicalObject {
 
     public addGraphicalStaffEntry(graphicalStaffEntry: GraphicalStaffEntry): void {
         this.staffEntries.push(graphicalStaffEntry);
-        this.PositionAndShape.ChildElements.push(graphicalStaffEntry.PositionAndShape);
     }
 
     /**
@@ -301,12 +300,11 @@ export abstract class StaffMeasure extends GraphicalObject {
                     }
                 }
             }
-            this.PositionAndShape.ChildElements.push(staffEntry.PositionAndShape);
         }
     }
 
     public beginsWithLineRepetition(): boolean {
-        let sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
         if (sourceMeasure === undefined) {
             return false;
         }
@@ -318,7 +316,7 @@ export abstract class StaffMeasure extends GraphicalObject {
      * @returns {boolean}
      */
     public endsWithLineRepetition(): boolean {
-        let sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
         if (sourceMeasure === undefined) {
             return false;
         }
@@ -330,7 +328,7 @@ export abstract class StaffMeasure extends GraphicalObject {
      * @returns {boolean}
      */
     public beginsWithWordRepetition(): boolean {
-        let sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
         if (sourceMeasure === undefined) {
             return false;
         }
@@ -341,7 +339,7 @@ export abstract class StaffMeasure extends GraphicalObject {
      * Check if this Measure is a Repetition Ending.
      */
     public endsWithWordRepetition(): boolean {
-        let sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
         if (sourceMeasure === undefined) {
             return false;
         }

+ 3 - 3
src/MusicalScore/Graphical/VerticalGraphicalStaffEntryContainer.ts

@@ -38,8 +38,8 @@ export class VerticalGraphicalStaffEntryContainer {
     }
 
     public static compareByTimestamp(x: VerticalGraphicalStaffEntryContainer, y: VerticalGraphicalStaffEntryContainer): number {
-        let xValue: number = x.absoluteTimestamp.RealValue;
-        let yValue: number = y.absoluteTimestamp.RealValue;
+        const xValue: number = x.absoluteTimestamp.RealValue;
+        const yValue: number = y.absoluteTimestamp.RealValue;
 
         if (xValue < yValue) {
             return -1;
@@ -56,7 +56,7 @@ export class VerticalGraphicalStaffEntryContainer {
      */
     public getFirstNonNullStaffEntry(): GraphicalStaffEntry {
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
             if (graphicalStaffEntry !== undefined) {
                 return graphicalStaffEntry;
             }

+ 66 - 0
src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts

@@ -0,0 +1,66 @@
+import Vex = require("vexflow");
+
+import {VexFlowBackend} from "./VexFlowBackend";
+import {FontStyles} from "../../../Common/Enums/FontStyles";
+import {Fonts} from "../../../Common/Enums/Fonts";
+import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D";
+import {PointF2D} from "../../../Common/DataObjects/PointF2D";
+import {VexFlowConverter} from "./VexFlowConverter";
+
+export class CanvasVexFlowBackend extends VexFlowBackend {
+
+    public getBackendType(): number {
+        return Vex.Flow.Renderer.Backends.CANVAS;
+    }
+
+    public initialize(container: HTMLElement): void {
+        this.canvas = document.createElement("canvas");
+        this.inner = document.createElement("div");
+        this.inner.style.position = "relative";
+        this.canvas.style.zIndex = "0";
+        this.inner.appendChild(this.canvas);
+        container.appendChild(this.inner);
+        this.renderer = new Vex.Flow.Renderer(this.canvas, this.getBackendType());
+        this.ctx = <Vex.Flow.CanvasContext>this.renderer.getContext();
+        this.canvasRenderingCtx = this.ctx.vexFlowCanvasContext;
+
+    }
+
+    public getContext(): Vex.Flow.CanvasContext {
+        return this.ctx;
+    }
+
+    public clear(): void {
+        // Doesn't need to do anything
+    }
+
+    public scale(k: number): void {
+        this.ctx.scale(k, k);
+    }
+
+    public translate(x: number, y: number): void {
+        this.canvasRenderingCtx.translate(x, y);
+    }
+    public renderText(fontHeight: number, fontStyle: FontStyles, font: Fonts, text: string,
+                      heightInPixel: number, screenPosition: PointF2D): void  {
+        const old: string = this.canvasRenderingCtx.font;
+        this.canvasRenderingCtx.font = VexFlowConverter.font(
+            fontHeight,
+            fontStyle,
+            font
+        );
+        this.canvasRenderingCtx.fillText(text, screenPosition.x, screenPosition.y + heightInPixel);
+        this.canvasRenderingCtx.font = old;
+    }
+    public renderRectangle(rectangle: RectangleF2D, styleId: number, alpha: number = 1): void {
+        const old: string | CanvasGradient | CanvasPattern = this.canvasRenderingCtx.fillStyle;
+        this.canvasRenderingCtx.fillStyle = VexFlowConverter.style(styleId);
+        this.canvasRenderingCtx.globalAlpha = alpha;
+        this.ctx.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+        this.canvasRenderingCtx.fillStyle = old;
+        this.canvasRenderingCtx.globalAlpha = 1;
+    }
+
+    private ctx: Vex.Flow.CanvasContext;
+    private canvasRenderingCtx: CanvasRenderingContext2D;
+}

+ 71 - 0
src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts

@@ -0,0 +1,71 @@
+import Vex = require("vexflow");
+
+import {VexFlowBackend} from "./VexFlowBackend";
+import {VexFlowConverter} from "./VexFlowConverter";
+import {FontStyles} from "../../../Common/Enums/FontStyles";
+import {Fonts} from "../../../Common/Enums/Fonts";
+import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D";
+import {PointF2D} from "../../../Common/DataObjects/PointF2D";
+
+export class SvgVexFlowBackend extends VexFlowBackend {
+
+    public getBackendType(): number {
+        return Vex.Flow.Renderer.Backends.SVG;
+    }
+
+    public initialize(container: HTMLElement): void {
+        this.canvas = document.createElement("div");
+        this.inner = this.canvas;
+        this.inner.style.position = "relative";
+        this.canvas.style.zIndex = "0";
+        container.appendChild(this.inner);
+        this.renderer = new Vex.Flow.Renderer(this.canvas, this.getBackendType());
+        this.ctx = <Vex.Flow.SVGContext>this.renderer.getContext();
+
+    }
+
+    public getContext(): Vex.Flow.SVGContext {
+        return this.ctx;
+    }
+
+    public clear(): void {
+        const { svg } = this.ctx;
+        if (!svg) {
+            return;
+        }
+        // removes all children from the SVG element,
+        // effectively clearing the SVG viewport
+        while (svg.lastChild) {
+            svg.removeChild(svg.lastChild);
+        }
+    }
+
+    public scale(k: number): void {
+        this.ctx.scale(k, k);
+    }
+
+    public translate(x: number, y: number): void {
+        // TODO: implement this
+    }
+    public renderText(fontHeight: number, fontStyle: FontStyles, font: Fonts, text: string,
+                      heightInPixel: number, screenPosition: PointF2D): void {
+        this.ctx.save();
+
+        this.ctx.setFont("Times New Roman", fontHeight, VexFlowConverter.fontStyle(fontStyle));
+        // font size is set by VexFlow in `pt`. This overwrites the font so it's set to px instead
+        this.ctx.attributes["font-size"] = `${fontHeight}px`;
+        this.ctx.state["font-size"] = `${fontHeight}px`;
+        this.ctx.fillText(text, screenPosition.x, screenPosition.y + heightInPixel);
+        this.ctx.restore();
+    }
+    public renderRectangle(rectangle: RectangleF2D, styleId: number, alpha: number = 1): void {
+        this.ctx.save();
+        this.ctx.attributes.fill = VexFlowConverter.style(styleId);
+        this.ctx.attributes["fill-opacity"] = alpha;
+        this.ctx.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+        this.ctx.restore();
+        this.ctx.attributes["fill-opacity"] = 1;
+    }
+
+    private ctx: Vex.Flow.SVGContext;
+}

+ 62 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowBackend.ts

@@ -0,0 +1,62 @@
+import * as Vex from "vexflow";
+import {FontStyles} from "../../../Common/Enums/FontStyles";
+import {Fonts} from "../../../Common/Enums/Fonts";
+import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D";
+import {PointF2D} from "../../../Common/DataObjects/PointF2D";
+
+export class VexFlowBackends {
+  public static CANVAS: 0;
+  public static RAPHAEL: 1;
+  public static SVG: 2;
+  public static VML: 3;
+
+}
+
+export abstract class VexFlowBackend {
+
+  public abstract initialize(container: HTMLElement): void;
+
+  public getInnerElement(): HTMLElement {
+    return this.inner;
+  }
+
+  public getCanvas(): HTMLElement {
+    return this.canvas;
+  }
+
+  public getRenderer(): Vex.Flow.Renderer {
+    return this.renderer;
+  }
+
+  public abstract getContext(): Vex.Flow.RenderContext;
+
+  // public abstract setWidth(width: number): void;
+  // public abstract setHeight(height: number): void;
+
+  public abstract scale(k: number): void;
+
+  public resize(x: number, y: number): void {
+    this.renderer.resize(x, y);
+  }
+
+  public abstract clear(): void;
+
+  public abstract translate(x: number, y: number): void;
+  public abstract renderText(fontHeight: number, fontStyle: FontStyles, font: Fonts, text: string,
+                             heightInPixel: number, screenPosition: PointF2D): void;
+  /**
+   * Renders a rectangle with the given style to the screen.
+   * It is given in screen coordinates.
+   * @param rectangle the rect in screen coordinates
+   * @param layer is the current rendering layer. There are many layers on top of each other to which can be rendered. Not needed for now.
+   * @param styleId the style id
+   * @param alpha alpha value between 0 and 1
+   */
+  public abstract renderRectangle(rectangle: RectangleF2D, styleId: number, alpha: number): void;
+
+  public abstract getBackendType(): number;
+
+  protected renderer: Vex.Flow.Renderer;
+  protected inner: HTMLElement;
+  protected canvas: HTMLElement;
+}

+ 164 - 56
src/MusicalScore/Graphical/VexFlow/VexFlowConverter.ts

@@ -14,7 +14,8 @@ import {GraphicalNote} from "../GraphicalNote";
 import {SystemLinesEnum} from "../SystemLinesEnum";
 import {FontStyles} from "../../../Common/Enums/FontStyles";
 import {Fonts} from "../../../Common/Enums/Fonts";
-import {OutlineAndFillStyleEnum} from "../DrawingEnums";
+import {OutlineAndFillStyleEnum, OUTLINE_AND_FILL_STYLE_DICT} from "../DrawingEnums";
+import {Logging} from "../../../Common/Logging";
 
 /**
  * Helper class, which contains static methods which actually convert
@@ -26,16 +27,16 @@ export class VexFlowConverter {
      * @type {[alterationsNo: number]: string; }
      */
     private static majorMap: {[_: number]: string; } = {
-        "0": "C", 1: "G", 2: "D", 3: "A", 4: "E", 5: "B", 6: "F#", 7: "C#",
-        8: "G#", "-1": "F", "-8": "Fb", "-7": "Cb", "-6": "Gb", "-5": "Db", "-4": "Ab", "-3": "Eb", "-2": "Bb",
+        "-1": "F", "-2": "Bb", "-3": "Eb", "-4": "Ab", "-5": "Db", "-6": "Gb", "-7": "Cb", "-8": "Fb",
+        "0": "C", "1": "G", "2": "D", "3": "A", "4": "E", "5": "B", "6": "F#", "7": "C#", "8": "G#"
     };
     /**
      * Mapping from numbers of alterations on the key signature to minor keys
      * @type {[alterationsNo: number]: string; }
      */
     private static minorMap: {[_: number]: string; } = {
-        "1": "E", "7": "A#", "0": "A", "6": "D#", "3": "F#", "-5": "Bb", "-4": "F", "-7": "Ab", "-6": "Eb",
-        "-1": "D", "4": "C#", "-3": "C", "-2": "G", "2": "B", "5": "G#", "-8": "Db", "8": "E#",
+        "-1": "D", "-2": "G", "-3": "C", "-4": "F", "-5": "Bb", "-6": "Eb", "-7": "Ab", "-8": "Db",
+        "0": "A", "1": "E", "2": "B", "3": "F#", "4": "C#", "5": "G#", "6": "D#", "7": "A#", "8": "E#"
     };
 
     /**
@@ -43,22 +44,53 @@ export class VexFlowConverter {
      * @param fraction a fraction representing the duration of a note
      * @returns {string}
      */
-    public static duration(fraction: Fraction): string {
-        let dur: number = fraction.RealValue;
-        if (dur >= 1) {
-            return "w";
-        } else if (dur < 1 && dur >= 0.5) {
-            return "h";
-        } else if (dur < 0.5 && dur >= 0.25) {
-            return "q";
-        } else if (dur < 0.25 && dur >= 0.125) {
-            return "8";
-        } else if (dur < 0.125 && dur >= 0.0625) {
-            return "16";
-        } else if (dur < 0.0625 && dur >= 0.03125) {
-            return "32";
+    public static duration(fraction: Fraction, isTuplet: boolean): string {
+      const dur: number = fraction.RealValue;
+
+      if (dur >= 1) {
+          return "w";
+      } else if (dur < 1 && dur >= 0.5) {
+        // change to the next higher straight note to get the correct note display type
+        if (isTuplet) {
+          return "w";
+        }
+        return "h";
+      } else if (dur < 0.5 && dur >= 0.25) {
+        // change to the next higher straight note to get the correct note display type
+        if (isTuplet && dur > 0.25) {
+          return "h";
+        }
+        return "q";
+      } else if (dur < 0.25 && dur >= 0.125) {
+        // change to the next higher straight note to get the correct note display type
+        if (isTuplet && dur > 0.125) {
+          return "q";
+        }
+        return "8";
+      } else if (dur < 0.125 && dur >= 0.0625) {
+        // change to the next higher straight note to get the correct note display type
+        if (isTuplet && dur > 0.0625) {
+          return "8";
         }
-        return "128";
+        return "16";
+      } else if (dur < 0.0625 && dur >= 0.03125) {
+        // change to the next higher straight note to get the correct note display type
+        if (isTuplet && dur > 0.03125) {
+          return "16";
+        }
+        return "32";
+      } else if (dur < 0.03125 && dur >= 0.015625) {
+        // change to the next higher straight note to get the correct note display type
+        if (isTuplet && dur > 0.015625) {
+          return "32";
+        }
+        return "64";
+      }
+
+      if (isTuplet) {
+        return "64";
+      }
+      return "128";
     }
 
     /**
@@ -68,10 +100,10 @@ export class VexFlowConverter {
      * @returns {string[]}
      */
     public static pitch(pitch: Pitch, clef: ClefInstruction): [string, string, ClefInstruction] {
-        let fund: string = NoteEnum[pitch.FundamentalNote].toLowerCase();
+        const fund: string = NoteEnum[pitch.FundamentalNote].toLowerCase();
         // The octave seems to need a shift of three FIXME?
-        let octave: number = pitch.Octave - clef.OctaveOffset + 3;
-        let acc: string = VexFlowConverter.accidental(pitch.Accidental);
+        const octave: number = pitch.Octave - clef.OctaveOffset + 3;
+        const acc: string = VexFlowConverter.accidental(pitch.Accidental);
         return [fund + "n/" + octave, acc, clef];
     }
 
@@ -110,22 +142,23 @@ export class VexFlowConverter {
      */
     public static StaveNote(notes: GraphicalNote[]): Vex.Flow.StaveNote {
         let keys: string[] = [];
-        let accidentals: string[] = [];
-        let frac: Fraction = notes[0].graphicalNoteLength;
-        let duration: string = VexFlowConverter.duration(frac);
+        const accidentals: string[] = [];
+        const frac: Fraction = notes[0].graphicalNoteLength;
+        const isTuplet: boolean = notes[0].sourceNote.NoteTuplet !== undefined;
+        let duration: string = VexFlowConverter.duration(frac, isTuplet);
         let vfClefType: string = undefined;
         let numDots: number = 0;
-        for (let note of notes) {
-            let res: [string, string, ClefInstruction] = (note as VexFlowGraphicalNote).vfpitch;
-            if (res === undefined) {
-                keys = ["b/4"];
-                duration += "r";
-                break;
+        for (const note of notes) {
+            const pitch: [string, string, ClefInstruction] = (note as VexFlowGraphicalNote).vfpitch;
+            if (pitch === undefined) { // if it is a rest:
+              keys = ["b/4"];
+              duration += "r";
+              break;
             }
-            keys.push(res[0]);
-            accidentals.push(res[1]);
+            keys.push(pitch[0]);
+            accidentals.push(pitch[1]);
             if (!vfClefType) {
-                let vfClef: {type: string, annotation: string} = VexFlowConverter.Clef(res[2]);
+                const vfClef: {type: string, annotation: string} = VexFlowConverter.Clef(pitch[2]);
                 vfClefType = vfClef.type;
             }
             if (numDots < note.numberOfDots) {
@@ -136,14 +169,10 @@ export class VexFlowConverter {
             duration += "d";
         }
 
-        let vfnote: Vex.Flow.StaveNote = new Vex.Flow.StaveNote({
+        const vfnote: Vex.Flow.StaveNote = new Vex.Flow.StaveNote({
             auto_stem: true,
             clef: vfClefType,
             duration: duration,
-            duration_override: {
-                denominator: frac.Denominator,
-                numerator: frac.Numerator,
-            },
             keys: keys,
         });
 
@@ -161,28 +190,91 @@ export class VexFlowConverter {
     }
 
     /**
-     * Convert a ClefInstruction to a string representing a clef type in VexFlow
-     * @param clef
-     * @returns {string}
-     * @constructor
+     * Convert a ClefInstruction to a string represention of a clef type in VexFlow.
+     *
+     * @param clef The OSMD object to be converted representing the clef
+     * @param size The VexFlow size to be used. Can be `default` or `small`. As soon as
+     *             #118 is done, this parameter will be dispensable.
+     * @returns    A string representation of a VexFlow clef
+     * @see        https://github.com/0xfe/vexflow/blob/master/src/clef.js
+     * @see        https://github.com/0xfe/vexflow/blob/master/tests/clef_tests.js
      */
-    public static Clef(clef: ClefInstruction): {type: string, annotation: string} {
+    public static Clef(clef: ClefInstruction, size: string = "default"): { type: string, size: string, annotation: string } {
         let type: string;
-        let annotation: string = undefined;
+        let annotation: string;
+
+        // Make sure size is either "default" or "small"
+        if (size !== "default" && size !== "small") {
+            Logging.warn(`Invalid VexFlow clef size "${size}" specified. Using "default".`);
+            size = "default";
+        }
 
+        /*
+         * For all of the following conversions, OSMD uses line numbers 1-5 starting from
+         * the bottom, while VexFlow uses 0-4 starting from the top.
+         */
         switch (clef.ClefType) {
+
+            // G Clef
             case ClefEnum.G:
-                type = "treble";
+                switch (clef.Line) {
+                    case 1:
+                        type = "french"; // VexFlow line 4
+                        break;
+                    case 2:
+                        type = "treble"; // VexFlow line 3
+                        break;
+                    default:
+                        type = "treble";
+                        Logging.error(`Clef ${ClefEnum[clef.ClefType]} on line ${clef.Line} not supported by VexFlow. Using default value "${type}".`);
+                }
                 break;
+
+            // F Clef
             case ClefEnum.F:
-                type = "bass";
+                switch (clef.Line) {
+                  case 4:
+                      type = "bass"; // VexFlow line 1
+                      break;
+                  case 3:
+                      type = "baritone-f"; // VexFlow line 2
+                      break;
+                  case 5:
+                      type = "subbass"; // VexFlow line 0
+                      break;
+                  default:
+                      type = "bass";
+                      Logging.error(`Clef ${ClefEnum[clef.ClefType]} on line ${clef.Line} not supported by VexFlow. Using default value "${type}".`);
+                }
                 break;
+
+            // C Clef
             case ClefEnum.C:
-                type = "alto";
+                switch (clef.Line) {
+                  case 3:
+                      type = "alto"; // VexFlow line 2
+                      break;
+                  case 4:
+                      type = "tenor"; // VexFlow line 1
+                      break;
+                  case 1:
+                      type = "soprano"; // VexFlow line 4
+                      break;
+                  case 2:
+                      type = "mezzo-soprano"; // VexFlow line 3
+                      break;
+                  default:
+                      type = "alto";
+                      Logging.error(`Clef ${ClefEnum[clef.ClefType]} on line ${clef.Line} not supported by VexFlow. Using default value "${type}".`);
+                }
                 break;
+
+            // Percussion Clef
             case ClefEnum.percussion:
                 type = "percussion";
                 break;
+
+            // TAB Clef
             case ClefEnum.TAB:
                 type = "tab";
                 break;
@@ -198,7 +290,7 @@ export class VexFlowConverter {
                 break;
             default:
         }
-        return {type, annotation};
+        return { type, size, annotation };
     }
 
     /**
@@ -235,16 +327,15 @@ export class VexFlowConverter {
         }
         let ret: string;
         switch (key.Mode) {
-            case KeyEnum.none:
-                ret = undefined;
-                break;
             case KeyEnum.minor:
                 ret = VexFlowConverter.minorMap[key.Key] + "m";
                 break;
             case KeyEnum.major:
                 ret = VexFlowConverter.majorMap[key.Key];
                 break;
+            case KeyEnum.none:
             default:
+                ret = "C";
         }
         return ret;
     }
@@ -286,7 +377,7 @@ export class VexFlowConverter {
     public static font(fontSize: number, fontStyle: FontStyles = FontStyles.Regular, font: Fonts = Fonts.TimesNewRoman): string {
         let style: string = "normal";
         let weight: string = "normal";
-        let family: string = "'Times New Roman'";
+        const family: string = "'Times New Roman'";
 
         switch (fontStyle) {
             case FontStyles.Bold:
@@ -318,12 +409,29 @@ export class VexFlowConverter {
     }
 
     /**
+     * Converts the style into a string that VexFlow RenderContext can understand
+     * as the weight of the font
+     */
+    public static fontStyle(style: FontStyles): string {
+        switch (style) {
+            case FontStyles.Bold:
+                return "bold";
+            case FontStyles.Italic:
+                return "italic";
+            case FontStyles.BoldItalic:
+                return "italic bold";
+            default:
+                return "normal";
+        }
+    }
+
+    /**
      * Convert OutlineAndFillStyle to CSS properties
      * @param styleId
      * @returns {string}
      */
     public static style(styleId: OutlineAndFillStyleEnum): string {
-        // TODO To be implemented
-        return "lightgreen";
+        const ret: string = OUTLINE_AND_FILL_STYLE_DICT.getValue(styleId);
+        return ret;
     }
 }

+ 1 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowGraphicalNote.ts

@@ -36,7 +36,7 @@ export class VexFlowGraphicalNote extends GraphicalNote {
      */
     public setPitch(pitch: Pitch): void {
         if (this.vfnote) {
-            let acc: string = VexFlowConverter.accidental(pitch.Accidental);
+            const acc: string = VexFlowConverter.accidental(pitch.Accidental);
             if (acc) {
                 alert(acc);
                 this.vfnote[0].addAccidental(this.vfnote[1], new Vex.Flow.Accidental(acc));

+ 16 - 5
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 {
     /**
@@ -95,11 +98,11 @@ export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
     public createNote(note: Note, graphicalStaffEntry: GraphicalStaffEntry,
                       activeClef: ClefInstruction, octaveShift: OctaveEnum = OctaveEnum.NONE,  graphicalNoteLength: Fraction = undefined): GraphicalNote {
         // Creates the note:
-        let graphicalNote: GraphicalNote = new VexFlowGraphicalNote(note, graphicalStaffEntry, activeClef, octaveShift, graphicalNoteLength);
+        const graphicalNote: GraphicalNote = new VexFlowGraphicalNote(note, graphicalStaffEntry, activeClef, octaveShift, graphicalNoteLength);
         if (note.ParentVoiceEntry !== undefined) {
             // Adds the note to the right (graphical) voice (mynotes)
-            let voiceID: number = note.ParentVoiceEntry.ParentVoice.VoiceId;
-            let mynotes: { [id: number]: GraphicalNote[]; } = (graphicalStaffEntry as VexFlowStaffEntry).graphicalNotes;
+            const voiceID: number = note.ParentVoiceEntry.ParentVoice.VoiceId;
+            const mynotes: { [id: number]: GraphicalNote[]; } = (graphicalStaffEntry as VexFlowStaffEntry).graphicalNotes;
             if (!(voiceID in mynotes)) {
                 mynotes[voiceID] = [];
             }
@@ -132,7 +135,7 @@ export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
      */
     public addGraphicalAccidental(graphicalNote: GraphicalNote, pitch: Pitch, grace: boolean, graceScalingFactor: number): void {
         // ToDo: set accidental here from pitch.Accidental
-        let note: VexFlowGraphicalNote = (graphicalNote as VexFlowGraphicalNote);
+        const note: VexFlowGraphicalNote = (graphicalNote as VexFlowGraphicalNote);
         note.setPitch(pitch);
     }
 
@@ -172,6 +175,14 @@ export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
      * @param transposeHalftones
      */
     public createChordSymbol(sourceStaffEntry: SourceStaffEntry, graphicalStaffEntry: GraphicalStaffEntry, transposeHalftones: number): void {
-        return;
+      const graphicalChordSymbolContainer: GraphicalChordSymbolContainer =
+        new GraphicalChordSymbolContainer(sourceStaffEntry.ChordContainer,
+                                          graphicalStaffEntry.PositionAndShape,
+                                          EngravingRules.Rules.ChordSymbolTextHeight,
+                                          transposeHalftones);
+      const graphicalLabel: GraphicalLabel = graphicalChordSymbolContainer.GetGraphicalLabel;
+      graphicalLabel.setLabelPositionAndShapeBorders();
+      graphicalChordSymbolContainer.PositionAndShape.calculateBoundingBox();
+      graphicalStaffEntry.graphicalChordContainer = graphicalChordSymbolContainer;
     }
 }

+ 42 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowInstrumentBracket.ts

@@ -0,0 +1,42 @@
+import Vex = require("vexflow");
+import {GraphicalObject} from "../GraphicalObject";
+import {VexFlowStaffLine} from "./VexFlowStaffLine";
+import { BoundingBox } from "../BoundingBox";
+import { VexFlowMeasure } from "./VexFlowMeasure";
+
+/**
+ * Class that defines a instrument bracket at the beginning of a line.
+ */
+export class VexFlowInstrumentBracket extends GraphicalObject {
+
+    private vexflowConnector: Vex.Flow.StaveConnector;
+
+    constructor(firstVexFlowStaffLine: VexFlowStaffLine, lastVexFlowStaffLine: VexFlowStaffLine) {
+        super();
+        // FIXME: B.Giesinger: Fill in sizes after calculation
+        this.boundingBox = new BoundingBox(this);
+        const firstVexMeasure: VexFlowMeasure = firstVexFlowStaffLine.Measures[0] as VexFlowMeasure;
+        const lastVexMeasure: VexFlowMeasure = lastVexFlowStaffLine.Measures[0] as VexFlowMeasure;
+        this.addConnector(firstVexMeasure.getVFStave(), lastVexMeasure.getVFStave(), Vex.Flow.StaveConnector.type.BRACE);
+    }
+
+    /**
+     * Render the bracket using the given backend
+     * @param ctx Render Vexflow context
+     */
+    public draw(ctx: Vex.Flow.RenderContext): void {
+        this.vexflowConnector.setContext(ctx).draw();
+    }
+
+    /**
+     * Adds a connector between two staves
+     *
+     * @param {Stave} stave1: First stave
+     * @param {Stave} stave2: Second stave
+     * @param {Flow.StaveConnector.type} type: Type of connector
+     */
+    private addConnector(stave1: Vex.Flow.Stave, stave2: Vex.Flow.Stave, type: any): void {
+        this.vexflowConnector = new Vex.Flow.StaveConnector(stave1, stave2)
+        .setType(type);
+    }
+}

+ 69 - 58
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -81,20 +81,19 @@ export class VexFlowMeasure extends StaffMeasure {
      * @returns {SystemLinesEnum} the x-width
      */
     public getLineWidth(line: SystemLinesEnum): number {
-      // FIXME: See values in VexFlow's stavebarline.js
-
-      // ToDo: feature/Repetitions
-      // Extend the lineWidth calculation with all repetition lines.
-      // Change also the code in VexFlowConverter.line.
-      let vfline: any = VexFlowConverter.line(line);
-      switch (vfline) {
-          case Vex.Flow.StaveConnector.type.SINGLE:
-              return 1.0 / unitInPixels;
-          case Vex.Flow.StaveConnector.type.DOUBLE:
-              return 3.0 / unitInPixels;
-          default:
-              return 0;
-      }
+        // FIXME: See values in VexFlow's stavebarline.js
+        // ToDo: feature/Repetitions
+        // Extend the lineWidth calculation with all repetition lines.
+        // Change also the code in VexFlowConverter.line.
+        const vfline: any = VexFlowConverter.line(line);
+        switch (vfline) {
+            case Vex.Flow.StaveConnector.type.SINGLE:
+                return 1.0 / unitInPixels;
+            case Vex.Flow.StaveConnector.type.DOUBLE:
+                return 3.0 / unitInPixels;
+            default:
+                return 0;
+        }
     }
 
     /**
@@ -104,8 +103,8 @@ export class VexFlowMeasure extends StaffMeasure {
      */
     public addClefAtBegin(clef: ClefInstruction): void {
         this.octaveOffset = clef.OctaveOffset;
-        let vfclef: {type: string, annotation: string} = VexFlowConverter.Clef(clef);
-        this.stave.addClef(vfclef.type, undefined, vfclef.annotation, Vex.Flow.Modifier.Position.BEGIN);
+        const vfclef: { type: string, size: string, annotation: string } = VexFlowConverter.Clef(clef, "default");
+        this.stave.addClef(vfclef.type, vfclef.size, vfclef.annotation, Vex.Flow.Modifier.Position.BEGIN);
         this.updateInstructionWidth();
     }
 
@@ -131,7 +130,7 @@ export class VexFlowMeasure extends StaffMeasure {
      * @param rhythm
      */
     public addRhythmAtBegin(rhythm: RhythmInstruction): void {
-        let timeSig: Vex.Flow.TimeSignature = VexFlowConverter.TimeSignature(rhythm);
+        const timeSig: Vex.Flow.TimeSignature = VexFlowConverter.TimeSignature(rhythm);
         this.stave.addModifier(
             timeSig,
             Vex.Flow.Modifier.Position.BEGIN
@@ -145,8 +144,8 @@ export class VexFlowMeasure extends StaffMeasure {
      * @param clef
      */
     public addClefAtEnd(clef: ClefInstruction): void {
-        let vfclef: {type: string, annotation: string} = VexFlowConverter.Clef(clef);
-        this.stave.setEndClef(vfclef.type, "small", vfclef.annotation);
+        const vfclef: { type: string, size: string, annotation: string } = VexFlowConverter.Clef(clef, "small");
+        this.stave.setEndClef(vfclef.type, vfclef.size, vfclef.annotation);
         this.updateInstructionWidth();
     }
 
@@ -185,7 +184,7 @@ export class VexFlowMeasure extends StaffMeasure {
      * Draw this measure on a VexFlow CanvasContext
      * @param ctx
      */
-    public draw(ctx: Vex.Flow.CanvasContext): void {
+    public draw(ctx: Vex.Flow.RenderContext): void {
         // If this is the first stave in the vertical measure, call the format
         // method to set the width of all the voices
         if (this.formatVoices) {
@@ -198,36 +197,36 @@ export class VexFlowMeasure extends StaffMeasure {
         // Draw stave lines
         this.stave.setContext(ctx).draw();
         // Draw all voices
-        for (let voiceID in this.vfVoices) {
+        for (const voiceID in this.vfVoices) {
             if (this.vfVoices.hasOwnProperty(voiceID)) {
                 this.vfVoices[voiceID].draw(ctx, this.stave);
             }
         }
         // Draw beams
-        for (let voiceID in this.vfbeams) {
+        for (const voiceID in this.vfbeams) {
             if (this.vfbeams.hasOwnProperty(voiceID)) {
-                for (let beam of this.vfbeams[voiceID]) {
+                for (const beam of this.vfbeams[voiceID]) {
                     beam.setContext(ctx).draw();
                 }
             }
         }
 
         // Draw tuplets
-        for (let voiceID in this.vftuplets) {
+        for (const voiceID in this.vftuplets) {
             if (this.vftuplets.hasOwnProperty(voiceID)) {
-                for (let tuplet of this.vftuplets[voiceID]) {
+                for (const tuplet of this.vftuplets[voiceID]) {
                     tuplet.setContext(ctx).draw();
                 }
             }
         }
 
         // Draw ties
-        for (let tie of this.vfTies) {
+        for (const tie of this.vfTies) {
             tie.setContext(ctx).draw();
         }
 
         // Draw vertical lines
-        for (let connector of this.connectors) {
+        for (const connector of this.connectors) {
             connector.setContext(ctx).draw();
         }
 
@@ -241,13 +240,13 @@ export class VexFlowMeasure extends StaffMeasure {
      * @param beam
      */
     public handleBeam(graphicalNote: GraphicalNote, beam: Beam): void {
-        let voiceID: number = graphicalNote.sourceNote.ParentVoiceEntry.ParentVoice.VoiceId;
+        const voiceID: number = graphicalNote.sourceNote.ParentVoiceEntry.ParentVoice.VoiceId;
         let beams: [Beam, VexFlowStaffEntry[]][] = this.beams[voiceID];
         if (beams === undefined) {
             beams = this.beams[voiceID] = [];
         }
         let data: [Beam, VexFlowStaffEntry[]];
-        for (let mybeam of beams) {
+        for (const mybeam of beams) {
             if (mybeam[0] === beam) {
                 data = mybeam;
             }
@@ -256,20 +255,21 @@ export class VexFlowMeasure extends StaffMeasure {
             data = [beam, []];
             beams.push(data);
         }
-        let parent: VexFlowStaffEntry = graphicalNote.parentStaffEntry as VexFlowStaffEntry;
+        const parent: VexFlowStaffEntry = graphicalNote.parentStaffEntry as VexFlowStaffEntry;
         if (data[1].indexOf(parent) < 0) {
             data[1].push(parent);
         }
     }
 
     public handleTuplet(graphicalNote: GraphicalNote, tuplet: Tuplet): void {
-        let voiceID: number = graphicalNote.sourceNote.ParentVoiceEntry.ParentVoice.VoiceId;
+        const voiceID: number = graphicalNote.sourceNote.ParentVoiceEntry.ParentVoice.VoiceId;
+        tuplet = graphicalNote.sourceNote.NoteTuplet;
         let tuplets: [Tuplet, VexFlowStaffEntry[]][] = this.tuplets[voiceID];
         if (tuplets === undefined) {
             tuplets = this.tuplets[voiceID] = [];
         }
         let currentTupletBuilder: [Tuplet, VexFlowStaffEntry[]];
-        for (let t of tuplets) {
+        for (const t of tuplets) {
             if (t[0] === tuplet) {
                 currentTupletBuilder = t;
             }
@@ -278,7 +278,7 @@ export class VexFlowMeasure extends StaffMeasure {
             currentTupletBuilder = [tuplet, []];
             tuplets.push(currentTupletBuilder);
         }
-        let parent: VexFlowStaffEntry = graphicalNote.parentStaffEntry as VexFlowStaffEntry;
+        const parent: VexFlowStaffEntry = graphicalNote.parentStaffEntry as VexFlowStaffEntry;
         if (currentTupletBuilder[1].indexOf(parent) < 0) {
             currentTupletBuilder[1].push(parent);
         }
@@ -292,16 +292,19 @@ export class VexFlowMeasure extends StaffMeasure {
         // created them brand new. Is this needed? And more importantly,
         // should the old beams be removed manually by the notes?
         this.vfbeams = {};
-        for (let voiceID in this.beams) {
+        for (const voiceID in this.beams) {
             if (this.beams.hasOwnProperty(voiceID)) {
                 let vfbeams: Vex.Flow.Beam[] = this.vfbeams[voiceID];
                 if (vfbeams === undefined) {
                     vfbeams = this.vfbeams[voiceID] = [];
                 }
-                for (let beam of this.beams[voiceID]) {
-                    let notes: Vex.Flow.StaveNote[] = [];
-                    for (let entry of beam[1]) {
-                        notes.push((<VexFlowStaffEntry>entry).vfNotes[voiceID]);
+                for (const beam of this.beams[voiceID]) {
+                    const notes: Vex.Flow.StaveNote[] = [];
+                    for (const entry of beam[1]) {
+                        const 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));
@@ -323,21 +326,27 @@ export class VexFlowMeasure extends StaffMeasure {
     public finalizeTuplets(): void {
         // The following line resets the created Vex.Flow Tuplets and
         // created them brand new. Is this needed? And more importantly,
-        // should the old tuplets be removed manually by the notes?
+        // should the old tuplets be removed manually from the notes?
         this.vftuplets = {};
-        for (let voiceID in this.tuplets) {
+        for (const voiceID in this.tuplets) {
             if (this.tuplets.hasOwnProperty(voiceID)) {
                 let vftuplets: Vex.Flow.Tuplet[] = this.vftuplets[voiceID];
                 if (vftuplets === undefined) {
                     vftuplets = this.vftuplets[voiceID] = [];
                 }
-                for (let tuplet of this.tuplets[voiceID]) {
-                    let notes: Vex.Flow.StaveNote[] = [];
-                    for (let entry of tuplet[1]) {
-                        notes.push((<VexFlowStaffEntry>entry).vfNotes[voiceID]);
+                for (const tupletBuilder of this.tuplets[voiceID]) {
+                    const tupletStaveNotes: Vex.Flow.StaveNote[] = [];
+                    const tupletStaffEntries: VexFlowStaffEntry[] = tupletBuilder[1];
+                    for (const tupletStaffEntry of tupletStaffEntries) {
+                      tupletStaveNotes.push((tupletStaffEntry).vfNotes[voiceID]);
                     }
-                    if (notes.length > 1) {
-                        vftuplets.push(new Vex.Flow.Tuplet(notes));
+                    if (tupletStaveNotes.length > 1) {
+                      const notesOccupied: number = 2;
+                      vftuplets.push(new Vex.Flow.Tuplet( tupletStaveNotes,
+                                                          {
+                                                            notes_occupied: notesOccupied,
+                                                            num_notes: tupletStaveNotes.length //, location: -1, ratioed: true
+                                                          }));
                     } else {
                         Logging.log("Warning! Tuplet with no notes! Trying to ignore, but this is a serious problem.");
                     }
@@ -352,13 +361,13 @@ export class VexFlowMeasure extends StaffMeasure {
 
     public staffMeasureCreatedCalculations(): void {
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
+            const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
 
             // create vex flow Notes:
-            let gnotes: { [voiceID: number]: GraphicalNote[]; } = graphicalStaffEntry.graphicalNotes;
-            for (let voiceID in gnotes) {
+            const gnotes: { [voiceID: number]: GraphicalNote[]; } = graphicalStaffEntry.graphicalNotes;
+            for (const voiceID in gnotes) {
                 if (gnotes.hasOwnProperty(voiceID)) {
-                    let vfnote: StaveNote = VexFlowConverter.StaveNote(gnotes[voiceID]);
+                    const vfnote: StaveNote = VexFlowConverter.StaveNote(gnotes[voiceID]);
                     (graphicalStaffEntry as VexFlowStaffEntry).vfNotes[voiceID] = vfnote;
                 }
             }
@@ -368,11 +377,11 @@ export class VexFlowMeasure extends StaffMeasure {
         this.finalizeTuplets();
 
         for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
-            let graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
-            let gnotes: { [voiceID: number]: GraphicalNote[]; } = graphicalStaffEntry.graphicalNotes;
+            const graphicalStaffEntry: VexFlowStaffEntry = (this.staffEntries[idx] as VexFlowStaffEntry);
+            const gnotes: { [voiceID: number]: GraphicalNote[]; } = graphicalStaffEntry.graphicalNotes;
             // create vex flow voices and add tickables to it:
-            let vfVoices: { [voiceID: number]: Vex.Flow.Voice; } = this.vfVoices;
-            for (let voiceID in gnotes) {
+            const vfVoices: { [voiceID: number]: Vex.Flow.Voice; } = this.vfVoices;
+            for (const voiceID in gnotes) {
                 if (gnotes.hasOwnProperty(voiceID)) {
                     if (!(voiceID in vfVoices)) {
                         vfVoices[voiceID] = new Vex.Flow.Voice({
@@ -394,7 +403,7 @@ export class VexFlowMeasure extends StaffMeasure {
      * @param lineType
      */
     public lineTo(top: VexFlowMeasure, lineType: any): void {
-        let connector: StaveConnector = new Vex.Flow.StaveConnector(top.getVFStave(), this.stave);
+        const connector: StaveConnector = new Vex.Flow.StaveConnector(top.getVFStave(), this.stave);
         connector.setType(lineType);
         this.connectors.push(connector);
     }
@@ -440,14 +449,16 @@ export class VexFlowMeasure extends StaffMeasure {
      */
     private setStaffEntriesXPositions(): void {
         for (let idx3: number = 0, len3: number = this.staffEntries.length; idx3 < len3; ++idx3) {
-            let gse: VexFlowStaffEntry = (<VexFlowStaffEntry> this.staffEntries[idx3]);
-            let measure: StaffMeasure = gse.parentMeasure;
-            let x: number =
+            const gse: VexFlowStaffEntry = (<VexFlowStaffEntry> this.staffEntries[idx3]);
+            const measure: StaffMeasure = gse.parentMeasure;
+            const x: number =
                 gse.getX() -
                 measure.PositionAndShape.RelativePosition.x -
                 measure.ParentStaffLine.PositionAndShape.RelativePosition.x -
                 measure.parentMusicSystem.PositionAndShape.RelativePosition.x;
             gse.PositionAndShape.RelativePosition.x = x;
+            gse.PositionAndShape.calculateAbsolutePosition();
+            gse.PositionAndShape.calculateAbsolutePositionsOfChildren();
         }
     }
 }

+ 32 - 35
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -39,8 +39,8 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
 
     protected clearRecreatedObjects(): void {
         super.clearRecreatedObjects();
-        for (let staffMeasures of this.graphicalMusicSheet.MeasureList) {
-            for (let staffMeasure of staffMeasures) {
+        for (const staffMeasures of this.graphicalMusicSheet.MeasureList) {
+            for (const staffMeasure of staffMeasures) {
                 (<VexFlowMeasure>staffMeasure).clean();
             }
         }
@@ -68,15 +68,15 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
             (measure as VexFlowMeasure).finalizeTuplets();
         }*/
         // Format the voices
-        let allVoices: Vex.Flow.Voice[] = [];
-        let formatter: Vex.Flow.Formatter = new Vex.Flow.Formatter({
+        const allVoices: Vex.Flow.Voice[] = [];
+        const formatter: Vex.Flow.Formatter = new Vex.Flow.Formatter({
             align_rests: true,
         });
 
-        for (let measure of measures) {
-            let mvoices:  { [voiceID: number]: Vex.Flow.Voice; } = (measure as VexFlowMeasure).vfVoices;
-            let voices: Vex.Flow.Voice[] = [];
-            for (let voiceID in mvoices) {
+        for (const measure of measures) {
+            const mvoices:  { [voiceID: number]: Vex.Flow.Voice; } = (measure as VexFlowMeasure).vfVoices;
+            const voices: Vex.Flow.Voice[] = [];
+            for (const voiceID in mvoices) {
                 if (mvoices.hasOwnProperty(voiceID)) {
                     voices.push(mvoices[voiceID]);
                     allVoices.push(mvoices[voiceID]);
@@ -92,11 +92,11 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
 
         let width: number = 200;
         if (allVoices.length > 0) {
-            let firstMeasure: VexFlowMeasure = measures[0] as VexFlowMeasure;
+            const firstMeasure: VexFlowMeasure = measures[0] as VexFlowMeasure;
             // FIXME: The following ``+ 5.0'' is temporary: it was added as a workaround for
             // FIXME: a more relaxed formatting of voices
             width = formatter.preCalculateMinTotalWidth(allVoices) / unitInPixels + 5.0;
-            for (let measure of measures) {
+            for (const measure of measures) {
                 measure.minimumStaffEntriesWidth = width;
                 (measure as VexFlowMeasure).formatVoices = undefined;
             }
@@ -156,15 +156,15 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
      */
     protected calculateSystemYLayout(): void {
         for (let idx: number = 0, len: number = this.graphicalMusicSheet.MusicPages.length; idx < len; ++idx) {
-            let graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx];
+            const graphicalMusicPage: GraphicalMusicPage = this.graphicalMusicSheet.MusicPages[idx];
             if (!this.leadSheet) {
                 let globalY: number = this.rules.PageTopMargin + this.rules.TitleTopDistance + this.rules.SheetTitleHeight +
                     this.rules.TitleBottomDistance;
                 for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) {
-                    let musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
+                    const musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
                     // calculate y positions of stafflines within system
                     let y: number = 0;
-                    for (let line of musicSystem.StaffLines) {
+                    for (const line of musicSystem.StaffLines) {
                         line.PositionAndShape.RelativePosition.y = y;
                         y += 10;
                     }
@@ -191,13 +191,13 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
      * @param tieIsAtSystemBreak
      */
     protected layoutGraphicalTie(tie: GraphicalTie, tieIsAtSystemBreak: boolean): void {
-        let startNote: VexFlowGraphicalNote = (tie.StartNote as VexFlowGraphicalNote);
+        const startNote: VexFlowGraphicalNote = (tie.StartNote as VexFlowGraphicalNote);
         let vfStartNote: Vex.Flow.StaveNote = undefined;
         if (startNote !== undefined) {
             vfStartNote = startNote.vfnote[0];
         }
 
-        let endNote: VexFlowGraphicalNote = (tie.EndNote as VexFlowGraphicalNote);
+        const endNote: VexFlowGraphicalNote = (tie.EndNote as VexFlowGraphicalNote);
         let vfEndNote: Vex.Flow.StaveNote = undefined;
         if (endNote !== undefined) {
             vfEndNote = endNote.vfnote[0];
@@ -206,23 +206,23 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
 
         if (tieIsAtSystemBreak) {
             // split tie into two ties:
-            let vfTie1: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
+            const vfTie1: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
                 first_note: vfStartNote,
             });
-            let measure1: VexFlowMeasure = (startNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
+            const measure1: VexFlowMeasure = (startNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
             measure1.vfTies.push(vfTie1);
 
-            let vfTie2: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
+            const vfTie2: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
                 last_note : vfEndNote,
             });
-            let measure2: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
+            const measure2: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
             measure2.vfTies.push(vfTie2);
         } else {
-            let vfTie: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
+            const vfTie: Vex.Flow.StaveTie = new Vex.Flow.StaveTie({
                 first_note: vfStartNote,
                 last_note : vfEndNote,
             });
-            let measure: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
+            const measure: VexFlowMeasure = (endNote.parentStaffEntry.parentMeasure as VexFlowMeasure);
             measure.vfTies.push(vfTie);
         }
     }
@@ -255,13 +255,11 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void {
       // find first visible StaffLine
       let staffLine: VexFlowStaffLine = undefined;
-      let measures: VexFlowMeasure[]  = <VexFlowMeasure[]>this.graphicalMusicSheet.MeasureList[measureIndex];
-      let topMeasure: VexFlowMeasure = undefined;
+      const measures: VexFlowMeasure[]  = <VexFlowMeasure[]>this.graphicalMusicSheet.MeasureList[measureIndex];
       for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
-        let graphicalMeasure: VexFlowMeasure = measures[idx];
+        const graphicalMeasure: VexFlowMeasure = measures[idx];
         if (graphicalMeasure.ParentStaffLine !== undefined && graphicalMeasure.ParentStaff.ParentInstrument.Visible) {
           staffLine = <VexFlowStaffLine>graphicalMeasure.ParentStaffLine;
-          topMeasure = graphicalMeasure;
           break;
         }
       }
@@ -269,38 +267,37 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
       // now create corresponding graphical symbol or Text in VexFlow:
       // use top measure and staffline for positioning.
       if (staffLine !== undefined) {
-        let instruction: string = "";
+        //let instruction: string = "";
         switch (repetitionInstruction.type) {
           case RepetitionInstructionEnum.Segno:
-
             // create Segno Symbol:
             break;
           case RepetitionInstructionEnum.Coda:
             // create Coda Symbol:
             break;
           case RepetitionInstructionEnum.DaCapo:
-            instruction = "D.C.";
+            //instruction = "D.C.";
             break;
           case RepetitionInstructionEnum.DalSegno:
-            instruction = "D.S.";
+            //instruction = "D.S.";
             break;
           case RepetitionInstructionEnum.Fine:
-            instruction = "Fine";
+            //instruction = "Fine";
             break;
           case RepetitionInstructionEnum.ToCoda:
-            instruction = "To Coda";
+            //instruction = "To Coda";
             break;
           case RepetitionInstructionEnum.DaCapoAlFine:
-            instruction = "D.C. al Fine";
+            //instruction = "D.C. al Fine";
             break;
           case RepetitionInstructionEnum.DaCapoAlCoda:
-            instruction = "D.C. al Coda";
+            //instruction = "D.C. al Coda";
             break;
           case RepetitionInstructionEnum.DalSegnoAlFine:
-            instruction = "D.S. al Fine";
+            //instruction = "D.S. al Fine";
             break;
           case RepetitionInstructionEnum.DalSegnoAlCoda:
-            instruction = "D.S. al Coda";
+            //instruction = "D.S. al Coda";
             break;
           default:
             break;

+ 41 - 33
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -1,34 +1,36 @@
-import Vex = require("vexflow");
 import {MusicSheetDrawer} from "../MusicSheetDrawer";
 import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D";
 import {VexFlowMeasure} from "./VexFlowMeasure";
 import {PointF2D} from "../../../Common/DataObjects/PointF2D";
 import {GraphicalLabel} from "../GraphicalLabel";
-import {VexFlowConverter} from "./VexFlowConverter";
 import {VexFlowTextMeasurer} from "./VexFlowTextMeasurer";
 import {MusicSystem} from "../MusicSystem";
 import {GraphicalObject} from "../GraphicalObject";
+import {GraphicalLayers} from "../DrawingEnums";
+import {GraphicalStaffEntry} from "../GraphicalStaffEntry";
+import {VexFlowBackend} from "./VexFlowBackend";
+import { VexFlowInstrumentBracket } from "./VexFlowInstrumentBracket";
 
 /**
- * This is a global contant which denotes the height in pixels of the space between two lines of the stave
+ * This is a global constant which denotes the height in pixels of the space between two lines of the stave
  * (when zoom = 1.0)
  * @type number
  */
 export const unitInPixels: number = 10;
 
 export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
-    private renderer: Vex.Flow.Renderer;
-    private vfctx: Vex.Flow.CanvasContext;
-    private ctx: CanvasRenderingContext2D;
+    private backend: VexFlowBackend;
     private zoom: number = 1.0;
 
-    constructor(canvas: HTMLCanvasElement, isPreviewImageDrawer: boolean = false) {
+    constructor(element: HTMLElement,
+                backend: VexFlowBackend,
+                isPreviewImageDrawer: boolean = false) {
         super(new VexFlowTextMeasurer(), isPreviewImageDrawer);
-        this.renderer = new Vex.Flow.Renderer(canvas, Vex.Flow.Renderer.Backends.CANVAS);
-        this.vfctx = this.renderer.getContext();
-        // The following is a hack to retrieve the actual canvas' drawing context
-        // Not supposed to work forever....
-        this.ctx = (this.vfctx as any).vexFlowCanvasContext;
+        this.backend = backend;
+    }
+
+    public clear(): void {
+        this.backend.clear();
     }
 
     /**
@@ -37,7 +39,7 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
      */
     public scale(k: number): void {
         this.zoom = k;
-        this.vfctx.scale(k, k);
+        this.backend.scale(this.zoom);
     }
 
     /**
@@ -46,12 +48,11 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
      * @param y
      */
     public resize(x: number, y: number): void {
-        this.renderer.resize(x, y);
+        this.backend.resize(x, y);
     }
 
     public translate(x: number, y: number): void {
-        // Translation seems not supported by VexFlow
-        this.ctx.translate(x, y);
+        this.backend.translate(x, y);
     }
 
     /**
@@ -68,11 +69,25 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
             measure.PositionAndShape.AbsolutePosition.x * unitInPixels,
             measure.PositionAndShape.AbsolutePosition.y * unitInPixels
         );
-        return measure.draw(this.vfctx);
+        measure.draw(this.backend.getContext());
+
+        // Draw the StaffEntries
+        for (const staffEntry of measure.staffEntries) {
+            this.drawStaffEntry(staffEntry);
+        }
     }
 
-    protected drawInstrumentBrace(bracket: GraphicalObject, system: MusicSystem): void {
-        // empty
+    private drawStaffEntry(staffEntry: GraphicalStaffEntry): void {
+        // Draw ChordSymbol
+        if (staffEntry.graphicalChordContainer !== undefined) {
+            this.drawLabel(staffEntry.graphicalChordContainer.GetGraphicalLabel, <number>GraphicalLayers.Notes);
+        }
+    }
+
+    protected drawInstrumentBrace(brace: GraphicalObject, system: MusicSystem): void {
+        // Draw InstrumentBrackets at beginning of line
+        const vexBrace: VexFlowInstrumentBracket = (brace as VexFlowInstrumentBracket);
+        vexBrace.draw(this.backend.getContext());
     }
 
     protected drawGroupBracket(bracket: GraphicalObject, system: MusicSystem): void {
@@ -90,15 +105,10 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
      */
     protected renderLabel(graphicalLabel: GraphicalLabel, layer: number, bitmapWidth: number,
                           bitmapHeight: number, heightInPixel: number, screenPosition: PointF2D): void {
-        let ctx: CanvasRenderingContext2D = (this.vfctx as any).vexFlowCanvasContext;
-        let old: string = ctx.font;
-        ctx.font = VexFlowConverter.font(
-            graphicalLabel.Label.fontHeight * unitInPixels,
-            graphicalLabel.Label.fontStyle,
-            graphicalLabel.Label.font
-        );
-        ctx.fillText(graphicalLabel.Label.text, screenPosition.x, screenPosition.y + heightInPixel);
-        ctx.font = old;
+        const height: number = graphicalLabel.Label.fontHeight * unitInPixels;
+        const { fontStyle, font, text } = graphicalLabel.Label;
+
+        this.backend.renderText(height, fontStyle, font, text, heightInPixel, screenPosition);
     }
 
     /**
@@ -107,12 +117,10 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
      * @param rectangle the rect in screen coordinates
      * @param layer is the current rendering layer. There are many layers on top of each other to which can be rendered. Not needed for now.
      * @param styleId the style id
+     * @param alpha alpha value between 0 and 1
      */
-    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number): void {
-        let old: string|CanvasGradient|CanvasPattern = this.ctx.fillStyle;
-        this.ctx.fillStyle = VexFlowConverter.style(styleId);
-        this.ctx.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
-        this.ctx.fillStyle = old;
+    protected renderRectangle(rectangle: RectangleF2D, layer: number, styleId: number, alpha: number): void {
+       this.backend.renderRectangle(rectangle, styleId, alpha);
     }
 
     /**

+ 12 - 5
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSystem.ts

@@ -4,10 +4,12 @@ import {SystemLinesEnum} from "../SystemLinesEnum";
 import {SystemLinePosition} from "../SystemLinePosition";
 import {StaffMeasure} from "../StaffMeasure";
 import {SystemLine} from "../SystemLine";
+import {VexFlowStaffLine} from "./VexFlowStaffLine";
 import {VexFlowMeasure} from "./VexFlowMeasure";
 import {VexFlowConverter} from "./VexFlowConverter";
 import {StaffLine} from "../StaffLine";
 import {EngravingRules} from "../EngravingRules";
+import { VexFlowInstrumentBracket } from "./VexFlowInstrumentBracket";
 
 export class VexFlowMusicSystem extends MusicSystem {
     constructor(parent: GraphicalMusicPage, id: number) {
@@ -19,7 +21,7 @@ export class VexFlowMusicSystem extends MusicSystem {
         if (this.staffLines.length === 0) {
             return;
         }
-        let width: number = this.calcBracketsWidth();
+        const width: number = this.calcBracketsWidth();
         this.boundingBox.BorderLeft = -width;
         this.boundingBox.BorderMarginLeft = -width;
         this.boundingBox.XBordersHaveBeenSet = true;
@@ -47,11 +49,16 @@ export class VexFlowMusicSystem extends MusicSystem {
 
     /**
      * creates an instrument brace for the given dimension.
-     * The height and positioning can be inferred from the given points.
-     * @param firstStaffLine the upper staff line of the bracket to create
-     * @param lastStaffLine the lower staff line of the bracket to create
+     * The height and positioning can be inferred from the given staff lines.
+     * @param firstStaffLine the upper StaffLine (use a cast to get the VexFlowStaffLine) of the brace to create
+     * @param lastStaffLine the lower StaffLine (use a cast to get the VexFlowStaffLine) of the brace to create
      */
-    protected createInstrumentBrace(firstStaffLine: StaffLine, lastStaffLine: StaffLine): void {
+    protected createInstrumentBracket(firstStaffLine: StaffLine, lastStaffLine: StaffLine): void {
+        // You could write this in one line but the linter doesn't let me.
+        const firstVexStaff: VexFlowStaffLine = (firstStaffLine as VexFlowStaffLine);
+        const lastVexStaff: VexFlowStaffLine = (lastStaffLine as VexFlowStaffLine);
+        const vexFlowBracket: VexFlowInstrumentBracket = new VexFlowInstrumentBracket(firstVexStaff, lastVexStaff);
+        this.InstrumentBrackets.push(vexFlowBracket);
         return;
     }
 

+ 2 - 2
src/MusicalScore/Graphical/VexFlow/VexFlowStaffEntry.ts

@@ -21,8 +21,8 @@ export class VexFlowStaffEntry extends GraphicalStaffEntry {
     public getX(): number {
         let x: number = 0;
         let n: number = 0;
-        let vfNotes: { [voiceID: number]: Vex.Flow.StaveNote; } = this.vfNotes;
-        for (let voiceId in vfNotes) {
+        const vfNotes: { [voiceID: number]: Vex.Flow.StaveNote; } = this.vfNotes;
+        for (const voiceId in vfNotes) {
             if (vfNotes.hasOwnProperty(voiceId)) {
                 x += (vfNotes[voiceId].getNoteHeadBeginX() + vfNotes[voiceId].getNoteHeadEndX()) / 2;
                 n += 1;

+ 1 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowTextMeasurer.ts

@@ -8,7 +8,7 @@ import {VexFlowConverter} from "./VexFlowConverter";
 
 export class VexFlowTextMeasurer implements ITextMeasurer {
     constructor() {
-        let canvas: HTMLCanvasElement = document.createElement("canvas");
+        const canvas: HTMLCanvasElement = document.createElement("canvas");
         this.context = canvas.getContext("2d");
     }
     // The context of a canvas used internally to compute font sizes

+ 22 - 22
src/MusicalScore/Instrument.ts

@@ -80,7 +80,7 @@ export class Instrument extends InstrumentalGroup {
     }
     public set Volume(value: number) {
         for (let idx: number = 0, len: number = this.subInstruments.length; idx < len; ++idx) {
-            let subInstrument: SubInstrument = this.subInstruments[idx];
+            const subInstrument: SubInstrument = this.subInstruments[idx];
             subInstrument.volume = value;
         }
     }
@@ -96,7 +96,7 @@ export class Instrument extends InstrumentalGroup {
     }
     public getSubInstrument(subInstrumentIdString: string): SubInstrument {
         for (let idx: number = 0, len: number = this.subInstruments.length; idx < len; ++idx) {
-            let subInstrument: SubInstrument = this.subInstruments[idx];
+            const subInstrument: SubInstrument = this.subInstruments[idx];
             if (subInstrument.idString === subInstrumentIdString) {
                 return subInstrument;
             }
@@ -112,49 +112,49 @@ export class Instrument extends InstrumentalGroup {
     }
     public set Visible(value: boolean) {
         for (let idx: number = 0, len: number = this.Voices.length; idx < len; ++idx) {
-            let v: Voice = this.Voices[idx];
+            const v: Voice = this.Voices[idx];
             v.Visible = value;
         }
     }
     public get Audible(): boolean {
         let result: boolean = false;
         for (let idx: number = 0, len: number = this.Voices.length; idx < len; ++idx) {
-            let v: Voice = this.Voices[idx];
+            const v: Voice = this.Voices[idx];
             result = result || v.Audible;
         }
         return result;
     }
     public set Audible(value: boolean) {
         for (let idx: number = 0, len: number = this.Voices.length; idx < len; ++idx) {
-            let v: Voice = this.Voices[idx];
+            const v: Voice = this.Voices[idx];
             v.Audible = value;
         }
         for (let idx: number = 0, len: number = this.staves.length; idx < len; ++idx) {
-            let staff: Staff = this.staves[idx];
+            const staff: Staff = this.staves[idx];
             staff.audible = value;
         }
     }
     public get Following(): boolean {
         let result: boolean = false;
         for (let idx: number = 0, len: number = this.Voices.length; idx < len; ++idx) {
-            let v: Voice = this.Voices[idx];
+            const v: Voice = this.Voices[idx];
             result = result || v.Following;
         }
         return result;
     }
     public set Following(value: boolean) {
         for (let idx: number = 0, len: number = this.Voices.length; idx < len; ++idx) {
-            let v: Voice = this.Voices[idx];
+            const v: Voice = this.Voices[idx];
             v.Following = value;
         }
         for (let idx: number = 0, len: number = this.staves.length; idx < len; ++idx) {
-            let staff: Staff = this.staves[idx];
+            const staff: Staff = this.staves[idx];
             staff.following = value;
         }
     }
     public SetVoiceAudible(voiceId: number, audible: boolean): void {
         for (let idx: number = 0, len: number = this.Voices.length; idx < len; ++idx) {
-            let v: Voice = this.Voices[idx];
+            const v: Voice = this.Voices[idx];
             if (v.VoiceId === voiceId) {
                 v.Audible = audible;
                 break;
@@ -163,7 +163,7 @@ export class Instrument extends InstrumentalGroup {
     }
     public SetVoiceFollowing(voiceId: number, following: boolean): void {
         for (let idx: number = 0, len: number = this.Voices.length; idx < len; ++idx) {
-            let v: Voice = this.Voices[idx];
+            const v: Voice = this.Voices[idx];
             if (v.VoiceId === voiceId) {
                 v.Following = following;
                 break;
@@ -171,22 +171,22 @@ export class Instrument extends InstrumentalGroup {
         }
     }
     public SetStaffAudible(staffId: number, audible: boolean): void {
-        let staff: Staff = this.staves[staffId - 1];
+        const staff: Staff = this.staves[staffId - 1];
         staff.audible = audible;
         if (audible) {
             for (let idx: number = 0, len: number = staff.Voices.length; idx < len; ++idx) {
-                let v: Voice = staff.Voices[idx];
+                const v: Voice = staff.Voices[idx];
                 v.Audible = true;
             }
         } else {
             for (let idx: number = 0, len: number = staff.Voices.length; idx < len; ++idx) {
-                let voice: Voice = staff.Voices[idx];
+                const voice: Voice = staff.Voices[idx];
                 let isAudibleInOtherStaves: boolean = false;
                 for (let idx2: number = 0, len2: number = this.Staves.length; idx2 < len2; ++idx2) {
-                    let st: Staff = this.Staves[idx2];
+                    const st: Staff = this.Staves[idx2];
                     if (st.Id === staffId || !st.audible) { continue; }
                     for (let idx3: number = 0, len3: number = st.Voices.length; idx3 < len3; ++idx3) {
-                        let v: Voice = st.Voices[idx3];
+                        const v: Voice = st.Voices[idx3];
                         if (v === voice) {
                             isAudibleInOtherStaves = true;
                         }
@@ -199,22 +199,22 @@ export class Instrument extends InstrumentalGroup {
         }
     }
     public SetStaffFollow(staffId: number, follow: boolean): void {
-        let staff: Staff = this.staves[staffId - 1];
+        const staff: Staff = this.staves[staffId - 1];
         staff.following = follow;
         if (follow) {
             for (let idx: number = 0, len: number = staff.Voices.length; idx < len; ++idx) {
-                let v: Voice = staff.Voices[idx];
+                const v: Voice = staff.Voices[idx];
                 v.Following = true;
             }
         } else {
             for (let idx: number = 0, len: number = staff.Voices.length; idx < len; ++idx) {
-                let voice: Voice = staff.Voices[idx];
+                const voice: Voice = staff.Voices[idx];
                 let isFollowingInOtherStaves: boolean = false;
                 for (let idx2: number = 0, len2: number = this.Staves.length; idx2 < len2; ++idx2) {
-                    let st: Staff = this.Staves[idx2];
+                    const st: Staff = this.Staves[idx2];
                     if (st.Id === staffId || !st.following) { continue; }
                     for (let idx3: number = 0, len3: number = st.Voices.length; idx3 < len3; ++idx3) {
-                        let v: Voice = st.Voices[idx3];
+                        const v: Voice = st.Voices[idx3];
                         if (v === voice) {
                             isFollowingInOtherStaves = true;
                         }
@@ -227,7 +227,7 @@ export class Instrument extends InstrumentalGroup {
         }
     }
     public areAllVoiceVisible(): boolean {
-        for (let voice of this.Voices) {
+        for (const voice of this.Voices) {
             if (!voice.Visible) {
                 return false;
             }

+ 37 - 14
src/MusicalScore/Interfaces/IGraphicalSymbolFactory.ts

@@ -1,34 +1,57 @@
+import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
+import {Fraction} from "../../Common/DataObjects/Fraction";
 import {GraphicalMusicPage} from "../Graphical/GraphicalMusicPage";
-import {MusicSystem} from "../Graphical/MusicSystem";
-import {Staff} from "../VoiceData/Staff";
-import {StaffLine} from "../Graphical/StaffLine";
-import {SourceMeasure} from "../VoiceData/SourceMeasure";
-import {StaffMeasure} from "../Graphical/StaffMeasure";
-import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
+import {GraphicalNote} from "../Graphical/GraphicalNote";
 import {GraphicalStaffEntry} from "../Graphical/GraphicalStaffEntry";
+import {MusicSystem} from "../Graphical/MusicSystem";
 import {Note} from "../VoiceData/Note";
-import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
 import {OctaveEnum} from "../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
-import {GraphicalNote} from "../Graphical/GraphicalNote";
 import {Pitch} from "../../Common/DataObjects/Pitch";
+import {SourceMeasure} from "../VoiceData/SourceMeasure";
+import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
+import {Staff} from "../VoiceData/Staff";
+import {StaffLine} from "../Graphical/StaffLine";
+import {StaffMeasure} from "../Graphical/StaffMeasure";
 import {TechnicalInstruction} from "../VoiceData/Instructions/TechnicalInstruction";
-import {Fraction} from "../../Common/DataObjects/Fraction";
+
 export interface IGraphicalSymbolFactory {
+
     createMusicSystem(page: GraphicalMusicPage, systemIndex: number): MusicSystem;
+
     createStaffLine(parentSystem: MusicSystem, parentStaff: Staff): StaffLine;
+
     createStaffMeasure(sourceMeasure: SourceMeasure, staff: Staff): StaffMeasure;
+
     createExtraStaffMeasure(staffLine: StaffLine): StaffMeasure;
+
     createStaffEntry(sourceStaffEntry: SourceStaffEntry, measure: StaffMeasure): GraphicalStaffEntry;
+
     createGraceStaffEntry(staffEntryParent: GraphicalStaffEntry, measure: StaffMeasure): GraphicalStaffEntry;
-    createNote(note: Note, graphicalStaffEntry: GraphicalStaffEntry, activeClef: ClefInstruction,
-        octaveShift: OctaveEnum, graphicalNoteLength: Fraction): GraphicalNote;
-    createGraceNote(note: Note, graphicalStaffEntry: GraphicalStaffEntry, activeClef: ClefInstruction,
+
+    createNote(
+        note: Note, graphicalStaffEntry: GraphicalStaffEntry,
+        activeClef: ClefInstruction,
+        octaveShift: OctaveEnum,
+        graphicalNoteLength: Fraction): GraphicalNote;
+
+    createGraceNote(
+        note: Note,
+        graphicalStaffEntry: GraphicalStaffEntry,
+        activeClef: ClefInstruction,
         octaveShift: OctaveEnum): GraphicalNote;
+
     addGraphicalAccidental(graphicalNote: GraphicalNote, pitch: Pitch, grace: boolean, graceScalingFactor: number): void;
+
     addFermataAtTiedEndNote(tiedNote: Note, graphicalStaffEntry: GraphicalStaffEntry): void;
-    createGraphicalTechnicalInstruction(technicalInstruction: TechnicalInstruction,
+
+    createGraphicalTechnicalInstruction(
+        technicalInstruction: TechnicalInstruction,
         graphicalStaffEntry: GraphicalStaffEntry): void;
+
     createInStaffClef(graphicalStaffEntry: GraphicalStaffEntry, clefInstruction: ClefInstruction): void;
-    createChordSymbol(sourceStaffEntry: SourceStaffEntry, graphicalStaffEntry: GraphicalStaffEntry,
+
+    createChordSymbol(
+        sourceStaffEntry: SourceStaffEntry,
+        graphicalStaffEntry: GraphicalStaffEntry,
         transposeHalftones: number): void;
 }

+ 4 - 4
src/MusicalScore/MusicParts/MusicPartManager.ts

@@ -36,7 +36,7 @@ export class MusicPartManager /*implements ISelectionListener*/ {
         if (this.timestamps.length === 0) {
             return timestamp;
         }
-        let transform: TimestampTransform = this.getCurrentRepetitionTimestampTransform(timestamp);
+        const transform: TimestampTransform = this.getCurrentRepetitionTimestampTransform(timestamp);
         return Fraction.plus(timestamp, Fraction.minus(transform.to, transform.$from)); // FIXME
     }
     public get Parts(): PartListEntry[] {
@@ -60,8 +60,8 @@ export class MusicPartManager /*implements ISelectionListener*/ {
         this.musicSheet.SelectionEnd = end === undefined ? this.sheetEnd : end;
     }
     private calcMapping(): void {
-        let timestamps: TimestampTransform[] = [];
-        let iterator: MusicPartManagerIterator = this.getIterator();
+        const timestamps: TimestampTransform[] = [];
+        const iterator: MusicPartManagerIterator = this.getIterator();
         let currentRepetition: Repetition = iterator.CurrentRepetition;
         let curTimestampTransform: TimestampTransform = new TimestampTransform(
             iterator.CurrentEnrolledTimestamp.clone(),
@@ -74,7 +74,7 @@ export class MusicPartManager /*implements ISelectionListener*/ {
             if (iterator.JumpOccurred || currentRepetition !== iterator.CurrentRepetition) {
                 currentRepetition = iterator.CurrentRepetition;
                 if (iterator.backJumpOccurred) {
-                    let jumpRep: Repetition = iterator.JumpResponsibleRepetition;
+                    const jumpRep: Repetition = iterator.JumpResponsibleRepetition;
                     curTimestampTransform.nextBackJump = iterator.CurrentEnrolledTimestamp;
                     curTimestampTransform.curRepetition = jumpRep;
                     curTimestampTransform.curRepetitionIteration = iterator.CurrentJumpResponsibleRepetitionIterationBeforeJump;

+ 34 - 34
src/MusicalScore/MusicParts/MusicPartManagerIterator.ts

@@ -23,7 +23,7 @@ export class MusicPartManagerIterator {
             this.manager = manager;
             this.currentVoiceEntries = undefined;
             this.frontReached = false;
-            for (let rep of manager.MusicSheet.Repetitions) {
+            for (const rep of manager.MusicSheet.Repetitions) {
                 this.setRepetitionIterationCount(rep, 1);
             }
             this.activeDynamicExpressions = new Array(manager.MusicSheet.getCompleteNumberOfStaves());
@@ -35,11 +35,11 @@ export class MusicPartManagerIterator {
             for (let staffIndex: number = 0; staffIndex < this.activeDynamicExpressions.length; staffIndex++) {
                 if (this.activeDynamicExpressions[staffIndex] !== undefined) {
                     if (this.activeDynamicExpressions[staffIndex] instanceof ContinuousDynamicExpression) {
-                        let continuousDynamic: ContinuousDynamicExpression =
+                        const continuousDynamic: ContinuousDynamicExpression =
                             <ContinuousDynamicExpression>this.activeDynamicExpressions[staffIndex];
                         this.currentDynamicChangingExpressions.push(new DynamicsContainer(continuousDynamic, staffIndex));
                     } else {
-                        let instantaniousDynamic: InstantaniousDynamicExpression =
+                        const instantaniousDynamic: InstantaniousDynamicExpression =
                             <InstantaniousDynamicExpression>this.activeDynamicExpressions[staffIndex];
                         this.currentDynamicChangingExpressions.push(new DynamicsContainer(instantaniousDynamic, staffIndex));
                     }
@@ -129,7 +129,7 @@ export class MusicPartManagerIterator {
         return this.jumpResponsibleRepetition;
     }
     public clone(): MusicPartManagerIterator {
-        let ret: MusicPartManagerIterator = new MusicPartManagerIterator(this.manager);
+        const ret: MusicPartManagerIterator = new MusicPartManagerIterator(this.manager);
         ret.currentVoiceEntryIndex = this.currentVoiceEntryIndex;
         ret.currentMappingPart = this.currentMappingPart;
         ret.currentPartIndex = this.currentPartIndex;
@@ -140,19 +140,19 @@ export class MusicPartManagerIterator {
     }
 
     public CurrentVisibleVoiceEntries(instrument?: Instrument): VoiceEntry[] {
-        let voiceEntries: VoiceEntry[] = [];
+        const voiceEntries: VoiceEntry[] = [];
         if (this.currentVoiceEntries === undefined) {
             return voiceEntries;
         }
         if (instrument !== undefined) {
-            for (let entry of this.currentVoiceEntries) {
+            for (const entry of this.currentVoiceEntries) {
                 if (entry.ParentVoice.Parent.IdString === instrument.IdString) {
                     this.getVisibleEntries(entry, voiceEntries);
                     return voiceEntries;
                 }
             }
         } else {
-            for (let entry of this.currentVoiceEntries) {
+            for (const entry of this.currentVoiceEntries) {
                 this.getVisibleEntries(entry, voiceEntries);
             }
         }
@@ -160,19 +160,19 @@ export class MusicPartManagerIterator {
     }
 
     public CurrentAudibleVoiceEntries(instrument?: Instrument): VoiceEntry[] {
-        let voiceEntries: VoiceEntry[] = [];
+        const voiceEntries: VoiceEntry[] = [];
         if (this.currentVoiceEntries === undefined) {
             return voiceEntries;
         }
         if (instrument !== undefined) {
-            for (let entry of this.currentVoiceEntries) {
+            for (const entry of this.currentVoiceEntries) {
                 if (entry.ParentVoice.Parent.IdString === instrument.IdString) {
                     this.getAudibleEntries(entry, voiceEntries);
                     return voiceEntries;
                 }
             }
         } else {
-            for (let entry of this.currentVoiceEntries) {
+            for (const entry of this.currentVoiceEntries) {
                 this.getAudibleEntries(entry, voiceEntries);
             }
         }
@@ -184,19 +184,19 @@ export class MusicPartManagerIterator {
     }
 
     public CurrentScoreFollowingVoiceEntries(instrument?: Instrument): VoiceEntry[] {
-        let voiceEntries: VoiceEntry[] = [];
+        const voiceEntries: VoiceEntry[] = [];
         if (this.currentVoiceEntries === undefined) {
             return voiceEntries;
         }
         if (instrument !== undefined) {
-            for (let entry of this.currentVoiceEntries) {
+            for (const entry of this.currentVoiceEntries) {
                 if (entry.ParentVoice.Parent.IdString === instrument.IdString) {
                     this.getScoreFollowingEntries(entry, voiceEntries);
                     return voiceEntries;
                 }
             }
         } else {
-            for (let entry of this.currentVoiceEntries) {
+            for (const entry of this.currentVoiceEntries) {
                 this.getScoreFollowingEntries(entry, voiceEntries);
             }
         }
@@ -235,7 +235,7 @@ export class MusicPartManagerIterator {
         }
     }
     private setRepetitionIterationCount(repetition: Repetition, iterationCount: number): number {
-        let i: number = this.repetitionIterationCountDictKeys.indexOf(repetition);
+        const i: number = this.repetitionIterationCountDictKeys.indexOf(repetition);
         if (i === -1) {
             this.repetitionIterationCountDictKeys.push(repetition);
             this.repetitionIterationCountDictValues.push(iterationCount);
@@ -245,7 +245,7 @@ export class MusicPartManagerIterator {
         return iterationCount;
     }
     private getRepetitionIterationCount(rep: Repetition): number {
-        let i: number = this.repetitionIterationCountDictKeys.indexOf(rep);
+        const i: number = this.repetitionIterationCountDictKeys.indexOf(rep);
         if (i !== -1) {
             return this.repetitionIterationCountDictValues[i];
         }
@@ -296,9 +296,9 @@ export class MusicPartManagerIterator {
     */
     private handleRepetitionsAtMeasureBegin(): void {
         for (let idx: number = 0, len: number = this.currentMeasure.FirstRepetitionInstructions.length; idx < len; ++idx) {
-            let repetitionInstruction: RepetitionInstruction = this.currentMeasure.FirstRepetitionInstructions[idx];
+            const repetitionInstruction: RepetitionInstruction = this.currentMeasure.FirstRepetitionInstructions[idx];
             if (repetitionInstruction.parentRepetition === undefined) { continue; }
-            let currentRepetition: Repetition = repetitionInstruction.parentRepetition;
+            const currentRepetition: Repetition = repetitionInstruction.parentRepetition;
             this.currentRepetition = currentRepetition;
             if (currentRepetition.StartIndex === this.currentMeasureIndex) {
                 if (
@@ -315,8 +315,8 @@ export class MusicPartManagerIterator {
 
     private handleRepetitionsAtMeasureEnd(): void {
         for (let idx: number = 0, len: number = this.currentMeasure.LastRepetitionInstructions.length; idx < len; ++idx) {
-            let repetitionInstruction: RepetitionInstruction = this.currentMeasure.LastRepetitionInstructions[idx];
-            let currentRepetition: Repetition = repetitionInstruction.parentRepetition;
+            const repetitionInstruction: RepetitionInstruction = this.currentMeasure.LastRepetitionInstructions[idx];
+            const currentRepetition: Repetition = repetitionInstruction.parentRepetition;
             if (currentRepetition === undefined) { continue; }
             if (currentRepetition.BackwardJumpInstructions.indexOf(repetitionInstruction) > -1) {
                 if (this.getRepetitionIterationCount(currentRepetition) < currentRepetition.UserNumberOfRepetitions) {
@@ -335,7 +335,7 @@ export class MusicPartManagerIterator {
                     this.resetRepetitionIterationCount(currentRepetition);
                 }
 
-                let forwardJumpTargetMeasureIndex: number = currentRepetition.getForwardJumpTargetForIteration(
+                const forwardJumpTargetMeasureIndex: number = currentRepetition.getForwardJumpTargetForIteration(
                   this.getRepetitionIterationCount(currentRepetition)
                 );
                 if (forwardJumpTargetMeasureIndex >= 0) {
@@ -369,9 +369,9 @@ export class MusicPartManagerIterator {
           this.currentMeasure.FirstInstructionsStaffEntries.length > 0 &&
           this.currentMeasure.FirstInstructionsStaffEntries[0] !== undefined
         ) {
-            let instructions: AbstractNotationInstruction[] = this.currentMeasure.FirstInstructionsStaffEntries[0].Instructions;
+            const instructions: AbstractNotationInstruction[] = this.currentMeasure.FirstInstructionsStaffEntries[0].Instructions;
             for (let idx: number = 0, len: number = instructions.length; idx < len; ++idx) {
-                let abstractNotationInstruction: AbstractNotationInstruction = instructions[idx];
+                const abstractNotationInstruction: AbstractNotationInstruction = instructions[idx];
                 if (abstractNotationInstruction instanceof RhythmInstruction) {
                     this.manager.MusicSheet.SheetPlaybackSetting.rhythm = (<RhythmInstruction>abstractNotationInstruction).Rhythm;
                 }
@@ -379,7 +379,7 @@ export class MusicPartManagerIterator {
         }
     }
     private activateCurrentDynamicOrTempoInstructions(): void {
-        let timeSortedDynamics: DynamicsContainer[] = this.manager.MusicSheet.TimestampSortedDynamicExpressionsList;
+        const timeSortedDynamics: DynamicsContainer[] = this.manager.MusicSheet.TimestampSortedDynamicExpressionsList;
         while (
           this.currentDynamicEntryIndex > 0 && (
             this.currentDynamicEntryIndex >= timeSortedDynamics.length ||
@@ -398,8 +398,8 @@ export class MusicPartManagerIterator {
           this.currentDynamicEntryIndex < timeSortedDynamics.length
           && timeSortedDynamics[this.currentDynamicEntryIndex].parMultiExpression().AbsoluteTimestamp.Equals(this.CurrentSourceTimestamp)
         ) {
-            let dynamicsContainer: DynamicsContainer = timeSortedDynamics[this.currentDynamicEntryIndex];
-            let staffIndex: number = dynamicsContainer.staffNumber;
+            const dynamicsContainer: DynamicsContainer = timeSortedDynamics[this.currentDynamicEntryIndex];
+            const staffIndex: number = dynamicsContainer.staffNumber;
             if (this.CurrentSourceTimestamp.Equals(dynamicsContainer.parMultiExpression().AbsoluteTimestamp)) {
                 if (dynamicsContainer.continuousDynamicExpression !== undefined) {
                     this.activeDynamicExpressions[staffIndex] = dynamicsContainer.continuousDynamicExpression;
@@ -415,21 +415,21 @@ export class MusicPartManagerIterator {
                 let startTime: Fraction;
                 let endTime: Fraction;
                 if (this.activeDynamicExpressions[staffIndex] instanceof ContinuousDynamicExpression) {
-                    let continuousDynamic: ContinuousDynamicExpression = <ContinuousDynamicExpression>this.activeDynamicExpressions[staffIndex];
+                    const continuousDynamic: ContinuousDynamicExpression = <ContinuousDynamicExpression>this.activeDynamicExpressions[staffIndex];
                     startTime = continuousDynamic.StartMultiExpression.AbsoluteTimestamp;
                     endTime = continuousDynamic.EndMultiExpression.AbsoluteTimestamp;
                     if (startTime.lte(this.CurrentSourceTimestamp) && this.CurrentSourceTimestamp.lte(endTime)) {
                         this.currentDynamicChangingExpressions.push(new DynamicsContainer(continuousDynamic, staffIndex));
                     }
                 } else {
-                    let instantaniousDynamic: InstantaniousDynamicExpression = <InstantaniousDynamicExpression>this.activeDynamicExpressions[staffIndex];
+                    const instantaniousDynamic: InstantaniousDynamicExpression = <InstantaniousDynamicExpression>this.activeDynamicExpressions[staffIndex];
                     if (this.CurrentSourceTimestamp.Equals(instantaniousDynamic.ParentMultiExpression.AbsoluteTimestamp)) {
                         this.currentDynamicChangingExpressions.push(new DynamicsContainer(instantaniousDynamic, staffIndex));
                     }
                 }
             }
         }
-        let timeSortedTempoExpressions: MultiTempoExpression[] = this.manager.MusicSheet.TimestampSortedTempoExpressionsList;
+        const timeSortedTempoExpressions: MultiTempoExpression[] = this.manager.MusicSheet.TimestampSortedTempoExpressionsList;
 
         while (this.currentTempoEntryIndex > 0 && (
           this.currentTempoEntryIndex >= timeSortedTempoExpressions.length
@@ -472,7 +472,7 @@ export class MusicPartManagerIterator {
             this.activateCurrentRhythmInstructions();
         }
         if (this.currentVoiceEntryIndex >= 0 && this.currentVoiceEntryIndex < this.currentMeasure.VerticalSourceStaffEntryContainers.length) {
-            let currentContainer: VerticalSourceStaffEntryContainer = this.currentMeasure.VerticalSourceStaffEntryContainers[this.currentVoiceEntryIndex];
+            const currentContainer: VerticalSourceStaffEntryContainer = this.currentMeasure.VerticalSourceStaffEntryContainers[this.currentVoiceEntryIndex];
             this.currentVoiceEntries = this.getVoiceEntries(currentContainer);
             this.currentVerticalContainerInMeasureTimestamp = currentContainer.Timestamp;
             this.currentTimeStamp = Fraction.plus(this.currentMeasure.AbsoluteTimestamp, this.currentVerticalContainerInMeasureTimestamp);
@@ -497,11 +497,11 @@ export class MusicPartManagerIterator {
         this.endReached = true;
     }
     private checkEntries(notesOnly: boolean): boolean {
-        let tlist: VoiceEntry[] = this.CurrentVisibleVoiceEntries();
+        const tlist: VoiceEntry[] = this.CurrentVisibleVoiceEntries();
         if (tlist.length > 0) {
             if (!notesOnly) { return true; }
             for (let idx: number = 0, len: number = tlist.length; idx < len; ++idx) {
-                let entry: VoiceEntry = tlist[idx];
+                const entry: VoiceEntry = tlist[idx];
                 if (entry.Notes[0].Pitch !== undefined) { return true; }
             }
         }
@@ -523,10 +523,10 @@ export class MusicPartManagerIterator {
         }
     }
     private getVoiceEntries(container: VerticalSourceStaffEntryContainer): VoiceEntry[] {
-        let entries: VoiceEntry[] = [];
-        for (let sourceStaffEntry of container.StaffEntries) {
+        const entries: VoiceEntry[] = [];
+        for (const sourceStaffEntry of container.StaffEntries) {
             if (sourceStaffEntry === undefined) { continue; }
-            for (let voiceEntry of sourceStaffEntry.VoiceEntries) {
+            for (const voiceEntry of sourceStaffEntry.VoiceEntries) {
                 entries.push(voiceEntry);
             }
         }

+ 19 - 19
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);
@@ -235,9 +235,9 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
     }
     public checkForInstrumentWithNoVoice(): void {
         for (let idx: number = 0, len: number = this.instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = this.instruments[idx];
+            const instrument: Instrument = this.instruments[idx];
             if (instrument.Voices.length === 0) {
-                let voice: Voice = new Voice(instrument, 1);
+                const voice: Voice = new Voice(instrument, 1);
                 instrument.Voices.push(voice);
             }
         }
@@ -254,9 +254,9 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
     public fillStaffList(): void {
         let i: number = 0;
         for (let idx: number = 0, len: number = this.instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = this.instruments[idx];
+            const instrument: Instrument = this.instruments[idx];
             for (let idx2: number = 0, len2: number = instrument.Staves.length; idx2 < len2; ++idx2) {
-                let staff: Staff = instrument.Staves[idx2];
+                const staff: Staff = instrument.Staves[idx2];
                 staff.idInMusicSheet = i;
                 this.staves.push(staff);
                 i++;
@@ -272,7 +272,7 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
     public getCompleteNumberOfStaves(): number {
         let num: number = 0;
         for (let idx: number = 0, len: number = this.instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = this.instruments[idx];
+            const instrument: Instrument = this.instruments[idx];
             num += instrument.Staves.length;
         }
         return num;
@@ -285,14 +285,14 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
      * @returns {SourceMeasure[]}
      */
     public getListOfMeasuresFromIndeces(start: number, end: number): SourceMeasure[] {
-        let measures: SourceMeasure[] = [];
+        const measures: SourceMeasure[] = [];
         for (let i: number = start; i <= end; i++) {
             measures.push(this.sourceMeasures[i]);
         }
         return measures;
     }
     public getNextSourceMeasure(measure: SourceMeasure): SourceMeasure {
-        let index: number = this.sourceMeasures.indexOf(measure);
+        const index: number = this.sourceMeasures.indexOf(measure);
         if (index === this.sourceMeasures.length - 1) {
             return measure;
         }
@@ -305,12 +305,12 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
         return this.sourceMeasures[this.sourceMeasures.length - 1];
     }
     public resetAllNoteStates(): void {
-       let iterator: MusicPartManagerIterator = this.MusicPartManager.getIterator();
+       const iterator: MusicPartManagerIterator = this.MusicPartManager.getIterator();
        while (!iterator.EndReached && iterator.CurrentVoiceEntries !== undefined) {
            for (let idx: number = 0, len: number = iterator.CurrentVoiceEntries.length; idx < len; ++idx) {
-               let voiceEntry: VoiceEntry = iterator.CurrentVoiceEntries[idx];
+               const voiceEntry: VoiceEntry = iterator.CurrentVoiceEntries[idx];
                for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) {
-                   let note: Note = voiceEntry.Notes[idx2];
+                   const note: Note = voiceEntry.Notes[idx2];
                    note.state = NoteState.Normal;
                }
            }
@@ -321,7 +321,7 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
         return this.Instruments.indexOf(instrument);
     }
     public getGlobalStaffIndexOfFirstStaff(instrument: Instrument): number {
-        let instrumentIndex: number = this.getMusicSheetInstrumentIndex(instrument);
+        const instrumentIndex: number = this.getMusicSheetInstrumentIndex(instrument);
         let staffLineIndex: number = 0;
         for (let i: number = 0; i < instrumentIndex; i++) {
             staffLineIndex += this.Instruments[i].Staves.length;
@@ -481,11 +481,11 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
     //    }
     // }
     public getEnrolledSelectionStartTimeStampWorkaround(): Fraction {
-        let iter: MusicPartManagerIterator = this.MusicPartManager.getIterator(this.SelectionStart);
+        const iter: MusicPartManagerIterator = this.MusicPartManager.getIterator(this.SelectionStart);
         return Fraction.createFromFraction(iter.CurrentEnrolledTimestamp);
     }
     public get SheetEndTimestamp(): Fraction {
-        let lastMeasure: SourceMeasure = this.getLastSourceMeasure();
+        const lastMeasure: SourceMeasure = this.getLastSourceMeasure();
         return Fraction.plus(lastMeasure.AbsoluteTimestamp, lastMeasure.Duration);
     }
 
@@ -496,9 +496,9 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
      */
     public getSourceMeasureFromTimeStamp(timeStamp: Fraction): SourceMeasure {
         for (let idx: number = 0, len: number = this.sourceMeasures.length; idx < len; ++idx) {
-            let sm: SourceMeasure = this.sourceMeasures[idx];
+            const sm: SourceMeasure = this.sourceMeasures[idx];
             for (let idx2: number = 0, len2: number = sm.VerticalSourceStaffEntryContainers.length; idx2 < len2; ++idx2) {
-                let vssec: VerticalSourceStaffEntryContainer = sm.VerticalSourceStaffEntryContainers[idx2];
+                const vssec: VerticalSourceStaffEntryContainer = sm.VerticalSourceStaffEntryContainers[idx2];
                 if (timeStamp.Equals(vssec.getAbsoluteTimestamp())) {
                     return sm;
                 }
@@ -507,7 +507,7 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
         return this.findSourceMeasureFromTimeStamp(timeStamp);
     }
     public findSourceMeasureFromTimeStamp(timestamp: Fraction): SourceMeasure {
-        for (let sm of this.sourceMeasures) {
+        for (const sm of this.sourceMeasures) {
             if (sm.AbsoluteTimestamp.lte(timestamp) && timestamp.lt(Fraction.plus(sm.AbsoluteTimestamp, sm.Duration))) {
                 return sm;
             }
@@ -515,9 +515,9 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
     }
 
     public getVisibleInstruments(): Instrument[] {
-        let visInstruments: Instrument[] = [];
+        const visInstruments: Instrument[] = [];
         for (let idx: number = 0, len: number = this.Instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = this.Instruments[idx];
+            const instrument: Instrument = this.Instruments[idx];
             if (instrument.Voices.length > 0 && instrument.Voices[0].Visible) {
                 visInstruments.push(instrument);
             }

+ 9 - 9
src/MusicalScore/MusicSource/Repetition.ts

@@ -54,7 +54,7 @@ export class Repetition extends PartListEntry /*implements IRepetition*/ {
     public set UserNumberOfRepetitions(value: number) {
         this.userNumberOfRepetitions = value;
         this.repetitonIterationOrder = [];
-        let endingsDiff: number = this.userNumberOfRepetitions - this.NumberOfEndings;
+        const endingsDiff: number = this.userNumberOfRepetitions - this.NumberOfEndings;
         for (let i: number = 1; i <= this.userNumberOfRepetitions; i++) {
             if (i <= endingsDiff) {
                 this.repetitonIterationOrder.push(1);
@@ -64,7 +64,7 @@ export class Repetition extends PartListEntry /*implements IRepetition*/ {
         }
     }
     public getForwardJumpTargetForIteration(iteration: number): number {
-        let endingIndex: number = this.repetitonIterationOrder[iteration - 1];
+        const endingIndex: number = this.repetitonIterationOrder[iteration - 1];
         if (this.endingIndexDict[endingIndex] !== undefined) {
             return this.endingIndexDict[endingIndex].part.StartIndex;
         }
@@ -74,9 +74,9 @@ export class Repetition extends PartListEntry /*implements IRepetition*/ {
         return this.startMarker.measureIndex;
     }
     public SetEndingStartIndex(endingNumbers: number[], startIndex: number): void {
-        let part: RepetitionEndingPart = new RepetitionEndingPart(new SourceMusicPart(this.musicSheet2, startIndex, startIndex));
+        const part: RepetitionEndingPart = new RepetitionEndingPart(new SourceMusicPart(this.musicSheet2, startIndex, startIndex));
         this.endingParts.push(part);
-        for (let endingNumber of endingNumbers) {
+        for (const endingNumber of endingNumbers) {
             try {
                 this.endingIndexDict[endingNumber] = part;
                 part.endingIndices.push(endingNumber);
@@ -130,15 +130,15 @@ export class Repetition extends PartListEntry /*implements IRepetition*/ {
     }
     private checkRepetitionForMultipleLyricVerses(): number {
         let lyricVerses: number = 0;
-        let start: number = this.StartIndex;
-        let end: number = this.EndIndex;
+        const start: number = this.StartIndex;
+        const end: number = this.EndIndex;
         for (let measureIndex: number = start; measureIndex <= end; measureIndex++) {
-            let sourceMeasure: SourceMeasure = this.musicSheet2.SourceMeasures[measureIndex];
+            const sourceMeasure: SourceMeasure = this.musicSheet2.SourceMeasures[measureIndex];
             for (let i: number = 0; i < sourceMeasure.CompleteNumberOfStaves; i++) {
-                for (let sourceStaffEntry of sourceMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries) {
+                for (const sourceStaffEntry of sourceMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries) {
                     if (sourceStaffEntry !== undefined) {
                         let verses: number = 0;
-                        for (let voiceEntry of sourceStaffEntry.VoiceEntries) {
+                        for (const voiceEntry of sourceStaffEntry.VoiceEntries) {
                             verses += Object.keys(voiceEntry.LyricsEntries).length;
                         }
                         lyricVerses = Math.max(lyricVerses, verses);

+ 962 - 961
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
@@ -46,7 +47,7 @@ import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
 /**
  * To be implemented
  */
-export type repetitionInstructionReader = any;
+export type RepetitionInstructionReader = any;
 
 /**
  * An InstrumentReader is used during the reading phase to keep parsing new measures from the MusicXML file
@@ -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);
-    }
+  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;
+  // 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 ActiveKey(): KeyInstruction {
+    return this.activeKey;
+  }
 
-    public get MaxTieNoteFraction(): Fraction {
-        return this.maxTieNoteFraction;
-    }
+  public get MaxTieNoteFraction(): Fraction {
+    return this.maxTieNoteFraction;
+  }
 
-    public get ActiveRhythm(): RhythmInstruction {
-        return this.activeRhythm;
-    }
+  public get ActiveRhythm(): RhythmInstruction {
+    return this.activeRhythm;
+  }
 
-    public set ActiveRhythm(value: RhythmInstruction) {
-        this.activeRhythm = value;
-    }
+  public set ActiveRhythm(value: RhythmInstruction) {
+    this.activeRhythm = value;
+  }
 
-    /**
-     * 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;
-                            }
-                        }
-                    }
-
-                    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;
-                        }
-                    }
-
-                    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);
-
-                    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);
-                            }
-                        }
-
-                    }
-                    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 {
+      const xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[this.currentXmlMeasureIndex].elements();
+      for (const 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];
+          const isChord: boolean = xmlNode.element("chord") !== undefined;
+          if (xmlNode.element("voice") !== undefined) {
+            const 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 {
+              const 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;
-    }
+          const restNote: boolean = xmlNode.element("rest") !== undefined;
+          //Logging.log("New note found!", noteDivisions, noteDuration.toString(), restNote);
+          const 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
+            );
+          }
+          const 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
+            );
+          }
+          const 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") {
+          const divisionsNode: IXmlElement = xmlNode.element("divisions");
+          if (divisionsNode !== undefined) {
+            this.divisions = parseInt(divisionsNode.value, 10);
+            if (isNaN(this.divisions)) {
+              const 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
+          ) {
+            const 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") {
+          const forFraction: number = parseInt(xmlNode.element("duration").value, 10);
+          currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
+        } else if (xmlNode.name === "backup") {
+          const 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);
         }
-        return voiceGenerator;
+      }
+      for (const j in this.voiceGeneratorsDict) {
+        if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
+          const voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[j];
+          voiceGenerator.checkForOpenBeam();
+          voiceGenerator.checkForOpenGraceNotes();
+        }
+      }
+      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);
+      }
+      const 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 (const 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 {
+    const 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 {
+      const 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;
+  }
+
+
+  //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;
+    }
+    const 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];
+  /**
+   * 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;
+    }
+    const 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) {
+        const firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+        first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+        keyInstruction.Parent = firstStaffEntry;
+        firstStaffEntry.Instructions.push(keyInstruction);
+      } else {
+        const 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 {
+    const children: IXmlElement[] = parentNode.elements();
+    const 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 {
+    const 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) {
+      const typeNode: IXmlElement = xmlNode.element("type");
+      if (typeNode !== undefined) {
+        const 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;
+      }
+    }
+    const transposeNode: IXmlElement = node.element("transpose");
+    if (transposeNode !== undefined) {
+      const chromaticNode: IXmlElement = transposeNode.element("chromatic");
+      if (chromaticNode !== undefined) {
+        this.instrument.PlaybackTranspose = parseInt(chromaticNode.value, 10);
+      }
+    }
+    const clefList: IXmlElement[] = node.elements("clef");
+    let errorMsg: string;
+    if (clefList.length > 0) {
+      for (let idx: number = 0, len: number = clefList.length; idx < len; ++idx) {
+        const nodeList: IXmlElement = clefList[idx];
+        let clefEnum: ClefEnum = ClefEnum.G;
+        let line: number = 2;
+        let staffNumber: number = 1;
+        let clefOctaveOffset: number = 0;
+        const 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);
+        const 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;
-                    }
+        }
+        const 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]);
-            }
+        const 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;
+      const 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]);
+      }
+      const keyInstruction: KeyInstruction = new KeyInstruction(undefined, key, keyEnum);
+      this.abstractInstructions.push([1, keyInstruction]);
+    }
+    if (node.element("time") !== undefined) {
+      let symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
+      const timeNode: IXmlElement = node.element("time");
+      if (timeNode !== undefined && timeNode.hasAttributes) {
+        const 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;
+      const senzaMisura: boolean = (timeNode !== undefined && timeNode.element("senza-misura") !== undefined);
+      const timeList: IXmlElement[] = node.elements("time");
+      const beatsList: IXmlElement[] = [];
+      const typeList: IXmlElement[] = [];
+      for (let idx: number = 0, len: number = timeList.length; idx < len; ++idx) {
+        const 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) {
+            const length: number = beatsList.length;
+            const fractions: Fraction[] = new Array(length);
+            let maxDenom: number = 0;
+            for (let i: number = 0; i < length; i++) {
+              const s: string = beatsList[i].value;
+              let n: number = 0;
+              let d: number = 0;
+              if (s.indexOf("+") !== -1) {
+                const 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--) {
+      const pair: [number, AbstractNotationInstruction] = this.abstractInstructions[i];
+      const key: number = pair[0];
+      const value: AbstractNotationInstruction = pair[1];
+      if (value instanceof ClefInstruction) {
+        const 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)) {
+            const 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) {
+              const newClefInstruction: ClefInstruction = clefInstruction;
+              const sseIndex: number = this.inSourceMeasureInstrumentIndex + key - 1;
+              const 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 {
+                  const 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]) {
+                const 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 {
+                const 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);
             }
-            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 if (key <= this.activeClefs.length && clefInstruction === this.activeClefs[key - 1]) {
+          this.abstractInstructions.splice(i, 1);
+        }
+      }
+      if (value instanceof KeyInstruction) {
+        const 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++) {
+              const newKeyInstruction: KeyInstruction = keyInstruction;
+              if (sourceMeasure.FirstInstructionsStaffEntries[j] === undefined) {
+                const firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+                sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+                newKeyInstruction.Parent = firstStaffEntry;
+                firstStaffEntry.Instructions.push(newKeyInstruction);
+              } else {
+                const 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) {
+        const 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++) {
+              const 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--) {
+      const key: number = this.abstractInstructions[i][0];
+      const value: AbstractNotationInstruction = this.abstractInstructions[i][1];
+      if (value instanceof ClefInstruction) {
+        const 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
+          ))) {
+          const lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
+          this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
+          const 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);
+    const typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
+    if (xmlNode.element("time-modification") !== undefined) {
+      const time: IXmlElement = xmlNode.element("time-modification");
+      if (time !== undefined) {
+        if (time.element("actual-notes") !== undefined && time.element("normal-notes") !== undefined) {
+          const actualNotes: IXmlElement = time.element("actual-notes");
+          const normalNotes: IXmlElement = time.element("normal-notes");
+          if (actualNotes !== undefined && normalNotes !== undefined) {
+            const actual: number = parseInt(actualNotes.value, 10);
+            const 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) {
+      const xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].elements();
+      for (let idx: number = 0, len: number = xmlMeasureListArr.length; idx < len; ++idx) {
+        const xmlNode: IXmlElement = xmlMeasureListArr[idx];
+        if (xmlNode.name === "note" && xmlNode.element("time-modification") === undefined) {
+          if (xmlNode.element("duration") !== undefined && xmlNode.element("type") !== undefined) {
+            const durationNode: IXmlElement = xmlNode.element("duration");
+            const typeNode: IXmlElement = xmlNode.element("type");
+            if (durationNode !== undefined && typeNode !== undefined) {
+              const 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) {
+          const errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
+          throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
         }
-        return divisionsFromNote;
+      }
     }
+    return divisionsFromNote;
+  }
 }

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

@@ -48,7 +48,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     }
 
     private static doCalculationsAfterDurationHasBeenSet(instrumentReaders: InstrumentReader[]): void {
-        for (let instrumentReader of instrumentReaders) {
+        for (const instrumentReader of instrumentReaders) {
             instrumentReader.doCalculationsAfterDurationHasBeenSet();
         }
     }
@@ -68,7 +68,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     }
 
     private _removeFromArray(list: any[], elem: any): void {
-        let i: number = list.indexOf(elem);
+        const i: number = list.indexOf(elem);
         if (i !== -1) {
             list.splice(i, 1);
         }
@@ -111,7 +111,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     //}
 
     private _createMusicSheet(root: IXmlElement, path: string): MusicSheet {
-        let instrumentReaders: InstrumentReader[] = [];
+        const instrumentReaders: InstrumentReader[] = [];
         let sourceMeasureCounter: number = 0;
         this.musicSheet = new MusicSheet();
         this.musicSheet.Path = path;
@@ -119,13 +119,13 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             throw new MusicSheetReadingException("Undefined root element");
         }
         this.pushSheetLabels(root, path);
-        let partlistNode: IXmlElement = root.element("part-list");
+        const partlistNode: IXmlElement = root.element("part-list");
         if (partlistNode === undefined) {
             throw new MusicSheetReadingException("Undefined partListNode");
         }
 
-        let partInst: IXmlElement[] = root.elements("part");
-        let partList: IXmlElement[] = partlistNode.elements();
+        const partInst: IXmlElement[] = root.elements("part");
+        const partList: IXmlElement[] = partlistNode.elements();
         this.initializeReading(partList, partInst, instrumentReaders);
         let couldReadMeasure: boolean = true;
         this.currentFraction = new Fraction(0, 1);
@@ -146,11 +146,11 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                 sourceMeasureCounter = 0;
             }
             this.currentMeasure = new SourceMeasure(this.completeNumberOfStaves);
-            for (let instrumentReader of instrumentReaders) {
+            for (const instrumentReader of instrumentReaders) {
                 try {
                     couldReadMeasure = couldReadMeasure && instrumentReader.readNextXmlMeasure(this.currentMeasure, this.currentFraction, guitarPro);
                 } catch (e) {
-                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/InstrumentError", "Error while reading instruments.");
+                    const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/InstrumentError", "Error while reading instruments.");
                     throw new MusicSheetReadingException(errorMsg, e);
                 }
 
@@ -178,7 +178,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         this.musicSheet.fillStaffList();
         //this.musicSheet.DefaultStartTempoInBpm = this.musicSheet.SheetPlaybackSetting.BeatsPerMinute;
         for (let idx: number = 0, len: number = this.afterSheetReadingModules.length; idx < len; ++idx) {
-         let afterSheetReadingModule: IAfterSheetReadingModule = this.afterSheetReadingModules[idx];
+         const afterSheetReadingModule: IAfterSheetReadingModule = this.afterSheetReadingModules[idx];
          afterSheetReadingModule.calculate(this.musicSheet);
         }
 
@@ -186,7 +186,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     }
 
     private initializeReading(partList: IXmlElement[], partInst: IXmlElement[], instrumentReaders: InstrumentReader[]): void {
-        let instrumentDict: { [_: string]: Instrument; } = this.createInstrumentGroups(partList);
+        const instrumentDict: { [_: string]: Instrument; } = this.createInstrumentGroups(partList);
         this.completeNumberOfStaves = this.getCompleteNumberOfStavesFromXml(partInst);
         if (partInst.length !== 0) {
             this.repetitionInstructionReader.MusicSheet = this.musicSheet;
@@ -195,16 +195,16 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             this.previousMeasure = undefined;
         }
         let counter: number = 0;
-        for (let node of partInst) {
-            let idNode: IXmlAttribute = node.attribute("id");
+        for (const node of partInst) {
+            const idNode: IXmlAttribute = node.attribute("id");
             if (idNode) {
-                let currentInstrument: Instrument = instrumentDict[idNode.value];
-                let xmlMeasureList: IXmlElement[] = node.elements("measure");
+                const currentInstrument: Instrument = instrumentDict[idNode.value];
+                const xmlMeasureList: IXmlElement[] = node.elements("measure");
                 let instrumentNumberOfStaves: number = 1;
                 try {
                     instrumentNumberOfStaves = this.getInstrumentNumberOfStavesFromXml(node);
                 } catch (err) {
-                    let errorMsg: string = ITextTranslation.translateText(
+                    const errorMsg: string = ITextTranslation.translateText(
                         "ReaderErrorMessages/InstrumentStavesNumberError",
                         "Invalid number of staves at instrument: "
                     );
@@ -230,10 +230,10 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
      * @param instrumentReaders
      */
     private checkIfRhythmInstructionsAreSetAndEqual(instrumentReaders: InstrumentReader[]): void {
-        let rhythmInstructions: RhythmInstruction[] = [];
+        const rhythmInstructions: RhythmInstruction[] = [];
         for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
             if (this.currentMeasure.FirstInstructionsStaffEntries[i] !== undefined) {
-                let last: AbstractNotationInstruction = this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions[
+                const last: AbstractNotationInstruction = this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions[
                 this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.length - 1
                     ];
                 if (last instanceof RhythmInstruction) {
@@ -244,7 +244,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         let maxRhythmValue: number = 0.0;
         let index: number = -1;
         for (let idx: number = 0, len: number = rhythmInstructions.length; idx < len; ++idx) {
-            let rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
+            const rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
             if (rhythmInstruction.Rhythm.RealValue > maxRhythmValue) {
                 if (this.areRhythmInstructionsMixed(rhythmInstructions) && rhythmInstruction.SymbolEnum !== RhythmSymbolEnum.NONE) {
                     continue;
@@ -254,7 +254,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             }
         }
         if (rhythmInstructions.length > 0 && rhythmInstructions.length < this.completeNumberOfStaves) {
-            let rhythmInstruction: RhythmInstruction = rhythmInstructions[index].clone();
+            const rhythmInstruction: RhythmInstruction = rhythmInstructions[index].clone();
             for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
                 if (
                     this.currentMeasure.FirstInstructionsStaffEntries[i] !== undefined &&
@@ -269,12 +269,12 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                 }
             }
             for (let idx: number = 0, len: number = instrumentReaders.length; idx < len; ++idx) {
-                let instrumentReader: InstrumentReader = instrumentReaders[idx];
+                const instrumentReader: InstrumentReader = instrumentReaders[idx];
                 instrumentReader.ActiveRhythm = rhythmInstruction;
             }
         }
         if (rhythmInstructions.length === 0 && this.currentMeasure === this.musicSheet.SourceMeasures[0]) {
-            let rhythmInstruction: RhythmInstruction = new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE);
+            const 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);
@@ -284,18 +284,18 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                 this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.push(rhythmInstruction);
             }
             for (let idx: number = 0, len: number = instrumentReaders.length; idx < len; ++idx) {
-                let instrumentReader: InstrumentReader = instrumentReaders[idx];
+                const instrumentReader: InstrumentReader = instrumentReaders[idx];
                 instrumentReader.ActiveRhythm = rhythmInstruction;
             }
         }
         for (let idx: number = 0, len: number = rhythmInstructions.length; idx < len; ++idx) {
-            let rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
+            const rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
             if (rhythmInstruction.Rhythm.RealValue < maxRhythmValue) {
                 if (this._lastElement(
                         this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.indexOf(rhythmInstruction)].Instructions
                     ) instanceof RhythmInstruction) {
                     // TODO Test correctness
-                    let instrs: AbstractNotationInstruction[] =
+                    const instrs: AbstractNotationInstruction[] =
                         this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.indexOf(rhythmInstruction)].Instructions;
                     instrs[instrs.length - 1] = rhythmInstructions[index].clone();
                 }
@@ -335,17 +335,17 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
      */
     private setSourceMeasureDuration(instrumentReaders: InstrumentReader[], sourceMeasureCounter: number): number {
         let activeRhythm: Fraction = new Fraction(0, 1);
-        let instrumentsMaxTieNoteFractions: Fraction[] = [];
-        for (let instrumentReader of instrumentReaders) {
+        const instrumentsMaxTieNoteFractions: Fraction[] = [];
+        for (const instrumentReader of instrumentReaders) {
             instrumentsMaxTieNoteFractions.push(instrumentReader.MaxTieNoteFraction);
-            let activeRythmMeasure: Fraction = instrumentReader.ActiveRhythm.Rhythm;
+            const 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);
+        const instrumentsDurations: Fraction[] = this.currentMeasure.calculateInstrumentsDuration(this.musicSheet, instrumentsMaxTieNoteFractions);
         let maxInstrumentDuration: Fraction = new Fraction(0, 1);
-        for (let instrumentsDuration of instrumentsDurations) {
+        for (const instrumentsDuration of instrumentsDurations) {
             if (maxInstrumentDuration.lt(instrumentsDuration)) {
                 maxInstrumentDuration = instrumentsDuration;
             }
@@ -365,18 +365,18 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         this.currentMeasure.Duration = maxInstrumentDuration;
         this.currentMeasure.MeasureNumber = sourceMeasureCounter;
         for (let i: number = 0; i < instrumentsDurations.length; i++) {
-            let instrumentsDuration: Fraction = instrumentsDurations[i];
+            const instrumentsDuration: Fraction = instrumentsDurations[i];
             if (
                 (this.currentMeasure.ImplicitMeasure && instrumentsDuration !== maxInstrumentDuration) ||
                 !Fraction.Equal(instrumentsDuration, activeRhythm) &&
                 !this.allInstrumentsHaveSameDuration(instrumentsDurations, maxInstrumentDuration)
             ) {
-                let firstStaffIndexOfInstrument: number = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.musicSheet.Instruments[i]);
+                const firstStaffIndexOfInstrument: number = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.musicSheet.Instruments[i]);
                 for (let staffIndex: number = 0; staffIndex < this.musicSheet.Instruments[i].Staves.length; staffIndex++) {
                     if (!this.staffMeasureIsEmpty(firstStaffIndexOfInstrument + staffIndex)) {
                         this.currentMeasure.setErrorInStaffMeasure(firstStaffIndexOfInstrument + staffIndex, true);
-                        let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MissingNotesError",
-                                                                              "Given Notes don't correspond to measure duration.");
+                        const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MissingNotesError",
+                                                                                "Given Notes don't correspond to measure duration.");
                         this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
                     }
                 }
@@ -394,8 +394,8 @@ 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);
+            const factor: number = activeRhythm.Denominator / maxInstrumentDuration.Denominator;
+            maxInstrumentDuration.expand(factor);
         }
     }
 
@@ -424,7 +424,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     private allInstrumentsHaveSameDuration(instrumentsDurations: Fraction[], maxInstrumentDuration: Fraction): boolean {
         let counter: number = 0;
         for (let idx: number = 0, len: number = instrumentsDurations.length; idx < len; ++idx) {
-            let instrumentsDuration: Fraction = instrumentsDurations[idx];
+            const instrumentsDuration: Fraction = instrumentsDurations[idx];
             if (instrumentsDuration.Equals(maxInstrumentDuration)) {
                 counter++;
             }
@@ -449,10 +449,10 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     private checkSourceMeasureForNullEntries(): void {
         for (let i: number = this.currentMeasure.VerticalSourceStaffEntryContainers.length - 1; i >= 0; i--) {
             for (let j: number = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.length - 1; j >= 0; j--) {
-                let sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[j];
+                const sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[j];
                 if (sourceStaffEntry !== undefined) {
                     for (let k: number = sourceStaffEntry.VoiceEntries.length - 1; k >= 0; k--) {
-                        let voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[k];
+                        const voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[k];
                         if (voiceEntry.Notes.length === 0) {
                             this._removeFromArray(voiceEntry.ParentVoice.VoiceEntries, voiceEntry);
                             this._removeFromArray(sourceStaffEntry.VoiceEntries, voiceEntry);
@@ -467,7 +467,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         for (let i: number = this.currentMeasure.VerticalSourceStaffEntryContainers.length - 1; i >= 0; i--) {
             let counter: number = 0;
             for (let idx: number = 0, len: number = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.length; idx < len; ++idx) {
-                let sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[idx];
+                const sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[idx];
                 if (sourceStaffEntry === undefined) {
                     counter++;
                 }
@@ -491,11 +491,11 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         }
         if (this.musicSheet.Title === undefined) {
             try {
-                let barI: number = Math.max(
+                const barI: number = Math.max(
                     0, filePath.lastIndexOf("/"), filePath.lastIndexOf("\\")
                 );
-                let filename: string = filePath.substr(barI);
-                let filenameSplits: string[] = filename.split(".", 1);
+                const filename: string = filePath.substr(barI);
+                const filenameSplits: string[] = filename.split(".", 1);
                 this.musicSheet.Title = new Label(filenameSplits[0]);
             } catch (ex) {
                 Logging.log("MusicSheetReader.pushSheetLabels: ", ex);
@@ -506,7 +506,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
 
     // Checks whether _elem_ has an attribute with value _val_.
     private presentAttrsWithValue(elem: IXmlElement, val: string): boolean {
-        for (let attr of elem.attributes()) {
+        for (const attr of elem.attributes()) {
             if (attr.value === val) {
                 return true;
             }
@@ -515,11 +515,11 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     }
 
     private readComposer(root: IXmlElement): void {
-        let identificationNode: IXmlElement = root.element("identification");
+        const identificationNode: IXmlElement = root.element("identification");
         if (identificationNode !== undefined) {
-            let creators: IXmlElement[] = identificationNode.elements("creator");
+            const creators: IXmlElement[] = identificationNode.elements("creator");
             for (let idx: number = 0, len: number = creators.length; idx < len; ++idx) {
-                let creator: IXmlElement = creators[idx];
+                const creator: IXmlElement = creators[idx];
                 if (creator.hasAttributes) {
                     if (this.presentAttrsWithValue(creator, "composer")) {
                         this.musicSheet.Composer = new Label(this.trimString(creator.value));
@@ -534,7 +534,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     }
 
     private readTitleAndComposerFromCredits(root: IXmlElement): void {
-        let systemYCoordinates: number = this.computeSystemYCoordinates(root);
+        const systemYCoordinates: number = this.computeSystemYCoordinates(root);
         if (systemYCoordinates === 0) {
             return;
         }
@@ -543,9 +543,9 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         let largestCreditYInfo: number = 0;
         let finalSubtitle: string = undefined;
         let possibleTitle: string = undefined;
-        let creditElements: IXmlElement[] = root.elements("credit");
+        const creditElements: IXmlElement[] = root.elements("credit");
         for (let idx: number = 0, len: number = creditElements.length; idx < len; ++idx) {
-            let credit: IXmlElement = creditElements[idx];
+            const credit: IXmlElement = creditElements[idx];
             if (!credit.attribute("page")) {
                 return;
             }
@@ -556,13 +556,13 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                     if (!creditChild.attribute("justify")) {
                         break;
                     }
-                    let creditJustify: string = creditChild.attribute("justify").value;
-                    let creditY: string = creditChild.attribute("default-y").value;
-                    let creditYInfo: number = parseFloat(creditY);
+                    const creditJustify: string = creditChild.attribute("justify").value;
+                    const creditY: string = creditChild.attribute("default-y").value;
+                    const creditYInfo: number = parseFloat(creditY);
                     if (creditYInfo > systemYCoordinates) {
                         if (this.musicSheet.Title === undefined) {
-                            let creditSize: string = creditChild.attribute("font-size").value;
-                            let titleCreditSizeInt: number = parseFloat(creditSize);
+                            const creditSize: string = creditChild.attribute("font-size").value;
+                            const titleCreditSizeInt: number = parseFloat(creditSize);
                             if (largestTitleCreditSize < titleCreditSizeInt) {
                                 largestTitleCreditSize = titleCreditSizeInt;
                                 finalTitle = creditChild.value;
@@ -611,20 +611,20 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         }
         let paperHeight: number = 0;
         let topSystemDistance: number = 0;
-        let defi: string = root.element("defaults").element("page-layout").element("page-height").value;
+        const defi: string = root.element("defaults").element("page-layout").element("page-height").value;
         paperHeight = parseFloat(defi);
         let found: boolean = false;
-        let parts: IXmlElement[] = root.elements("part");
+        const parts: IXmlElement[] = root.elements("part");
         for (let idx: number = 0, len: number = parts.length; idx < len; ++idx) {
-            let measures: IXmlElement[] = parts[idx].elements("measure");
+            const measures: IXmlElement[] = parts[idx].elements("measure");
             for (let idx2: number = 0, len2: number = measures.length; idx2 < len2; ++idx2) {
-                let measure: IXmlElement = measures[idx2];
+                const measure: IXmlElement = measures[idx2];
                 if (measure.element("print") !== undefined) {
-                    let systemLayouts: IXmlElement[] = measure.element("print").elements("system-layout");
+                    const systemLayouts: IXmlElement[] = measure.element("print").elements("system-layout");
                     for (let idx3: number = 0, len3: number = systemLayouts.length; idx3 < len3; ++idx3) {
-                        let syslab: IXmlElement = systemLayouts[idx3];
+                        const syslab: IXmlElement = systemLayouts[idx3];
                         if (syslab.element("top-system-distance") !== undefined) {
-                            let topSystemDistanceString: string = syslab.element("top-system-distance").value;
+                            const topSystemDistanceString: string = syslab.element("top-system-distance").value;
                             topSystemDistance = parseFloat(topSystemDistanceString);
                             found = true;
                             break;
@@ -638,9 +638,9 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             }
         }
         if (root.element("defaults").element("system-layout") !== undefined) {
-            let syslay: IXmlElement = root.element("defaults").element("system-layout");
+            const syslay: IXmlElement = root.element("defaults").element("system-layout");
             if (syslay.element("top-system-distance") !== undefined) {
-                let topSystemDistanceString: string = root.element("defaults").element("system-layout").element("top-system-distance").value;
+                const topSystemDistanceString: string = root.element("defaults").element("system-layout").element("top-system-distance").value;
                 topSystemDistance = parseFloat(topSystemDistanceString);
             }
         }
@@ -651,7 +651,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
     }
 
     private readTitle(root: IXmlElement): void {
-        let titleNode: IXmlElement = root.element("work");
+        const titleNode: IXmlElement = root.element("work");
         let titleNodeChild: IXmlElement = undefined;
         if (titleNode !== undefined) {
             titleNodeChild = titleNode.element("work-title");
@@ -659,7 +659,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                 this.musicSheet.Title = new Label(this.trimString(titleNodeChild.value));
             }
         }
-        let movementNode: IXmlElement = root.element("movement-title");
+        const movementNode: IXmlElement = root.element("movement-title");
         let finalSubTitle: string = "";
         if (movementNode !== undefined) {
             if (this.musicSheet.Title === undefined) {
@@ -669,9 +669,9 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             }
         }
         if (titleNode !== undefined) {
-            let subtitleNodeChild: IXmlElement = titleNode.element("work-number");
+            const subtitleNodeChild: IXmlElement = titleNode.element("work-number");
             if (subtitleNodeChild !== undefined) {
-                let workNumber: string = subtitleNodeChild.value;
+                const workNumber: string = subtitleNodeChild.value;
                 if (workNumber) {
                     if (finalSubTitle) {
                         finalSubTitle = workNumber;
@@ -694,27 +694,27 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
      */
     private createInstrumentGroups(entryList: IXmlElement[]): { [_: string]: Instrument; } {
         let instrumentId: number = 0;
-        let instrumentDict: { [_: string]: Instrument; } = {};
+        const instrumentDict: { [_: string]: Instrument; } = {};
         let currentGroup: InstrumentalGroup;
         try {
-            let entryArray: IXmlElement[] = entryList;
+            const entryArray: IXmlElement[] = entryList;
             for (let idx: number = 0, len: number = entryArray.length; idx < len; ++idx) {
-                let node: IXmlElement = entryArray[idx];
+                const node: IXmlElement = entryArray[idx];
                 if (node.name === "score-part") {
-                    let instrIdString: string = node.attribute("id").value;
-                    let instrument: Instrument = new Instrument(instrumentId, instrIdString, this.musicSheet, currentGroup);
+                    const instrIdString: string = node.attribute("id").value;
+                    const instrument: Instrument = new Instrument(instrumentId, instrIdString, this.musicSheet, currentGroup);
                     instrumentId++;
-                    let partElements: IXmlElement[] = node.elements();
+                    const partElements: IXmlElement[] = node.elements();
                     for (let idx2: number = 0, len2: number = partElements.length; idx2 < len2; ++idx2) {
-                        let partElement: IXmlElement = partElements[idx2];
+                        const partElement: IXmlElement = partElements[idx2];
                         try {
                             if (partElement.name === "part-name") {
                                 instrument.Name = partElement.value;
                             } else if (partElement.name === "score-instrument") {
-                                let subInstrument: SubInstrument = new SubInstrument(instrument);
+                                const subInstrument: SubInstrument = new SubInstrument(instrument);
                                 subInstrument.idString = partElement.firstAttribute.value;
                                 instrument.SubInstruments.push(subInstrument);
-                                let subElement: IXmlElement = partElement.element("instrument-name");
+                                const subElement: IXmlElement = partElement.element("instrument-name");
                                 if (subElement !== undefined) {
                                     subInstrument.name = subElement.value;
                                     subInstrument.setMidiInstrument(subElement.value);
@@ -722,15 +722,15 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                             } else if (partElement.name === "midi-instrument") {
                                 let subInstrument: SubInstrument = instrument.getSubInstrument(partElement.firstAttribute.value);
                                 for (let idx3: number = 0, len3: number = instrument.SubInstruments.length; idx3 < len3; ++idx3) {
-                                    let subInstr: SubInstrument = instrument.SubInstruments[idx3];
+                                    const subInstr: SubInstrument = instrument.SubInstruments[idx3];
                                     if (subInstr.idString === partElement.value) {
                                         subInstrument = subInstr;
                                         break;
                                     }
                                 }
-                                let instrumentElements: IXmlElement[] = partElement.elements();
+                                const instrumentElements: IXmlElement[] = partElement.elements();
                                 for (let idx3: number = 0, len3: number = instrumentElements.length; idx3 < len3; ++idx3) {
-                                    let instrumentElement: IXmlElement = instrumentElements[idx3];
+                                    const instrumentElement: IXmlElement = instrumentElements[idx3];
                                     try {
                                         if (instrumentElement.name === "midi-channel") {
                                             if (parseInt(instrumentElement.value, 10) === 10) {
@@ -744,7 +744,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                                             subInstrument.fixedKey = Math.max(0, parseInt(instrumentElement.value, 10));
                                         } else if (instrumentElement.name === "volume") {
                                             try {
-                                                let result: number = <number>parseFloat(instrumentElement.value);
+                                                const result: number = <number>parseFloat(instrumentElement.value);
                                                 subInstrument.volume = result / 127.0;
                                             } catch (ex) {
                                                 Logging.debug("ExpressionReader.readExpressionParameters", "read volume", ex);
@@ -752,7 +752,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
 
                                         } else if (instrumentElement.name === "pan") {
                                             try {
-                                                let result: number = <number>parseFloat(instrumentElement.value);
+                                                const result: number = <number>parseFloat(instrumentElement.value);
                                                 subInstrument.pan = result / 64.0;
                                             } catch (ex) {
                                                 Logging.debug("ExpressionReader.readExpressionParameters", "read pan", ex);
@@ -771,7 +771,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
 
                     }
                     if (instrument.SubInstruments.length === 0) {
-                        let subInstrument: SubInstrument = new SubInstrument(instrument);
+                        const subInstrument: SubInstrument = new SubInstrument(instrument);
                         instrument.SubInstruments.push(subInstrument);
                     }
                     instrumentDict[instrIdString] = instrument;
@@ -784,7 +784,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                     }
                 } else {
                     if ((node.name === "part-group") && (node.attribute("type").value === "start")) {
-                        let iG: InstrumentalGroup = new InstrumentalGroup("group", this.musicSheet, currentGroup);
+                        const iG: InstrumentalGroup = new InstrumentalGroup("group", this.musicSheet, currentGroup);
                         if (currentGroup !== undefined) {
                             currentGroup.InstrumentalGroups.push(iG);
                         } else {
@@ -795,7 +795,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                         if ((node.name === "part-group") && (node.attribute("type").value === "stop")) {
                             if (currentGroup !== undefined) {
                                 if (currentGroup.InstrumentalGroups.length === 1) {
-                                    let instr: InstrumentalGroup = currentGroup.InstrumentalGroups[0];
+                                    const instr: InstrumentalGroup = currentGroup.InstrumentalGroups[0];
                                     if (currentGroup.Parent !== undefined) {
                                         currentGroup.Parent.InstrumentalGroups.push(instr);
                                         this._removeFromArray(currentGroup.Parent.InstrumentalGroups, currentGroup);
@@ -811,14 +811,14 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                 }
             }
         } catch (e) {
-            let errorMsg: string = ITextTranslation.translateText(
+            const errorMsg: string = ITextTranslation.translateText(
                 "ReaderErrorMessages/InstrumentError", "Error while reading Instruments"
             );
             throw new MusicSheetReadingException(errorMsg, e);
         }
 
         for (let idx: number = 0, len: number = this.musicSheet.Instruments.length; idx < len; ++idx) {
-            let instrument: Instrument = this.musicSheet.Instruments[idx];
+            const instrument: Instrument = this.musicSheet.Instruments[idx];
             if (!instrument.Name) {
                 instrument.Name = "Instr. " + instrument.IdString;
             }
@@ -833,10 +833,10 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
      */
     private getCompleteNumberOfStavesFromXml(partInst: IXmlElement[]): number {
         let num: number = 0;
-        for (let partNode of partInst) {
-            let xmlMeasureList: IXmlElement[] = partNode.elements("measure");
+        for (const partNode of partInst) {
+            const xmlMeasureList: IXmlElement[] = partNode.elements("measure");
             if (xmlMeasureList.length > 0) {
-                let xmlMeasure: IXmlElement = xmlMeasureList[0];
+                const xmlMeasure: IXmlElement = xmlMeasureList[0];
                 if (xmlMeasure !== undefined) {
                     let stavesNode: IXmlElement = xmlMeasure.element("attributes");
                     if (stavesNode !== undefined) {
@@ -851,7 +851,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             }
         }
         if (isNaN(num) || num <= 0) {
-            let errorMsg: string = ITextTranslation.translateText(
+            const errorMsg: string = ITextTranslation.translateText(
                 "ReaderErrorMessages/StaffError", "Invalid number of staves."
             );
             throw new MusicSheetReadingException(errorMsg);
@@ -866,9 +866,9 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
      */
     private getInstrumentNumberOfStavesFromXml(partNode: IXmlElement): number {
         let num: number = 0;
-        let xmlMeasure: IXmlElement = partNode.element("measure");
+        const xmlMeasure: IXmlElement = partNode.element("measure");
         if (xmlMeasure !== undefined) {
-            let attributes: IXmlElement = xmlMeasure.element("attributes");
+            const attributes: IXmlElement = xmlMeasure.element("attributes");
             let staves: IXmlElement = undefined;
             if (attributes !== undefined) {
                 staves = attributes.element("staves");
@@ -880,7 +880,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             }
         }
         if (isNaN(num) || num <= 0) {
-            let errorMsg: string = ITextTranslation.translateText(
+            const errorMsg: string = ITextTranslation.translateText(
                 "ReaderErrorMessages/StaffError", "Invalid number of Staves."
             );
             throw new MusicSheetReadingException(errorMsg);

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

@@ -0,0 +1,144 @@
+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 * as log from "loglevel";
+
+export class ChordSymbolReader {
+    public static readChordSymbol(xmlNode: IXmlElement, musicSheet: MusicSheet, activeKey: KeyInstruction): ChordSymbolContainer {
+        const root: IXmlElement = xmlNode.element("root");
+        const kind: IXmlElement = xmlNode.element("kind");
+
+        // must be always present
+        if (root === undefined || kind === undefined) {
+          return undefined;
+        }
+
+        const rootStep: IXmlElement = root.element("root-step");
+        const 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) {
+            const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                    "Invalid chord symbol");
+            musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            log.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) {
+                const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                        "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                log.debug("InstrumentReader.readChordSymbol", errorMsg, ex);
+            }
+
+        }
+        // using default octave value, to be changed later
+        const rootPitch: Pitch = new Pitch(rootNote, 1, rootAlteration);
+        const kindValue: string = kind.value.trim().replace("-", "");
+        let chordKind: ChordSymbolEnum;
+        try {
+            chordKind = ChordSymbolEnum[kindValue];
+        } catch (ex) {
+            const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                    "Invalid chord symbol");
+            musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            log.debug("InstrumentReader.readChordSymbol", errorMsg, ex);
+            return undefined;
+        }
+
+        // bass is optional
+        let bassPitch: Pitch = undefined;
+        const bass: IXmlElement = xmlNode.element("bass");
+        if (bass !== undefined) {
+            const bassStep: IXmlElement = bass.element("bass-step");
+            const bassAlter: IXmlElement = bass.element("bass-alter");
+            let bassNote: NoteEnum = NoteEnum.C;
+            if (bassStep !== undefined) {
+                try {
+                    bassNote = NoteEnum[bassStep.value.trim()];
+                } catch (ex) {
+                    const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                            "Invalid chord symbol");
+                    musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                    log.debug("InstrumentReader.readChordSymbol", errorMsg, ex);
+                    return undefined;
+                }
+            }
+            let bassAlteration: AccidentalEnum = AccidentalEnum.NONE;
+            if (bassAlter !== undefined) {
+                try {
+                    bassAlteration = <AccidentalEnum>parseInt(bassAlter.value, undefined);
+                } catch (ex) {
+                    const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                            "Invalid chord symbol");
+                    musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                    log.debug("InstrumentReader.readChordSymbol", errorMsg, ex);
+                }
+            }
+            bassPitch = new Pitch(bassNote, 1, bassAlteration);
+        }
+
+        // degree is optional
+        let degree: Degree = undefined;
+        const degreeNode: IXmlElement = xmlNode.element("degree");
+        if (degreeNode !== undefined) {
+            const degreeValue: IXmlElement = degreeNode.element("degree-value");
+            const degreeAlter: IXmlElement = degreeNode.element("degree-alter");
+            const 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) {
+                const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                        "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                log.debug("InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            let alter: AccidentalEnum;
+            try {
+                alter = <AccidentalEnum>parseInt(degreeAlter.value, undefined);
+            } catch (ex) {
+                const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                        "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                log.debug("InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            let text: ChordDegreeText;
+            try {
+                text = ChordDegreeText[degreeType.value.trim().toLowerCase()];
+            } catch (ex) {
+                const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                        "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                log.debug("InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            degree = new Degree(value, alter, text);
+        }
+        return new ChordSymbolContainer(rootPitch, chordKind, bassPitch, degree, activeKey);
+    }
+}

+ 4 - 6
src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionCalculator.ts

@@ -1,4 +1,4 @@
-import {SourceMeasure} from "../../VoiceData/SourceMeasure";
+import {SourceMeasure} from "../../VoiceData/SourceMeasure";
 import {RepetitionInstruction, RepetitionInstructionEnum, AlignmentType} from "../../VoiceData/Instructions/RepetitionInstruction";
 import {ArgumentOutOfRangeException} from "../../Exceptions";
 import {MusicSheet} from "../../MusicSheet";
@@ -6,7 +6,6 @@ import {MusicSheet} from "../../MusicSheet";
 export class RepetitionCalculator {
   private musicSheet: MusicSheet;
   private repetitionInstructions: RepetitionInstruction[] = [];
-  private lastRepetitionCommonPartStartIndex: number = 0;
   private currentMeasure: SourceMeasure;
   private currentMeasureIndex: number;
 
@@ -20,10 +19,9 @@ export class RepetitionCalculator {
   public calculateRepetitions(musicSheet: MusicSheet, repetitionInstructions: RepetitionInstruction[]): void {
     this.musicSheet = <MusicSheet>musicSheet;
     this.repetitionInstructions = repetitionInstructions;
-    this.lastRepetitionCommonPartStartIndex = 0;
-    let sourceMeasures: SourceMeasure[] = this.musicSheet.SourceMeasures;
+    const sourceMeasures: SourceMeasure[] = this.musicSheet.SourceMeasures;
     for (let idx: number = 0, len: number = this.repetitionInstructions.length; idx < len; ++idx) {
-      let instruction: RepetitionInstruction = this.repetitionInstructions[idx];
+      const instruction: RepetitionInstruction = this.repetitionInstructions[idx];
       this.currentMeasureIndex = instruction.measureIndex;
       this.currentMeasure = sourceMeasures[this.currentMeasureIndex];
       this.handleRepetitionInstructions(instruction);
@@ -32,7 +30,7 @@ export class RepetitionCalculator {
     // if there are more than one instruction at measure begin or end,
     // sort them according to the nesting of the repetitions:
     for (let idx: number = 0, len: number = this.musicSheet.SourceMeasures.length; idx < len; ++idx) {
-      let measure: SourceMeasure = this.musicSheet.SourceMeasures[idx];
+      const measure: SourceMeasure = this.musicSheet.SourceMeasures[idx];
       if (measure.FirstRepetitionInstructions.length > 1) {
         measure.FirstRepetitionInstructions.sort(RepetitionInstruction.compare);
       }

+ 39 - 39
src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionInstructionReader.ts

@@ -1,4 +1,4 @@
-import {MusicSheet} from "../../MusicSheet";
+import {MusicSheet} from "../../MusicSheet";
 import {IXmlElement} from "../../../Common/FileIO/Xml";
 import {SourceMeasure} from "../../VoiceData/SourceMeasure";
 import {RepetitionInstruction, RepetitionInstructionEnum, AlignmentType} from "../../VoiceData/Instructions/RepetitionInstruction";
@@ -35,10 +35,10 @@ export class RepetitionInstructionReader {
       let direction: string = "";
       let type: string = "";
       let style: string = "";
-      let endingIndices: number[] = [];
+      const endingIndices: number[] = [];
 
       // read barline style
-      let styleNode: IXmlElement = barlineNode.element("bar-style");
+      const styleNode: IXmlElement = barlineNode.element("bar-style");
 
       // if location is ommited in Xml, right is implied (from documentation)
       if (styleNode !== undefined) {
@@ -49,36 +49,36 @@ export class RepetitionInstructionReader {
       } else {
         location = "right";
       }
-      let barlineNodeElements: IXmlElement[] = barlineNode.elements();
+      const barlineNodeElements: IXmlElement[] = barlineNode.elements();
 
       // read repeat- or ending line information
       for (let idx: number = 0, len: number = barlineNodeElements.length; idx < len; ++idx) {
-        let childNode: IXmlElement = barlineNodeElements[idx];
+        const childNode: IXmlElement = barlineNodeElements[idx];
         if ("repeat" === childNode.name && childNode.hasAttributes) {
           hasRepeat = true;
           direction = childNode.attribute("direction").value;
         } else if ( "ending" === childNode.name && childNode.hasAttributes &&
                     childNode.attribute("type") !== undefined && childNode.attribute("number") !== undefined) {
           type = childNode.attribute("type").value;
-          let num: string = childNode.attribute("number").value;
+          const num: string = childNode.attribute("number").value;
 
           // Parse the given ending indices:
           // handle cases like: "1, 2" or "1 + 2" or even "1 - 3, 6"
-          let separatedEndingIndices: string[] = num.split("[,+]");
+          const separatedEndingIndices: string[] = num.split("[,+]");
           for (let idx2: number = 0, len2: number = separatedEndingIndices.length; idx2 < len2; ++idx2) {
-            let separatedEndingIndex: string = separatedEndingIndices[idx2];
-            let indices: string[] = separatedEndingIndex.match("[0-9]");
+            const separatedEndingIndex: string = separatedEndingIndices[idx2];
+            const indices: string[] = separatedEndingIndex.match("[0-9]");
 
             // check if possibly something like "1-3" is given..
             if (separatedEndingIndex.search("-") !== -1 && indices.length === 2) {
-              let startIndex: number = parseInt(indices[0], 10);
-              let endIndex: number = parseInt(indices[1], 10);
+              const startIndex: number = parseInt(indices[0], 10);
+              const endIndex: number = parseInt(indices[1], 10);
               for (let index: number = startIndex; index <= endIndex; index++) {
                 endingIndices.push(index);
               }
             } else {
               for (let idx3: number = 0, len3: number = indices.length; idx3 < len3; ++idx3) {
-                let index: string = indices[idx3];
+                const index: string = indices[idx3];
                 endingIndices.push(parseInt(index, 10));
               }
             }
@@ -93,23 +93,23 @@ export class RepetitionInstructionReader {
       if (hasRepeat || endingIndices.length > 0) {
         if (location === "left") {
           if (type === "start") {
-            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.Ending,
-                                                                                  AlignmentType.Begin, undefined, endingIndices);
+            const newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.Ending,
+                                                                                    AlignmentType.Begin, undefined, endingIndices);
             this.addInstruction(this.repetitionInstructions, newInstruction);
           }
           if (direction === "forward") {
             // start new Repetition
-            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.StartLine);
+            const newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.StartLine);
             this.addInstruction(this.repetitionInstructions, newInstruction);
           }
         } else { // location right
           if (type === "stop" || type === "discontinue") {
-            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.Ending,
-                                                                                  AlignmentType.End, undefined, endingIndices);
+            const newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.Ending,
+                                                                                    AlignmentType.End, undefined, endingIndices);
             this.addInstruction(this.repetitionInstructions, newInstruction);
           }
           if (direction === "backward") {
-            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.BackJumpLine);
+            const newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.BackJumpLine);
             this.addInstruction(this.repetitionInstructions, newInstruction);
           }
         }
@@ -118,17 +118,17 @@ export class RepetitionInstructionReader {
   }
 
   public handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode: IXmlElement, relativeMeasurePosition: number): boolean {
-    let wordsNode: IXmlElement = directionTypeNode.element("words");
+    const wordsNode: IXmlElement = directionTypeNode.element("words");
     if (wordsNode !== undefined) {
       // must Trim string and ToLower before compare
-      let innerText: string = wordsNode.value.trim().toLowerCase();
+      const innerText: string = wordsNode.value.trim().toLowerCase();
       if (StringUtil.StringContainsSeparatedWord(innerText, "d.s. al fine") ||
         StringUtil.StringContainsSeparatedWord(innerText, "d. s. al fine")) {
         let measureIndex: number = this.currentMeasureIndex;
         if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegnoAlFine);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegnoAlFine);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -138,7 +138,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition < 0.5) {
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegnoAlCoda);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegnoAlCoda);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -148,7 +148,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapoAlFine);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapoAlFine);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -158,7 +158,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition < 0.5) {
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapoAlCoda);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapoAlCoda);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -170,7 +170,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapo);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapo);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -182,7 +182,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegno);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegno);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -194,7 +194,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition < 0.5) {
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.ToCoda);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.ToCoda);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -203,7 +203,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition < 0.5) {
           measureIndex--;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Fine);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Fine);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -212,7 +212,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition > 0.5) {
           measureIndex++;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Coda);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Coda);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -221,7 +221,7 @@ export class RepetitionInstructionReader {
         if (relativeMeasurePosition > 0.5) {
           measureIndex++;
         }
-        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Segno);
+        const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Segno);
         this.addInstruction(this.repetitionInstructions, newInstruction);
         return true;
       }
@@ -230,7 +230,7 @@ export class RepetitionInstructionReader {
       if (relativeMeasurePosition > 0.5) {
         measureIndex++;
       }
-      let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Segno);
+      const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Segno);
       this.addInstruction(this.repetitionInstructions, newInstruction);
       return true;
     } else if (directionTypeNode.element("coda") !== undefined) {
@@ -238,7 +238,7 @@ export class RepetitionInstructionReader {
       if (relativeMeasurePosition > 0.5) {
         measureIndex++;
       }
-      let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Coda);
+      const newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Coda);
       this.addInstruction(this.repetitionInstructions, newInstruction);
       return true;
     }
@@ -248,11 +248,11 @@ export class RepetitionInstructionReader {
   public removeRedundantInstructions(): void {
     let segnoCount: number = 0;
     let codaCount: number = 0;
-    let fineCount: number = 0;
+    //const fineCount: number = 0;
     let toCodaCount: number = 0;
     let dalSegnaCount: number = 0;
     for (let index: number = 0; index < this.repetitionInstructions.length; index++) {
-      let instruction: RepetitionInstruction = this.repetitionInstructions[index];
+      const instruction: RepetitionInstruction = this.repetitionInstructions[index];
       switch (instruction.type) {
         case RepetitionInstructionEnum.Coda:
           if (toCodaCount > 0) {
@@ -270,7 +270,7 @@ export class RepetitionInstructionReader {
           if (segnoCount - dalSegnaCount > 0) { // two segnos in a row
             let foundInstruction: boolean = false;
             for (let idx: number = 0, len: number = this.repetitionInstructions.length; idx < len; ++idx) {
-              let instr: RepetitionInstruction = this.repetitionInstructions[idx];
+              const instr: RepetitionInstruction = this.repetitionInstructions[idx];
               if (instruction.measureIndex - instr.measureIndex === 1) {
                 switch (instr.type) {
                   case RepetitionInstructionEnum.BackJumpLine:
@@ -320,7 +320,7 @@ export class RepetitionInstructionReader {
       } else {
         switch (instruction.type) {
           case RepetitionInstructionEnum.Fine:
-            fineCount++;
+            //fineCount++;
             break;
           case RepetitionInstructionEnum.ToCoda:
             toCodaCount++;
@@ -345,7 +345,7 @@ export class RepetitionInstructionReader {
 
   private findInstructionInPreviousMeasure(currentInstructionIndex: number, currentMeasureIndex: number, searchedType: RepetitionInstructionEnum): boolean {
     for (let index: number = currentInstructionIndex - 1; index >= 0; index--) {
-      let instruction: RepetitionInstruction = this.repetitionInstructions[index];
+      const instruction: RepetitionInstruction = this.repetitionInstructions[index];
       if (currentMeasureIndex - instruction.measureIndex === 1 && instruction.type === searchedType) {
         return true;
       }
@@ -355,7 +355,7 @@ export class RepetitionInstructionReader {
 
   private backwardSearchForPreviousIdenticalInstruction(currentInstructionIndex: number, currentInstruction: RepetitionInstruction): boolean {
     for (let index: number = currentInstructionIndex - 1; index >= 0; index--) {
-      let instruction: RepetitionInstruction = this.repetitionInstructions[index];
+      const instruction: RepetitionInstruction = this.repetitionInstructions[index];
       if (instruction.equals(currentInstruction)) {
         return true;
       }
@@ -366,7 +366,7 @@ export class RepetitionInstructionReader {
   private addInstruction(currentRepetitionInstructions: RepetitionInstruction[], newInstruction: RepetitionInstruction): void {
     let addInstruction: boolean = true;
     for (let idx: number = 0, len: number = currentRepetitionInstructions.length; idx < len; ++idx) {
-      let repetitionInstruction: RepetitionInstruction = currentRepetitionInstructions[idx];
+      const repetitionInstruction: RepetitionInstruction = currentRepetitionInstructions[idx];
       if (newInstruction.equals(repetitionInstruction)) {
         addInstruction = false;
         break;

+ 133 - 122
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -36,7 +36,7 @@ export type SlurReader = any;
 export class VoiceGenerator {
     constructor(instrument: Instrument, voiceId: number, slurReader: SlurReader, mainVoice: Voice = undefined) {
         this.musicSheet = instrument.GetMusicSheet;
-        this.slurReader = slurReader;
+        // this.slurReader = slurReader;
         if (mainVoice !== undefined) {
             this.voice = new LinkedVoice(instrument, voiceId, mainVoice);
         } else {
@@ -47,7 +47,7 @@ export class VoiceGenerator {
         //this.articulationReader = MusicSymbolModuleFactory.createArticulationReader();
     }
 
-    private slurReader: SlurReader;
+    // private slurReader: SlurReader;
     //private lyricsReader: LyricsReader;
     //private articulationReader: ArticulationReader;
     private musicSheet: MusicSheet;
@@ -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,14 +115,15 @@ 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);
             //    this.voice.Parent.HasLyrics = true;
             //}
-            let notationNode: IXmlElement = noteNode.element("notations");
+            let hasTupletCommand: boolean = false;
+            const notationNode: IXmlElement = noteNode.element("notations");
             if (notationNode !== undefined) {
                 // let articNode: IXmlElement = undefined;
                 // (*)
@@ -133,33 +134,40 @@ export class VoiceGenerator {
                 // (*)
                 //if (this.slurReader !== undefined && (slurNodes = notationNode.elements("slur")))
                 //    this.slurReader.addSlur(slurNodes, this.currentNote);
-                let tupletNodeList: IXmlElement[] = notationNode.elements("tuplet");
-                if (tupletNodeList) {
-                    this.openTupletNumber = this.addTuplet(noteNode, tupletNodeList);
+                // check for Tuplets
+                const tupletNodeList: IXmlElement[] = notationNode.elements("tuplet");
+                if (tupletNodeList.length > 0) {
+                  this.openTupletNumber = this.addTuplet(noteNode, tupletNodeList);
+                  hasTupletCommand = true;
                 }
+                // check for Arpeggios
                 if (notationNode.element("arpeggiate") !== undefined && !graceNote) {
                     this.currentVoiceEntry.ArpeggiosNotesIndices.push(this.currentVoiceEntry.Notes.indexOf(this.currentNote));
                 }
-                let tiedNodeList: IXmlElement[] = notationNode.elements("tied");
-                if (tiedNodeList) {
+                // check for Ties - must be the last check
+                const tiedNodeList: IXmlElement[] = notationNode.elements("tied");
+                if (tiedNodeList.length > 0) {
                     this.addTie(tiedNodeList, measureStartAbsoluteTimestamp, maxTieNoteFraction);
                 }
 
-                let openTieDict: { [_: number]: Tie; } = this.openTieDict;
-                for (let key in openTieDict) {
+                // remove open ties, if there is already a gap between the last tie note and now.
+                const openTieDict: { [_: number]: Tie; } = this.openTieDict;
+                for (const key in openTieDict) {
                     if (openTieDict.hasOwnProperty(key)) {
-                        let tie: Tie = openTieDict[key];
+                        const tie: Tie = openTieDict[key];
                         if (Fraction.plus(tie.Start.ParentStaffEntry.Timestamp, tie.Start.Length).lt(this.currentStaffEntry.Timestamp)) {
                             delete openTieDict[key];
                         }
                     }
                 }
             }
-            if (noteNode.element("time-modification") !== undefined && notationNode === undefined) {
+            // time-modification yields tuplet in currentNote
+            // mustn't execute method, if this is the Note where the Tuplet has been created
+            if (noteNode.element("time-modification") !== undefined && !hasTupletCommand) {
                 this.handleTimeModificationNode(noteNode);
             }
         } catch (err) {
-            let errorMsg: string = ITextTranslation.translateText(
+            const errorMsg: string = ITextTranslation.translateText(
                 "ReaderErrorMessages/NoteError", "Ignored erroneous Note."
             );
             this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -179,19 +187,19 @@ export class VoiceGenerator {
             && this.currentVoiceEntry.graceVoiceEntriesBefore !== undefined
             && this.currentVoiceEntry.graceVoiceEntriesBefore.length > 0
         ) {
-            let voice: Voice = this.currentVoiceEntry.ParentVoice;
-            let horizontalIndex: number = this.currentMeasure.VerticalSourceStaffEntryContainers.indexOf(this.currentStaffEntry.VerticalContainerParent);
-            let verticalIndex: number = this.currentStaffEntry.VerticalContainerParent.StaffEntries.indexOf(this.currentStaffEntry);
-            let previousStaffEntry: SourceStaffEntry = this.currentMeasure.getPreviousSourceStaffEntryFromIndex(verticalIndex, horizontalIndex);
+            const voice: Voice = this.currentVoiceEntry.ParentVoice;
+            const horizontalIndex: number = this.currentMeasure.VerticalSourceStaffEntryContainers.indexOf(this.currentStaffEntry.VerticalContainerParent);
+            const verticalIndex: number = this.currentStaffEntry.VerticalContainerParent.StaffEntries.indexOf(this.currentStaffEntry);
+            const previousStaffEntry: SourceStaffEntry = this.currentMeasure.getPreviousSourceStaffEntryFromIndex(verticalIndex, horizontalIndex);
             if (previousStaffEntry !== undefined) {
                 let previousVoiceEntry: VoiceEntry = undefined;
                 for (let idx: number = 0, len: number = previousStaffEntry.VoiceEntries.length; idx < len; ++idx) {
-                    let voiceEntry: VoiceEntry = previousStaffEntry.VoiceEntries[idx];
+                    const voiceEntry: VoiceEntry = previousStaffEntry.VoiceEntries[idx];
                     if (voiceEntry.ParentVoice === voice) {
                         previousVoiceEntry = voiceEntry;
                         previousVoiceEntry.graceVoiceEntriesAfter = [];
                         for (let idx2: number = 0, len2: number = this.currentVoiceEntry.graceVoiceEntriesBefore.length; idx2 < len2; ++idx2) {
-                            let graceVoiceEntry: VoiceEntry = this.currentVoiceEntry.graceVoiceEntriesBefore[idx2];
+                            const graceVoiceEntry: VoiceEntry = this.currentVoiceEntry.graceVoiceEntriesBefore[idx2];
                             previousVoiceEntry.graceVoiceEntriesAfter.push(graceVoiceEntry);
                         }
                         this.currentVoiceEntry.graceVoiceEntriesBefore = [];
@@ -214,11 +222,11 @@ export class VoiceGenerator {
     public checkForStaffEntryLink(
         index: number, currentStaff: Staff, currentStaffEntry: SourceStaffEntry, currentMeasure: SourceMeasure
     ): SourceStaffEntry {
-        let staffEntryLink: StaffEntryLink = new StaffEntryLink(this.currentVoiceEntry);
+        const staffEntryLink: StaffEntryLink = new StaffEntryLink(this.currentVoiceEntry);
         staffEntryLink.LinkStaffEntries.push(currentStaffEntry);
         currentStaffEntry.Link = staffEntryLink;
-        let linkMusicTimestamp: Fraction = this.currentVoiceEntry.Timestamp.clone();
-        let verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = currentMeasure.getVerticalContainerByTimestamp(linkMusicTimestamp);
+        const linkMusicTimestamp: Fraction = this.currentVoiceEntry.Timestamp.clone();
+        const verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = currentMeasure.getVerticalContainerByTimestamp(linkMusicTimestamp);
         currentStaffEntry = verticalSourceStaffEntryContainer.StaffEntries[index];
         if (currentStaffEntry === undefined) {
             currentStaffEntry = new SourceStaffEntry(verticalSourceStaffEntryContainer, currentStaff);
@@ -235,10 +243,10 @@ export class VoiceGenerator {
         }
     }
     public checkOpenTies(): void {
-        let openTieDict: {[key: number]: Tie} = this.openTieDict;
-        for (let key in openTieDict) {
+        const openTieDict: {[key: number]: Tie} = this.openTieDict;
+        for (const key in openTieDict) {
             if (openTieDict.hasOwnProperty(key)) {
-                let tie: Tie = openTieDict[key];
+                const tie: Tie = openTieDict[key];
                 if (Fraction.plus(tie.Start.ParentStaffEntry.Timestamp, tie.Start.Length)
                         .lt(tie.Start.ParentStaffEntry.VerticalContainerParent.ParentMeasure.Duration)) {
                     delete openTieDict[key];
@@ -287,7 +295,7 @@ export class VoiceGenerator {
             case "maxima":
                 return new Fraction(8, 1);
             default: {
-                let errorMsg: string = ITextTranslation.translateText(
+                const errorMsg: string = ITextTranslation.translateText(
                     "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
                 );
                 throw new MusicSheetReadingException(errorMsg);
@@ -321,26 +329,26 @@ 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;
         let noteStep: NoteEnum = NoteEnum.C;
         let noteOctave: number = 0;
         let playbackInstrumentId: string = undefined;
-        let xmlnodeElementsArr: IXmlElement[] = node.elements();
+        const xmlnodeElementsArr: IXmlElement[] = node.elements();
         for (let idx: number = 0, len: number = xmlnodeElementsArr.length; idx < len; ++idx) {
-            let noteElement: IXmlElement = xmlnodeElementsArr[idx];
+            const noteElement: IXmlElement = xmlnodeElementsArr[idx];
             try {
                 if (noteElement.name === "pitch") {
-                    let noteElementsArr: IXmlElement[] = noteElement.elements();
+                    const noteElementsArr: IXmlElement[] = noteElement.elements();
                     for (let idx2: number = 0, len2: number = noteElementsArr.length; idx2 < len2; ++idx2) {
-                        let pitchElement: IXmlElement = noteElementsArr[idx2];
+                        const pitchElement: IXmlElement = noteElementsArr[idx2];
                         try {
                             if (pitchElement.name === "step") {
                                 noteStep = NoteEnum[pitchElement.value];
                                 if (noteStep === undefined) {
-                                    let errorMsg: string = ITextTranslation.translateText(
+                                    const errorMsg: string = ITextTranslation.translateText(
                                         "ReaderErrorMessages/NotePitchError",
                                         "Invalid pitch while reading note."
                                     );
@@ -350,7 +358,7 @@ export class VoiceGenerator {
                             } else if (pitchElement.name === "alter") {
                                 noteAlter = parseInt(pitchElement.value, 10);
                                 if (isNaN(noteAlter)) {
-                                    let errorMsg: string = ITextTranslation.translateText(
+                                    const errorMsg: string = ITextTranslation.translateText(
                                         "ReaderErrorMessages/NoteAlterationError", "Invalid alteration while reading note."
                                     );
                                     this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -360,7 +368,7 @@ export class VoiceGenerator {
                             } else if (pitchElement.name === "octave") {
                                 noteOctave = parseInt(pitchElement.value, 10);
                                 if (isNaN(noteOctave)) {
-                                    let errorMsg: string = ITextTranslation.translateText(
+                                    const errorMsg: string = ITextTranslation.translateText(
                                         "ReaderErrorMessages/NoteOctaveError", "Invalid octave value while reading note."
                                     );
                                     this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -373,11 +381,11 @@ export class VoiceGenerator {
 
                     }
                 } else if (noteElement.name === "unpitched") {
-                    let displayStep: IXmlElement = noteElement.element("display-step");
+                    const displayStep: IXmlElement = noteElement.element("display-step");
                     if (displayStep !== undefined) {
                         noteStep = NoteEnum[displayStep.value.toUpperCase()];
                     }
-                    let octave: IXmlElement = noteElement.element("display-octave");
+                    const octave: IXmlElement = noteElement.element("display-octave");
                     if (octave !== undefined) {
                         noteOctave = parseInt(octave.value, 10);
                         if (guitarPro) {
@@ -395,9 +403,9 @@ export class VoiceGenerator {
         }
 
         noteOctave -= Pitch.OctaveXmlDifference;
-        let pitch: Pitch = new Pitch(noteStep, noteOctave, noteAlter);
-        let noteLength: Fraction = new Fraction(noteDuration, divisions);
-        let note: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, noteLength, pitch);
+        const pitch: Pitch = new Pitch(noteStep, noteOctave, noteAlter);
+        const noteLength: Fraction = Fraction.createFromFraction(noteDuration);
+        const note: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, noteLength, pitch);
         note.PlaybackInstrumentId = playbackInstrumentId;
         if (!graceNote) {
             this.currentVoiceEntry.Notes.push(note);
@@ -416,9 +424,9 @@ export class VoiceGenerator {
      * @param divisions
      * @returns {Note}
      */
-    private addRestNote(noteDuration: number, divisions: number): Note {
-        let restFraction: Fraction = new Fraction(noteDuration, divisions);
-        let restNote: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, restFraction, undefined);
+    private addRestNote(noteDuration: Fraction): Note {
+        const restFraction: Fraction = Fraction.createFromFraction(noteDuration);
+        const restNote: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, restFraction, undefined);
         this.currentVoiceEntry.Notes.push(restNote);
         if (this.openBeam !== undefined) {
             this.openBeam.ExtendedNoteList.push(restNote);
@@ -434,15 +442,15 @@ export class VoiceGenerator {
      */
     private createBeam(node: IXmlElement, note: Note, grace: boolean): void {
         try {
-            let beamNode: IXmlElement = node.element("beam");
+            const beamNode: IXmlElement = node.element("beam");
             let beamAttr: IXmlAttribute = undefined;
             if (beamNode !== undefined && beamNode.hasAttributes) {
                 beamAttr = beamNode.attribute("number");
             }
             if (beamAttr !== undefined) {
-                let beamNumber: number = parseInt(beamAttr.value, 10);
-                let mainBeamNode: IXmlElement[] = node.elements("beam");
-                let currentBeamTag: string = mainBeamNode[0].value;
+                const beamNumber: number = parseInt(beamAttr.value, 10);
+                const mainBeamNode: IXmlElement[] = node.elements("beam");
+                const currentBeamTag: string = mainBeamNode[0].value;
                 if (beamNumber === 1 && mainBeamNode !== undefined) {
                     if (currentBeamTag === "begin" && this.lastBeamTag !== currentBeamTag) {
                         if (grace) {
@@ -463,7 +471,7 @@ export class VoiceGenerator {
                 if (grace) {
                     if (this.openGraceBeam === undefined) { return; }
                     for (let idx: number = 0, len: number = this.openGraceBeam.Notes.length; idx < len; ++idx) {
-                        let beamNote: Note = this.openGraceBeam.Notes[idx];
+                        const beamNote: Note = this.openGraceBeam.Notes[idx];
                         if (this.currentVoiceEntry === beamNote.ParentVoiceEntry) {
                             sameVoiceEntry = true;
                         }
@@ -477,7 +485,7 @@ export class VoiceGenerator {
                 } else {
                     if (this.openBeam === undefined) { return; }
                     for (let idx: number = 0, len: number = this.openBeam.Notes.length; idx < len; ++idx) {
-                        let beamNote: Note = this.openBeam.Notes[idx];
+                        const beamNote: Note = this.openBeam.Notes[idx];
                         if (this.currentVoiceEntry === beamNote.ParentVoiceEntry) {
                             sameVoiceEntry = true;
                         }
@@ -491,7 +499,7 @@ export class VoiceGenerator {
                 }
             }
         } catch (e) {
-            let errorMsg: string = ITextTranslation.translateText(
+            const errorMsg: string = ITextTranslation.translateText(
                 "ReaderErrorMessages/BeamError", "Error while reading beam."
             );
             this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -505,7 +513,7 @@ export class VoiceGenerator {
      */
     private handleOpenBeam(): void {
         if (this.openBeam.Notes.length === 1) {
-            let beamNote: Note = this.openBeam.Notes[0];
+            const beamNote: Note = this.openBeam.Notes[0];
             beamNote.NoteBeam = undefined;
             this.openBeam = undefined;
             return;
@@ -513,17 +521,19 @@ export class VoiceGenerator {
         if (this.currentNote === CollectionUtil.last(this.openBeam.Notes)) {
             this.openBeam = undefined;
         } else {
-            let beamLastNote: Note = CollectionUtil.last(this.openBeam.Notes);
-            let beamLastNoteStaffEntry: SourceStaffEntry = beamLastNote.ParentStaffEntry;
-            let horizontalIndex: number = this.currentMeasure.getVerticalContainerIndexByTimestamp(beamLastNoteStaffEntry.Timestamp);
-            let verticalIndex: number = beamLastNoteStaffEntry.VerticalContainerParent.StaffEntries.indexOf(beamLastNoteStaffEntry);
+            const beamLastNote: Note = CollectionUtil.last(this.openBeam.Notes);
+            const beamLastNoteStaffEntry: SourceStaffEntry = beamLastNote.ParentStaffEntry;
+            const horizontalIndex: number = this.currentMeasure.getVerticalContainerIndexByTimestamp(beamLastNoteStaffEntry.Timestamp);
+            const verticalIndex: number = beamLastNoteStaffEntry.VerticalContainerParent.StaffEntries.indexOf(beamLastNoteStaffEntry);
             if (horizontalIndex < this.currentMeasure.VerticalSourceStaffEntryContainers.length - 1) {
-                let nextStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[horizontalIndex + 1].StaffEntries[verticalIndex];
+                const nextStaffEntry: SourceStaffEntry = this.currentMeasure
+                                                             .VerticalSourceStaffEntryContainers[horizontalIndex + 1]
+                                                             .StaffEntries[verticalIndex];
                 if (nextStaffEntry !== undefined) {
                     for (let idx: number = 0, len: number = nextStaffEntry.VoiceEntries.length; idx < len; ++idx) {
-                        let voiceEntry: VoiceEntry = nextStaffEntry.VoiceEntries[idx];
+                        const voiceEntry: VoiceEntry = nextStaffEntry.VoiceEntries[idx];
                         if (voiceEntry.ParentVoice === this.voice) {
-                            let candidateNote: Note = voiceEntry.Notes[0];
+                            const candidateNote: Note = voiceEntry.Notes[0];
                             if (candidateNote.Length.lte(new Fraction(1, 8))) {
                                 this.openBeam.addNoteToBeam(candidateNote);
                                 this.openBeam = undefined;
@@ -542,14 +552,14 @@ export class VoiceGenerator {
         let graceChord: boolean = false;
         let type: string = "";
         if (node.elements("type")) {
-            let typeNode: IXmlElement[] = node.elements("type");
+            const typeNode: IXmlElement[] = node.elements("type");
             if (typeNode) {
                 type = typeNode[0].value;
                 try {
                     note.Length = this.getNoteDurationFromType(type);
                     note.Length.Numerator = 1;
                 } catch (e) {
-                    let errorMsg: string = ITextTranslation.translateText(
+                    const errorMsg: string = ITextTranslation.translateText(
                         "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
                     );
                     this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -558,10 +568,10 @@ export class VoiceGenerator {
 
             }
         }
-        let graceNode: IXmlElement = node.element("grace");
+        const graceNode: IXmlElement = node.element("grace");
         if (graceNode !== undefined && graceNode.attributes()) {
             if (graceNode.attribute("slash")) {
-                let slash: string = graceNode.attribute("slash").value;
+                const slash: string = graceNode.attribute("slash").value;
                 if (slash === "yes") {
                     note.GraceNoteSlash = true;
                 }
@@ -605,11 +615,11 @@ export class VoiceGenerator {
             if (timeModNode !== undefined) {
                 timeModNode = timeModNode.element("actual-notes");
             }
-            let tupletNodeListArr: IXmlElement[] = tupletNodeList;
+            const tupletNodeListArr: IXmlElement[] = tupletNodeList;
             for (let idx: number = 0, len: number = tupletNodeListArr.length; idx < len; ++idx) {
-                let tupletNode: IXmlElement = tupletNodeListArr[idx];
+                const tupletNode: IXmlElement = tupletNodeListArr[idx];
                 if (tupletNode !== undefined && tupletNode.attributes()) {
-                    let type: string = tupletNode.attribute("type").value;
+                    const type: string = tupletNode.attribute("type").value;
                     if (type === "start") {
                         let tupletNumber: number = 1;
                         if (tupletNode.attribute("number")) {
@@ -619,7 +629,7 @@ export class VoiceGenerator {
                         if (timeModNode !== undefined) {
                             tupletLabelNumber = parseInt(timeModNode.value, 10);
                             if (isNaN(tupletLabelNumber)) {
-                                let errorMsg: string = ITextTranslation.translateText(
+                                const errorMsg: string = ITextTranslation.translateText(
                                     "ReaderErrorMessages/TupletNoteDurationError", "Invalid tuplet note duration."
                                 );
                                 this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -627,7 +637,7 @@ export class VoiceGenerator {
                             }
 
                         }
-                        let tuplet: Tuplet = new Tuplet(tupletLabelNumber);
+                        const tuplet: Tuplet = new Tuplet(tupletLabelNumber);
                         if (this.tupletDict[tupletNumber] !== undefined) {
                             delete this.tupletDict[tupletNumber];
                             if (Object.keys(this.tupletDict).length === 0) {
@@ -637,7 +647,7 @@ export class VoiceGenerator {
                             }
                         }
                         this.tupletDict[tupletNumber] = tuplet;
-                        let subnotelist: Note[] = [];
+                        const subnotelist: Note[] = [];
                         subnotelist.push(this.currentNote);
                         tuplet.Notes.push(subnotelist);
                         tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
@@ -648,9 +658,9 @@ export class VoiceGenerator {
                         if (tupletNode.attribute("number")) {
                             tupletNumber = parseInt(tupletNode.attribute("number").value, 10);
                         }
-                        let tuplet: Tuplet = this.tupletDict[tupletNumber];
+                        const tuplet: Tuplet = this.tupletDict[tupletNumber];
                         if (tuplet !== undefined) {
-                            let subnotelist: Note[] = [];
+                            const subnotelist: Note[] = [];
                             subnotelist.push(this.currentNote);
                             tuplet.Notes.push(subnotelist);
                             tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
@@ -666,14 +676,14 @@ export class VoiceGenerator {
                 }
             }
         } else if (tupletNodeList[0] !== undefined) {
-            let n: IXmlElement = tupletNodeList[0];
+            const n: IXmlElement = tupletNodeList[0];
             if (n.hasAttributes) {
-                let type: string = n.attribute("type").value;
+                const type: string = n.attribute("type").value;
                 let tupletnumber: number = 1;
                 if (n.attribute("number")) {
                     tupletnumber = parseInt(n.attribute("number").value, 10);
                 }
-                let noTupletNumbering: boolean = isNaN(tupletnumber);
+                const noTupletNumbering: boolean = isNaN(tupletnumber);
 
                 if (type === "start") {
                     let tupletLabelNumber: number = 0;
@@ -684,7 +694,7 @@ export class VoiceGenerator {
                     if (timeModNode !== undefined) {
                         tupletLabelNumber = parseInt(timeModNode.value, 10);
                         if (isNaN(tupletLabelNumber)) {
-                            let errorMsg: string = ITextTranslation.translateText(
+                            const errorMsg: string = ITextTranslation.translateText(
                                 "ReaderErrorMessages/TupletNoteDurationError", "Invalid tuplet note duration."
                             );
                             this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -700,7 +710,7 @@ export class VoiceGenerator {
                     if (tuplet === undefined) {
                         tuplet = this.tupletDict[tupletnumber] = new Tuplet(tupletLabelNumber);
                     }
-                    let subnotelist: Note[] = [];
+                    const subnotelist: Note[] = [];
                     subnotelist.push(this.currentNote);
                     tuplet.Notes.push(subnotelist);
                     tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
@@ -710,9 +720,9 @@ export class VoiceGenerator {
                     if (noTupletNumbering) {
                         tupletnumber = this.openTupletNumber;
                     }
-                    let tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
+                    const tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
                     if (tuplet !== undefined) {
-                        let subnotelist: Note[] = [];
+                        const subnotelist: Note[] = [];
                         subnotelist.push(this.currentNote);
                         tuplet.Notes.push(subnotelist);
                         tuplet.Fractions.push(this.getTupletNoteDurationFromType(node));
@@ -731,15 +741,16 @@ export class VoiceGenerator {
     }
 
     /**
-     * Handle the time-modification [[IXmlElement]] for the [[Tuplet]] case (tupletNotes not at begin/end of [[Tuplet]]).
+     * This method handles the time-modification IXmlElement for the Tuplet case (tupletNotes not at begin/end of Tuplet).
      * @param noteNode
      */
     private handleTimeModificationNode(noteNode: IXmlElement): void {
-        if (this.openTupletNumber in this.tupletDict) {
+        if (this.tupletDict[this.openTupletNumber] !== undefined) {
             try {
-                let tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
-                let notes: Note[] = CollectionUtil.last(tuplet.Notes);
-                let lastTupletVoiceEntry: VoiceEntry = notes[0].ParentVoiceEntry;
+                // Tuplet should already be created
+                const tuplet: Tuplet = this.tupletDict[this.openTupletNumber];
+                const notes: Note[] = CollectionUtil.last(tuplet.Notes);
+                const lastTupletVoiceEntry: VoiceEntry = notes[0].ParentVoiceEntry;
                 let noteList: Note[];
                 if (lastTupletVoiceEntry.Timestamp.Equals(this.currentVoiceEntry.Timestamp)) {
                     noteList = notes;
@@ -751,7 +762,7 @@ export class VoiceGenerator {
                 noteList.push(this.currentNote);
                 this.currentNote.NoteTuplet = tuplet;
             } catch (ex) {
-                let errorMsg: string = ITextTranslation.translateText(
+                const errorMsg: string = ITextTranslation.translateText(
                     "ReaderErrorMessages/TupletNumberError", "Invalid tuplet number."
                 );
                 this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
@@ -759,10 +770,10 @@ export class VoiceGenerator {
             }
 
         } else if (this.currentVoiceEntry.Notes.length > 0) {
-            let firstNote: Note = this.currentVoiceEntry.Notes[0];
+            const firstNote: Note = this.currentVoiceEntry.Notes[0];
             if (firstNote.NoteTuplet !== undefined) {
-                let tuplet: Tuplet = firstNote.NoteTuplet;
-                let notes: Note[] = CollectionUtil.last(tuplet.Notes);
+                const tuplet: Tuplet = firstNote.NoteTuplet;
+                const notes: Note[] = CollectionUtil.last(tuplet.Notes);
                 notes.push(this.currentNote);
                 this.currentNote.NoteTuplet = tuplet;
             }
@@ -771,24 +782,24 @@ export class VoiceGenerator {
     private addTie(tieNodeList: IXmlElement[], measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction): void {
         if (tieNodeList !== undefined) {
             if (tieNodeList.length === 1) {
-                let tieNode: IXmlElement = tieNodeList[0];
+                const tieNode: IXmlElement = tieNodeList[0];
                 if (tieNode !== undefined && tieNode.attributes()) {
-                    let type: string = tieNode.attribute("type").value;
+                    const type: string = tieNode.attribute("type").value;
                     try {
                         if (type === "start") {
-                            let num: number = this.findCurrentNoteInTieDict(this.currentNote);
+                            const num: number = this.findCurrentNoteInTieDict(this.currentNote);
                             if (num < 0) {
                                 delete this.openTieDict[num];
                             }
-                            let newTieNumber: number = this.getNextAvailableNumberForTie();
-                            let tie: Tie = new Tie(this.currentNote);
+                            const newTieNumber: number = this.getNextAvailableNumberForTie();
+                            const tie: Tie = new Tie(this.currentNote);
                             this.openTieDict[newTieNumber] = tie;
                             if (this.currentNote.NoteBeam !== undefined) {
                                 if (this.currentNote.NoteBeam.Notes[0] === this.currentNote) {
                                     tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
                                 } else {
                                     for (let idx: number = 0, len: number = this.currentNote.NoteBeam.Notes.length; idx < len; ++idx) {
-                                        let note: Note = this.currentNote.NoteBeam.Notes[idx];
+                                        const note: Note = this.currentNote.NoteBeam.Notes[idx];
                                         if (note.NoteTie !== undefined && note.NoteTie !== tie && note.NoteTie.BeamStartTimestamp !== undefined) {
                                             tie.BeamStartTimestamp = note.NoteTie.BeamStartTimestamp;
                                             break;
@@ -800,17 +811,17 @@ export class VoiceGenerator {
                                 }
                             }
                         } else if (type === "stop") {
-                            let tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
-                            let tie: Tie = this.openTieDict[tieNumber];
+                            const tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
+                            const tie: Tie = this.openTieDict[tieNumber];
                             if (tie !== undefined) {
-                                let tieStartNote: Note = tie.Start;
+                                const tieStartNote: Note = tie.Start;
                                 tieStartNote.NoteTie = tie;
                                 tieStartNote.Length.Add(this.currentNote.Length);
                                 tie.Fractions.push(this.currentNote.Length);
                                 if (maxTieNoteFraction.lt(Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length))) {
                                     maxTieNoteFraction = Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length);
                                 }
-                                let i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
+                                const i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
                                 if (i !== -1) { this.currentVoiceEntry.Notes.splice(i, 1); }
                                 if (
                                     this.currentVoiceEntry.Articulations.length === 1
@@ -820,23 +831,23 @@ export class VoiceGenerator {
                                     tieStartNote.ParentVoiceEntry.Articulations.push(ArticulationEnum.fermata);
                                 }
                                 if (this.currentNote.NoteBeam !== undefined) {
-                                    let noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
+                                    const noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
                                     if (noteBeamIndex === 0 && tie.BeamStartTimestamp === undefined) {
                                         tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
                                     }
-                                    let noteBeam: Beam = this.currentNote.NoteBeam;
+                                    const noteBeam: Beam = this.currentNote.NoteBeam;
                                     noteBeam.Notes[noteBeamIndex] = tieStartNote;
                                     tie.TieBeam = noteBeam;
                                 }
                                 if (this.currentNote.NoteTuplet !== undefined) {
-                                    let noteTupletIndex: number = this.currentNote.NoteTuplet.getNoteIndex(this.currentNote);
-                                    let index: number = this.currentNote.NoteTuplet.Notes[noteTupletIndex].indexOf(this.currentNote);
-                                    let noteTuplet: Tuplet = this.currentNote.NoteTuplet;
+                                    const noteTupletIndex: number = this.currentNote.NoteTuplet.getNoteIndex(this.currentNote);
+                                    const index: number = this.currentNote.NoteTuplet.Notes[noteTupletIndex].indexOf(this.currentNote);
+                                    const noteTuplet: Tuplet = this.currentNote.NoteTuplet;
                                     noteTuplet.Notes[noteTupletIndex][index] = tieStartNote;
                                     tie.TieTuplet = noteTuplet;
                                 }
                                 for (let idx: number = 0, len: number = this.currentNote.NoteSlurs.length; idx < len; ++idx) {
-                                    let slur: Slur = this.currentNote.NoteSlurs[idx];
+                                    const slur: Slur = this.currentNote.NoteSlurs[idx];
                                     if (slur.StartNote === this.currentNote) {
                                         slur.StartNote = tie.Start;
                                         slur.StartNote.NoteSlurs.push(slur);
@@ -846,10 +857,10 @@ export class VoiceGenerator {
                                         slur.EndNote.NoteSlurs.push(slur);
                                     }
                                 }
-                                let lyricsEntries: Dictionary<number, LyricsEntry> = this.currentVoiceEntry.LyricsEntries;
-                                for (let lyricsEntry in lyricsEntries) {
+                                const lyricsEntries: Dictionary<number, LyricsEntry> = this.currentVoiceEntry.LyricsEntries;
+                                for (const lyricsEntry in lyricsEntries) {
                                     if (lyricsEntries.hasOwnProperty(lyricsEntry)) {
-                                        let val: LyricsEntry = this.currentVoiceEntry.LyricsEntries[lyricsEntry];
+                                        const val: LyricsEntry = this.currentVoiceEntry.LyricsEntries[lyricsEntry];
                                         if (!tieStartNote.ParentVoiceEntry.LyricsEntries.hasOwnProperty(lyricsEntry)) {
                                             tieStartNote.ParentVoiceEntry.LyricsEntries[lyricsEntry] = val;
                                             val.Parent = tieStartNote.ParentVoiceEntry;
@@ -860,29 +871,29 @@ export class VoiceGenerator {
                             }
                         }
                     } catch (err) {
-                        let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/TieError", "Error while reading tie.");
+                        const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/TieError", "Error while reading tie.");
                         this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
                     }
 
                 }
             } else if (tieNodeList.length === 2) {
-                let tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
+                const tieNumber: number = this.findCurrentNoteInTieDict(this.currentNote);
                 if (tieNumber >= 0) {
-                    let tie: Tie = this.openTieDict[tieNumber];
-                    let tieStartNote: Note = tie.Start;
+                    const tie: Tie = this.openTieDict[tieNumber];
+                    const tieStartNote: Note = tie.Start;
                     tieStartNote.Length.Add(this.currentNote.Length);
                     tie.Fractions.push(this.currentNote.Length);
                     if (this.currentNote.NoteBeam !== undefined) {
-                        let noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
+                        const noteBeamIndex: number = this.currentNote.NoteBeam.Notes.indexOf(this.currentNote);
                         if (noteBeamIndex === 0 && tie.BeamStartTimestamp === undefined) {
                             tie.BeamStartTimestamp = Fraction.plus(measureStartAbsoluteTimestamp, this.currentVoiceEntry.Timestamp);
                         }
-                        let noteBeam: Beam = this.currentNote.NoteBeam;
+                        const noteBeam: Beam = this.currentNote.NoteBeam;
                         noteBeam.Notes[noteBeamIndex] = tieStartNote;
                         tie.TieBeam = noteBeam;
                     }
                     for (let idx: number = 0, len: number = this.currentNote.NoteSlurs.length; idx < len; ++idx) {
-                        let slur: Slur = this.currentNote.NoteSlurs[idx];
+                        const slur: Slur = this.currentNote.NoteSlurs[idx];
                         if (slur.StartNote === this.currentNote) {
                             slur.StartNote = tie.Start;
                             slur.StartNote.NoteSlurs.push(slur);
@@ -903,7 +914,7 @@ export class VoiceGenerator {
                         maxTieNoteFraction = Fraction.plus(this.currentStaffEntry.Timestamp, this.currentNote.Length);
                     }
                     // delete currentNote from Notes:
-                    let i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
+                    const i: number = this.currentVoiceEntry.Notes.indexOf(this.currentNote);
                     if (i !== -1) { this.currentVoiceEntry.Notes.splice(i, 1); }
                 }
             }
@@ -915,7 +926,7 @@ export class VoiceGenerator {
      * @returns {number}
      */
     private getNextAvailableNumberForTie(): number {
-        let keys: string[] = Object.keys(this.openTieDict);
+        const keys: string[] = Object.keys(this.openTieDict);
         if (keys.length === 0) { return 1; }
         keys.sort((a, b) => (+a - +b)); // FIXME Andrea: test
         for (let i: number = 0; i < keys.length; i++) {
@@ -932,10 +943,10 @@ export class VoiceGenerator {
      * @returns {number}
      */
     private findCurrentNoteInTieDict(candidateNote: Note): number {
-        let openTieDict: { [_: number]: Tie; } = this.openTieDict;
-        for (let key in openTieDict) {
+        const openTieDict: { [_: number]: Tie; } = this.openTieDict;
+        for (const key in openTieDict) {
             if (openTieDict.hasOwnProperty(key)) {
-                let tie: Tie = openTieDict[key];
+                const tie: Tie = openTieDict[key];
                 if (tie.Start.Pitch.FundamentalNote === candidateNote.Pitch.FundamentalNote && tie.Start.Pitch.Octave === candidateNote.Pitch.Octave) {
                     return +key;
                 }
@@ -951,13 +962,13 @@ export class VoiceGenerator {
      */
     private getTupletNoteDurationFromType(xmlNode: IXmlElement): Fraction {
         if (xmlNode.element("type") !== undefined) {
-            let typeNode: IXmlElement = xmlNode.element("type");
+            const typeNode: IXmlElement = xmlNode.element("type");
             if (typeNode !== undefined) {
-                let type: string = typeNode.value;
+                const type: string = typeNode.value;
                 try {
                     return this.getNoteDurationFromType(type);
                 } catch (e) {
-                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid note duration.");
+                    const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid note duration.");
                     this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
                     throw new MusicSheetReadingException("", e);
                 }

+ 36 - 36
src/MusicalScore/SubInstrument.ts

@@ -13,58 +13,58 @@ export class SubInstrument {
     }
 
     private static midiInstrument: { [key: string]: MidiInstrument; } = {
+        "alt": MidiInstrument.Synth_Voice,
+        "alto": MidiInstrument.Synth_Voice,
+        "banjo": MidiInstrument.Banjo,
+        "bariton": MidiInstrument.Synth_Voice,
+        "baritone": MidiInstrument.Synth_Voice,
+        "bass": MidiInstrument.Synth_Voice,
+        "blockflöte": MidiInstrument.Recorder,
+        "brass": MidiInstrument.Trombone,
+        "bratsche": MidiInstrument.Viola,
         "cello": MidiInstrument.Cello,
-        "violon-c": MidiInstrument.Cello,
-        "contrabass": MidiInstrument.Contrabass,
-        "kontrabass": MidiInstrument.Contrabass,
         "clarinet": MidiInstrument.Clarinet,
-        "klarinette": MidiInstrument.Clarinet,
+        "contrabass": MidiInstrument.Contrabass,
+        "drums": MidiInstrument.Percussion,
         "flute": MidiInstrument.Flute,
         "flöte": MidiInstrument.Flute,
         "frenchhorn": MidiInstrument.French_Horn,
-        "guitar": MidiInstrument.Acoustic_Guitar_nylon,
         "gitarre": MidiInstrument.Acoustic_Guitar_nylon,
-        "harp": MidiInstrument.Orchestral_Harp,
+        "guitar": MidiInstrument.Acoustic_Guitar_nylon,
         "harfe": MidiInstrument.Orchestral_Harp,
+        "harp": MidiInstrument.Orchestral_Harp,
+        "klarinette": MidiInstrument.Clarinet,
+        "klavier": MidiInstrument.Acoustic_Grand_Piano,
+        "kontrabass": MidiInstrument.Contrabass,
         "oboe": MidiInstrument.Oboe,
         "organ": MidiInstrument.Church_Organ,
-        "orgue": MidiInstrument.Church_Organ,
         "orgel": MidiInstrument.Church_Organ,
+        "orgue": MidiInstrument.Church_Organ,
+        "percussion": MidiInstrument.Percussion,
         "piano": MidiInstrument.Acoustic_Grand_Piano,
-        "klavier": MidiInstrument.Acoustic_Grand_Piano,
         "piccolo": MidiInstrument.Piccolo,
-        "strings": MidiInstrument.String_Ensemble_1,
-        "streicher": MidiInstrument.String_Ensemble_1,
+        "posaune": MidiInstrument.Trombone,
+        "recorder": MidiInstrument.Recorder,
+        "sax": MidiInstrument.Tenor_Sax,
+        "schlagwerk": MidiInstrument.Percussion,
+        "schlagzeug": MidiInstrument.Percussion,
+        "sopran": MidiInstrument.Synth_Voice,
         "steeldrum": MidiInstrument.Steel_Drums,
+        "streicher": MidiInstrument.String_Ensemble_1,
+        "strings": MidiInstrument.String_Ensemble_1,
+        "tenor": MidiInstrument.Synth_Voice,
+        "tpt": MidiInstrument.Trumpet,
         "trombone": MidiInstrument.Trombone,
-        "posaune": MidiInstrument.Trombone,
-        "brass": MidiInstrument.Trombone,
-        "trumpet": MidiInstrument.Trumpet,
         "trompete": MidiInstrument.Trumpet,
-        "tpt": MidiInstrument.Trumpet,
+        "trumpet": MidiInstrument.Trumpet,
         "tuba": MidiInstrument.Tuba,
-        "sax": MidiInstrument.Tenor_Sax,
+        "unnamed": MidiInstrument.Acoustic_Grand_Piano,
         "viola": MidiInstrument.Viola,
-        "bratsche": MidiInstrument.Viola,
         "violin": MidiInstrument.Violin,
+        "violon-c": MidiInstrument.Cello,
         "violon.": MidiInstrument.Violin,
-        "woodblock": MidiInstrument.Woodblock,
-        "alt": MidiInstrument.Synth_Voice,
-        "alto": MidiInstrument.Synth_Voice,
-        "tenor": MidiInstrument.Synth_Voice,
-        "bariton": MidiInstrument.Synth_Voice,
-        "baritone": MidiInstrument.Synth_Voice,
-        "bass": MidiInstrument.Synth_Voice,
-        "sopran": MidiInstrument.Synth_Voice,
         "voice": MidiInstrument.Synth_Voice,
-        "recorder": MidiInstrument.Recorder,
-        "blockflöte": MidiInstrument.Recorder,
-        "banjo": MidiInstrument.Banjo,
-        "drums": MidiInstrument.Percussion,
-        "percussion": MidiInstrument.Percussion,
-        "schlagzeug": MidiInstrument.Percussion,
-        "schlagwerk": MidiInstrument.Percussion,
-        "unnamed": MidiInstrument.Acoustic_Grand_Piano,
+        "woodblock": MidiInstrument.Woodblock
     };
 
     public idString: string;
@@ -94,16 +94,16 @@ export class SubInstrument {
         // FIXME: test this function
         try {
             if (instrumentType) {
-                let tmpName: string = instrumentType.toLowerCase().trim();
-                for (let key in SubInstrument.midiInstrument) {
+                const tmpName: string = instrumentType.toLowerCase().trim();
+                for (const key in SubInstrument.midiInstrument) {
                     if (tmpName.indexOf(key) !== -1) {
                         return key;
                     }
                 }
             }
             if (this.parentInstrument.Name) {
-                let tmpName: string = this.parentInstrument.Name.toLowerCase().trim();
-                for (let key in SubInstrument.midiInstrument) {
+                const tmpName: string = this.parentInstrument.Name.toLowerCase().trim();
+                for (const key in SubInstrument.midiInstrument) {
                     if (tmpName.indexOf(key) !== -1) {
                         return key;
                     }

+ 1 - 1
src/MusicalScore/VoiceData/Expressions/AbstractExpression.ts

@@ -4,7 +4,7 @@ export class AbstractExpression {
     //}
     protected static isStringInStringList(stringList: Array<string>, inputString: string): boolean {
         for (let idx: number = 0, len: number = stringList.length; idx < len; ++idx) {
-            let s: string = stringList[idx];
+            const s: string = stringList[idx];
             if (inputString.toLowerCase() === s.toLowerCase().trim()) {
                 return true;
             }

+ 1 - 1
src/MusicalScore/VoiceData/Expressions/AbstractTempoExpression.ts

@@ -38,7 +38,7 @@ export abstract class AbstractTempoExpression {
     }
 
     protected static isStringInStringList(wordsToFind: string[], inputString: string): boolean {
-        for (let wordToFind of wordsToFind) {
+        for (const wordToFind of wordsToFind) {
             if (AbstractTempoExpression.stringContainsSeparatedWord(inputString.toLowerCase().trim(), wordToFind.toLowerCase().trim())) {
                 return true;
             }

+ 3 - 3
src/MusicalScore/VoiceData/Expressions/ContinuousExpressions/ContinuousDynamicExpression.ts

@@ -91,7 +91,7 @@ export class ContinuousDynamicExpression extends AbstractExpression {
         );
     }
     public getInterpolatedDynamic(currentAbsoluteTimestamp: Fraction): number {
-        let continuousAbsoluteStartTimestamp: Fraction = this.StartMultiExpression.AbsoluteTimestamp;
+        const continuousAbsoluteStartTimestamp: Fraction = this.StartMultiExpression.AbsoluteTimestamp;
         let continuousAbsoluteEndTimestamp: Fraction;
         if (this.EndMultiExpression !== undefined) {
             continuousAbsoluteEndTimestamp = this.EndMultiExpression.AbsoluteTimestamp;
@@ -102,10 +102,10 @@ export class ContinuousDynamicExpression extends AbstractExpression {
         }
         if (currentAbsoluteTimestamp.lt(continuousAbsoluteStartTimestamp)) { return -1; }
         if (continuousAbsoluteEndTimestamp.lt(currentAbsoluteTimestamp)) { return -2; }
-        let interpolationRatio: number =
+        const interpolationRatio: number =
             Fraction.minus(currentAbsoluteTimestamp, continuousAbsoluteStartTimestamp).RealValue
             / Fraction.minus(continuousAbsoluteEndTimestamp, continuousAbsoluteStartTimestamp).RealValue;
-        let interpolatedVolume: number = Math.max(0.0, Math.min(99.9, this.startVolume + (this.endVolume - this.startVolume) * interpolationRatio));
+        const interpolatedVolume: number = Math.max(0.0, Math.min(99.9, this.startVolume + (this.endVolume - this.startVolume) * interpolationRatio));
         return interpolatedVolume;
     }
     public isWedge(): boolean {

+ 3 - 3
src/MusicalScore/VoiceData/Expressions/ContinuousExpressions/ContinuousTempoExpression.ts

@@ -68,15 +68,15 @@ export class ContinuousTempoExpression extends AbstractTempoExpression {
         return this.ParentMultiTempoExpression.AbsoluteTimestamp.RealValue;
     }
     public getInterpolatedTempo(currentAbsoluteTimestamp: Fraction): number {
-        let continuousAbsoluteStartTimestamp: Fraction = Fraction.plus(
+        const continuousAbsoluteStartTimestamp: Fraction = Fraction.plus(
             this.parentMultiTempoExpression.SourceMeasureParent.AbsoluteTimestamp, this.parentMultiTempoExpression.Timestamp
         );
         if (currentAbsoluteTimestamp.lt(continuousAbsoluteStartTimestamp)) { return -1; }
         if (this.absoluteEndTimestamp.lt(currentAbsoluteTimestamp)) { return -2; }
-        let interpolationRatio: number =
+        const interpolationRatio: number =
             Fraction.minus(currentAbsoluteTimestamp, continuousAbsoluteStartTimestamp).RealValue
             / Fraction.minus(this.absoluteEndTimestamp, continuousAbsoluteStartTimestamp).RealValue;
-        let interpolatedTempo: number = Math.max(0.0, Math.min(250.0, this.startTempo + (this.endTempo - this.startTempo) * interpolationRatio));
+        const interpolatedTempo: number = Math.max(0.0, Math.min(250.0, this.startTempo + (this.endTempo - this.startTempo) * interpolationRatio));
         return interpolatedTempo;
     }
 

+ 5 - 5
src/MusicalScore/VoiceData/Expressions/ContinuousExpressions/Slur.ts

@@ -24,7 +24,7 @@ export class Slur {
     public startNoteHasMoreStartingSlurs(): boolean {
         if (this.startNote === undefined) { return false; }
         for (let idx: number = 0, len: number = this.startNote.NoteSlurs.length; idx < len; ++idx) {
-            let slur: Slur = this.startNote.NoteSlurs[idx];
+            const slur: Slur = this.startNote.NoteSlurs[idx];
             if (slur !== this && slur.StartNote === this.startNote) {
                 return true;
             }
@@ -34,7 +34,7 @@ export class Slur {
     public endNoteHasMoreEndingSlurs(): boolean {
         if (this.endNote === undefined) { return false; }
         for (let idx: number = 0, len: number = this.endNote.NoteSlurs.length; idx < len; ++idx) {
-            let slur: Slur = this.endNote.NoteSlurs[idx];
+            const slur: Slur = this.endNote.NoteSlurs[idx];
             if (slur !== this && slur.EndNote === this.endNote) {
                 return true;
             }
@@ -48,9 +48,9 @@ export class Slur {
         if (this.endNote === undefined || this.startNote === undefined) {
             return false;
         }
-        let length: Fraction = Fraction.minus(this.endNote.getAbsoluteTimestamp(), this.startNote.getAbsoluteTimestamp());
+        const length: Fraction = Fraction.minus(this.endNote.getAbsoluteTimestamp(), this.startNote.getAbsoluteTimestamp());
         for (let idx: number = 0, len: number = this.startNote.NoteSlurs.length; idx < len; ++idx) {
-            let slur: Slur = this.startNote.NoteSlurs[idx];
+            const slur: Slur = this.startNote.NoteSlurs[idx];
             if (
                 slur !== this
                 && slur.EndNote !== undefined
@@ -61,7 +61,7 @@ export class Slur {
             }
         }
         for (let idx: number = 0, len: number = this.endNote.NoteSlurs.length; idx < len; ++idx) {
-            let slur: Slur = this.endNote.NoteSlurs[idx];
+            const slur: Slur = this.endNote.NoteSlurs[idx];
             if (
                 slur !== this
                 && slur.EndNote !== undefined

+ 11 - 11
src/MusicalScore/VoiceData/Expressions/InstantaniousDynamicExpression.ts

@@ -14,12 +14,14 @@ export class InstantaniousDynamicExpression extends AbstractExpression {
         this.staffNumber = staffNumber;
     }
     public static dynamicToRelativeVolumeDict: { [_: string]: number; } = {
-        "ffffff": (127.0 / 127.0),
-        "fffff": (126.0 / 127.0) ,
-        "ffff": 125.0 / 127.0,
-        "fff": 124.0 / 127.0,
-        "ff": 108.0 / 127.0,
         "f": 92.0 / 127.0,
+        "ff": 108.0 / 127.0,
+        "fff": 124.0 / 127.0,
+        "ffff": 125.0 / 127.0,
+        "fffff": (126.0 / 127.0) ,
+        "ffffff": (127.0 / 127.0),
+        "fp": 0.5,
+        "fz": 0.5,
         "mf": 76.0 / 127.0,
         "mp": 60.0 / 127.0,
         "p": 44.0 / 127.0,
@@ -28,15 +30,13 @@ export class InstantaniousDynamicExpression extends AbstractExpression {
         "pppp": 10.0 / 127.0,
         "ppppp": 8.0 / 127.0,
         "pppppp": 6.0 / 127.0,
-        "sf": 0.5,
-        "sfp": 0.5,
-        "sfpp": 0.5,
-        "fp": 0.5,
         "rf": 0.5,
         "rfz": 0.5,
-        "sfz": 0.5,
+        "sf": 0.5,
         "sffz": 0.5,
-        "fz": 0.5,
+        "sfp": 0.5,
+        "sfpp": 0.5,
+        "sfz": 0.5
     };
 
     //private static weight: number;

+ 2 - 2
src/MusicalScore/VoiceData/Expressions/MultiExpression.ts

@@ -170,7 +170,7 @@ export class MultiExpression /*implements IComparable<MultiExpression>*/ {
         }
     }
     private addExpressionToEntryList(expression: AbstractExpression, prefix: string): void {
-        let multiExpressionEntry: MultiExpressionEntry = new MultiExpressionEntry();
+        const multiExpressionEntry: MultiExpressionEntry = new MultiExpressionEntry();
         multiExpressionEntry.prefix = prefix;
         multiExpressionEntry.expression = expression;
         if (expression instanceof ContinuousDynamicExpression) {
@@ -186,7 +186,7 @@ export class MultiExpression /*implements IComparable<MultiExpression>*/ {
     }
     private removeExpressionFromEntryList(expression: AbstractExpression): void {
         for (let idx: number = 0, len: number = this.expressions.length; idx < len; ++idx) {
-            let entry: MultiExpressionEntry = this.expressions[idx];
+            const entry: MultiExpressionEntry = this.expressions[idx];
             if (entry.expression === expression) {
                 this.expressions.splice(idx, 1);
                 break;

+ 1 - 1
src/MusicalScore/VoiceData/Expressions/MultiTempoExpression.ts

@@ -86,7 +86,7 @@ export class MultiTempoExpression /*implements IComparable<MultiTempoExpression>
         } else if (abstractTempoExpression instanceof ContinuousTempoExpression) {
             this.continuousTempo = <ContinuousTempoExpression>abstractTempoExpression;
         }
-        let tempoExpressionEntry: TempoExpressionEntry = new TempoExpressionEntry();
+        const tempoExpressionEntry: TempoExpressionEntry = new TempoExpressionEntry();
         tempoExpressionEntry.prefix = prefix;
         tempoExpressionEntry.expression = abstractTempoExpression;
         tempoExpressionEntry.label = abstractTempoExpression.Label;

+ 3 - 3
src/MusicalScore/VoiceData/Instructions/ClefInstruction.ts

@@ -48,13 +48,13 @@ export class ClefInstruction extends AbstractNotationInstruction {
     }
 
     public static getAllPossibleClefs(): ClefInstruction[] {
-        let clefList: ClefInstruction[] = [];
+        const clefList: ClefInstruction[] = [];
         for (let i: number = 0; i <= 2; i++) {
-            let clefInstructionG: ClefInstruction = new ClefInstruction(ClefEnum.G, i, 2);
+            const clefInstructionG: ClefInstruction = new ClefInstruction(ClefEnum.G, i, 2);
             clefList.push(clefInstructionG);
         }
         for (let j: number = -2; j <= 0; j++) {
-            let clefInstructionF: ClefInstruction = new ClefInstruction(ClefEnum.F, j, 4);
+            const clefInstructionF: ClefInstruction = new ClefInstruction(ClefEnum.F, j, 4);
             clefList.push(clefInstructionF);
         }
         return clefList;

+ 13 - 6
src/MusicalScore/VoiceData/Instructions/KeyInstruction.ts

@@ -21,12 +21,12 @@ export class KeyInstruction extends AbstractNotationInstruction {
     private mode: KeyEnum;
 
     public static copy(keyInstruction: KeyInstruction): KeyInstruction {
-        let newKeyInstruction: KeyInstruction = new KeyInstruction(keyInstruction.parent, keyInstruction.Key, keyInstruction.Mode);
+        const newKeyInstruction: KeyInstruction = new KeyInstruction(keyInstruction.parent, keyInstruction.Key, keyInstruction.Mode);
         return newKeyInstruction;
     }
 
     public static getNoteEnumList(instruction: KeyInstruction): NoteEnum[] {
-        let enums: NoteEnum[] = [];
+        const enums: NoteEnum[] = [];
         if (instruction.keyType > 0) {
             for (let i: number = 0; i < instruction.keyType; i++) {
                 enums.push(KeyInstruction.sharpPositionList[i]);
@@ -41,9 +41,9 @@ export class KeyInstruction extends AbstractNotationInstruction {
     }
 
     public static getAllPossibleMajorKeyInstructions(): KeyInstruction[] {
-        let keyInstructionList: KeyInstruction[] = [];
+        const keyInstructionList: KeyInstruction[] = [];
         for (let keyType: number = -7; keyType < 7; keyType++) {
-            let currentKeyInstruction: KeyInstruction = new KeyInstruction(undefined, keyType, KeyEnum.major);
+            const currentKeyInstruction: KeyInstruction = new KeyInstruction(undefined, keyType, KeyEnum.major);
             keyInstructionList.push(currentKeyInstruction);
         }
         return keyInstructionList;
@@ -66,7 +66,7 @@ export class KeyInstruction extends AbstractNotationInstruction {
     }
 
     public getFundamentalNotesOfAccidentals(): NoteEnum[] {
-        let noteList: NoteEnum[] = [];
+        const noteList: NoteEnum[] = [];
         if (this.keyType > 0) {
             for (let i: number = 0; i < this.keyType; i++) {
                 noteList.push(KeyInstruction.sharpPositionList[i]);
@@ -93,7 +93,7 @@ export class KeyInstruction extends AbstractNotationInstruction {
     }
 
     public OperatorEquals(key2: KeyInstruction): boolean {
-        let key1: KeyInstruction = this;
+        const key1: KeyInstruction = this;
         if (key1 === key2) {
             return true;
         }
@@ -122,4 +122,11 @@ export enum KeyEnum {
     major = 0,
     minor = 1,
     none = 2,
+    dorian = 3,
+    phrygian = 4,
+    lydian = 5,
+    mixolydian = 6,
+    aeolian = 7,
+    ionian = 8,
+    locrian = 9,
 }

+ 3 - 3
src/MusicalScore/VoiceData/Instructions/RepetitionInstruction.ts

@@ -56,9 +56,9 @@ export class RepetitionInstruction /*implements IComparable*/ {
     public alignment: AlignmentType;
     public parentRepetition: Repetition;
 
-    public static compare(one: RepetitionInstruction, other: RepetitionInstruction): number {
-
-        if (one.measureIndex > other.measureIndex) {
+    public CompareTo(obj: Object): number {
+        const other: RepetitionInstruction = <RepetitionInstruction>obj;
+        if (this.measureIndex > other.measureIndex) {
             return 1;
         } else if (one.measureIndex < other.measureIndex) {
             return -1;

+ 6 - 6
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,11 +35,11 @@ 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 {
-        let rhythm1: RhythmInstruction = this;
+        const rhythm1: RhythmInstruction = this;
         if (rhythm1 === rhythm2) {
             return true;
         }
@@ -50,7 +50,7 @@ export class RhythmInstruction extends AbstractNotationInstruction {
     }
 
     public OperatorNotEqual(rhythm2: RhythmInstruction): boolean {
-        let rhythm1: RhythmInstruction = this;
+        const rhythm1: RhythmInstruction = this;
         return !(rhythm1 === rhythm2);
     }
 

+ 2 - 2
src/MusicalScore/VoiceData/Lyrics/LyricsWord.ts

@@ -9,7 +9,7 @@ export class LyricWord {
     }
     public containsVoiceEntry(voiceEntry: VoiceEntry): boolean {
         for (let idx: number = 0, len: number = this.Syllables.length; idx < len; ++idx) {
-            let lyricsEntry: LyricsEntry = this.Syllables[idx];
+            const lyricsEntry: LyricsEntry = this.Syllables[idx];
             if (lyricsEntry.Parent === voiceEntry) {
                 return true;
             }
@@ -18,7 +18,7 @@ export class LyricWord {
     }
     public findLyricEntryInVoiceEntry(voiceEntry: VoiceEntry): LyricsEntry {
         for (let idx: number = 0, len: number = this.Syllables.length; idx < len; ++idx) {
-            let lyricsEntry: LyricsEntry = this.Syllables[idx];
+            const lyricsEntry: LyricsEntry = this.Syllables[idx];
             if (lyricsEntry.Parent === voiceEntry) {
                 return lyricsEntry;
             }

+ 4 - 4
src/MusicalScore/VoiceData/Note.ts

@@ -104,9 +104,9 @@ export class Note {
     }
 
     public calculateNoteLengthWithoutTie(): Fraction {
-        let withoutTieLength: Fraction = this.length.clone();
+        const withoutTieLength: Fraction = this.length.clone();
         if (this.tie !== undefined) {
-            for (let fraction of this.tie.Fractions) {
+            for (const fraction of this.tie.Fractions) {
                 withoutTieLength.Sub(fraction);
             }
         }
@@ -120,7 +120,7 @@ export class Note {
             return this.length;
         }
         if (originalLength.Numerator > 1) {
-            let exp: number = Math.floor(Math.log(originalLength.Denominator) / Math.LN2) - this.calculateNumberOfNeededDots(originalLength);
+            const exp: number = Math.floor(Math.log(originalLength.Denominator) / Math.LN2) - this.calculateNumberOfNeededDots(originalLength);
             originalLength.Denominator = Math.pow(2, exp);
             originalLength.Numerator = 1;
         }
@@ -141,7 +141,7 @@ export class Note {
     }
     public checkForDoubleSlur(slur: Slur): boolean {
         for (let idx: number = 0, len: number = this.slurs.length; idx < len; ++idx) {
-            let noteSlur: Slur = this.slurs[idx];
+            const noteSlur: Slur = this.slurs[idx];
             if (
               noteSlur.StartNote !== undefined &&
               noteSlur.EndNote !== undefined &&

+ 30 - 30
src/MusicalScore/VoiceData/SourceMeasure.ts

@@ -166,7 +166,7 @@ export class SourceMeasure extends BaseIdClass {
         let staffEntry: SourceStaffEntry = undefined;
         // Find:
         let existingVerticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer;
-        for (let container of this.verticalSourceStaffEntryContainers) {
+        for (const container of this.verticalSourceStaffEntryContainers) {
             if (container.Timestamp.Equals(inMeasureTimestamp)) {
                 existingVerticalSourceStaffEntryContainer = container;
                 break;
@@ -181,9 +181,9 @@ export class SourceMeasure extends BaseIdClass {
             }
             return {createdNewContainer: false, staffEntry: staffEntry};
         }
-        let last: VerticalSourceStaffEntryContainer = this.verticalSourceStaffEntryContainers[this.verticalSourceStaffEntryContainers.length - 1];
+        const last: VerticalSourceStaffEntryContainer = this.verticalSourceStaffEntryContainers[this.verticalSourceStaffEntryContainers.length - 1];
         if (this.verticalSourceStaffEntryContainers.length === 0 || last.Timestamp.lt(inMeasureTimestamp)) {
-            let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
+            const container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
                 this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
             );
             this.verticalSourceStaffEntryContainers.push(container);
@@ -195,7 +195,7 @@ export class SourceMeasure extends BaseIdClass {
                 i >= 0; i--
             ) {
                 if (this.verticalSourceStaffEntryContainers[i].Timestamp.lt(inMeasureTimestamp)) {
-                    let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
+                    const container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
                         this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
                     );
                     this.verticalSourceStaffEntryContainers.splice(i + 1, 0, container);
@@ -204,7 +204,7 @@ export class SourceMeasure extends BaseIdClass {
                     break;
                 }
                 if (i === 0) {
-                    let container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
+                    const container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(
                         this, inMeasureTimestamp.clone(), this.completeNumberOfStaves
                     );
                     this.verticalSourceStaffEntryContainers.splice(i, 0, container);
@@ -228,7 +228,7 @@ export class SourceMeasure extends BaseIdClass {
     public findOrCreateVoiceEntry(sse: SourceStaffEntry, voice: Voice): { createdVoiceEntry: boolean, voiceEntry: VoiceEntry } {
         let ve: VoiceEntry = undefined;
         let createdNewVoiceEntry: boolean = false;
-        for (let voiceEntry of sse.VoiceEntries) {
+        for (const voiceEntry of sse.VoiceEntries) {
             if (voiceEntry.ParentVoice === voice) {
                 ve = voiceEntry;
                 break;
@@ -279,7 +279,7 @@ export class SourceMeasure extends BaseIdClass {
      */
     public getVerticalContainerByTimestamp(musicTimestamp: Fraction): VerticalSourceStaffEntryContainer {
         for (let idx: number = 0, len: number = this.VerticalSourceStaffEntryContainers.length; idx < len; ++idx) {
-            let verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = this.VerticalSourceStaffEntryContainers[idx];
+            const verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = this.VerticalSourceStaffEntryContainers[idx];
             if (verticalSourceStaffEntryContainer.Timestamp.Equals(musicTimestamp)) {
                 return verticalSourceStaffEntryContainer;
             }
@@ -314,16 +314,16 @@ export class SourceMeasure extends BaseIdClass {
      */
     public reverseCheck(musicSheet: MusicSheet, maxInstDuration: Fraction): Fraction {
         let maxDuration: Fraction = new Fraction(0, 1);
-        let instrumentsDurations: Fraction[] = [];
+        const instrumentsDurations: Fraction[] = [];
         for (let i: number = 0; i < musicSheet.Instruments.length; i++) {
             let instrumentDuration: Fraction = new Fraction(0, 1);
-            let inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
+            const inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
             for (let j: number = 0; j < musicSheet.Instruments[i].Staves.length; j++) {
-                let lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
+                const lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
                 if (lastStaffEntry !== undefined && !lastStaffEntry.hasTie()) {
-                    let verticalContainerIndex: number = this.verticalSourceStaffEntryContainers.indexOf(lastStaffEntry.VerticalContainerParent);
+                    const verticalContainerIndex: number = this.verticalSourceStaffEntryContainers.indexOf(lastStaffEntry.VerticalContainerParent);
                     for (let m: number = verticalContainerIndex - 1; m >= 0; m--) {
-                        let previousStaffEntry: SourceStaffEntry = this.verticalSourceStaffEntryContainers[m][inSourceMeasureInstrumentIndex + j];
+                        const previousStaffEntry: SourceStaffEntry = this.verticalSourceStaffEntryContainers[m][inSourceMeasureInstrumentIndex + j];
                         if (previousStaffEntry !== undefined && previousStaffEntry.hasTie()) {
                             if (instrumentDuration.lt(Fraction.plus(previousStaffEntry.Timestamp, previousStaffEntry.calculateMaxNoteLength()))) {
                                 instrumentDuration = Fraction.plus(previousStaffEntry.Timestamp, previousStaffEntry.calculateMaxNoteLength());
@@ -336,7 +336,7 @@ export class SourceMeasure extends BaseIdClass {
             instrumentsDurations.push(instrumentDuration);
         }
         for (let idx: number = 0, len: number = instrumentsDurations.length; idx < len; ++idx) {
-            let instrumentsDuration: Fraction = instrumentsDurations[idx];
+            const instrumentsDuration: Fraction = instrumentsDurations[idx];
             if (maxDuration.lt(instrumentsDuration)) {
                 maxDuration = instrumentsDuration;
             }
@@ -352,12 +352,12 @@ export class SourceMeasure extends BaseIdClass {
      * @returns {Fraction[]}
      */
     public calculateInstrumentsDuration(musicSheet: MusicSheet, instrumentMaxTieNoteFractions: Fraction[]): Fraction[] {
-        let instrumentsDurations: Fraction[] = [];
+        const instrumentsDurations: Fraction[] = [];
         for (let i: number = 0; i < musicSheet.Instruments.length; i++) {
             let instrumentDuration: Fraction = new Fraction(0, 1);
-            let inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
+            const inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
             for (let j: number = 0; j < musicSheet.Instruments[i].Staves.length; j++) {
-                let lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
+                const lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
                 if (lastStaffEntry !== undefined && lastStaffEntry.Timestamp !== undefined) {
                     if (instrumentDuration.lt(Fraction.plus(lastStaffEntry.Timestamp, lastStaffEntry.calculateMaxNoteLength()))) {
                         instrumentDuration = Fraction.plus(lastStaffEntry.Timestamp, lastStaffEntry.calculateMaxNoteLength());
@@ -373,9 +373,9 @@ export class SourceMeasure extends BaseIdClass {
     }
 
     public getEntriesPerStaff(staffIndex: number): SourceStaffEntry[] {
-        let sourceStaffEntries: SourceStaffEntry[] = [];
-        for (let container of this.VerticalSourceStaffEntryContainers) {
-            let sse: SourceStaffEntry = container.StaffEntries[staffIndex];
+        const sourceStaffEntries: SourceStaffEntry[] = [];
+        for (const container of this.VerticalSourceStaffEntryContainers) {
+            const sse: SourceStaffEntry = container.StaffEntries[staffIndex];
             if (sse !== undefined) {
                 sourceStaffEntries.push(sse);
             }
@@ -389,7 +389,7 @@ export class SourceMeasure extends BaseIdClass {
      */
     public hasBeginInstructions(): boolean {
         for (let staffIndex: number = 0, len: number = this.FirstInstructionsStaffEntries.length; staffIndex < len; staffIndex++) {
-            let beginInstructionsStaffEntry: SourceStaffEntry = this.FirstInstructionsStaffEntries[staffIndex];
+            const beginInstructionsStaffEntry: SourceStaffEntry = this.FirstInstructionsStaffEntries[staffIndex];
             if (beginInstructionsStaffEntry !== undefined && beginInstructionsStaffEntry.Instructions.length > 0) {
                 return true;
             }
@@ -399,7 +399,7 @@ export class SourceMeasure extends BaseIdClass {
 
     public beginsWithLineRepetition(): boolean {
         for (let idx: number = 0, len: number = this.FirstRepetitionInstructions.length; idx < len; ++idx) {
-            let instr: RepetitionInstruction = this.FirstRepetitionInstructions[idx];
+            const instr: RepetitionInstruction = this.FirstRepetitionInstructions[idx];
             if (instr.parentRepetition !== undefined && instr === instr.parentRepetition.startMarker && !instr.parentRepetition.FromWords) {
                 return true;
             }
@@ -413,8 +413,8 @@ export class SourceMeasure extends BaseIdClass {
      */
     public endsWithLineRepetition(): boolean {
         for (let idx: number = 0, len: number = this.LastRepetitionInstructions.length; idx < len; ++idx) {
-            let instruction: RepetitionInstruction = this.LastRepetitionInstructions[idx];
-            let rep: Repetition = instruction.parentRepetition;
+            const instruction: RepetitionInstruction = this.LastRepetitionInstructions[idx];
+            const rep: Repetition = instruction.parentRepetition;
             if (rep === undefined) {
                 continue;
             }
@@ -422,7 +422,7 @@ export class SourceMeasure extends BaseIdClass {
                 continue;
             }
             for (let idx2: number = 0, len2: number = rep.BackwardJumpInstructions.length; idx2 < len2; ++idx2) {
-                let backJumpInstruction: RepetitionInstruction = rep.BackwardJumpInstructions[idx2];
+                const backJumpInstruction: RepetitionInstruction = rep.BackwardJumpInstructions[idx2];
                 if (instruction === backJumpInstruction) {
                     return true;
                 }
@@ -437,7 +437,7 @@ export class SourceMeasure extends BaseIdClass {
      */
     public beginsWithWordRepetition(): boolean {
         for (let idx: number = 0, len: number = this.FirstRepetitionInstructions.length; idx < len; ++idx) {
-            let instruction: RepetitionInstruction = this.FirstRepetitionInstructions[idx];
+            const instruction: RepetitionInstruction = this.FirstRepetitionInstructions[idx];
             if (instruction.parentRepetition !== undefined &&
                 instruction === instruction.parentRepetition.startMarker && instruction.parentRepetition.FromWords) {
                 return true;
@@ -452,8 +452,8 @@ export class SourceMeasure extends BaseIdClass {
      */
     public endsWithWordRepetition(): boolean {
         for (let idx: number = 0, len: number = this.LastRepetitionInstructions.length; idx < len; ++idx) {
-            let instruction: RepetitionInstruction = this.LastRepetitionInstructions[idx];
-            let rep: Repetition = instruction.parentRepetition;
+            const instruction: RepetitionInstruction = this.LastRepetitionInstructions[idx];
+            const rep: Repetition = instruction.parentRepetition;
             if (rep === undefined) {
                 continue;
             }
@@ -461,7 +461,7 @@ export class SourceMeasure extends BaseIdClass {
                 continue;
             }
             for (let idx2: number = 0, len2: number = rep.BackwardJumpInstructions.length; idx2 < len2; ++idx2) {
-                let backJumpInstruction: RepetitionInstruction = rep.BackwardJumpInstructions[idx2];
+                const backJumpInstruction: RepetitionInstruction = rep.BackwardJumpInstructions[idx2];
                 if (instruction === backJumpInstruction) {
                     return true;
                 }
@@ -475,9 +475,9 @@ export class SourceMeasure extends BaseIdClass {
 
     public getKeyInstruction(staffIndex: number): KeyInstruction {
         if (this.FirstInstructionsStaffEntries[staffIndex] !== undefined) {
-            let sourceStaffEntry: SourceStaffEntry = this.FirstInstructionsStaffEntries[staffIndex];
+            const sourceStaffEntry: SourceStaffEntry = this.FirstInstructionsStaffEntries[staffIndex];
             for (let idx: number = 0, len: number = sourceStaffEntry.Instructions.length; idx < len; ++idx) {
-                let abstractNotationInstruction: AbstractNotationInstruction = sourceStaffEntry.Instructions[idx];
+                const abstractNotationInstruction: AbstractNotationInstruction = sourceStaffEntry.Instructions[idx];
                 if (abstractNotationInstruction instanceof KeyInstruction) {
                     return <KeyInstruction>abstractNotationInstruction;
                 }

+ 9 - 9
src/MusicalScore/VoiceData/SourceStaffEntry.ts

@@ -194,9 +194,9 @@ export class SourceStaffEntry {
     public calculateMinNoteLength(): Fraction {
         let duration: Fraction = new Fraction(Number.MAX_VALUE, 1);
         for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
-            let voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
             for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) {
-                let note: Note = voiceEntry.Notes[idx2];
+                const note: Note = voiceEntry.Notes[idx2];
                 if (note.NoteTie !== undefined) {
                     if (note.calculateNoteLengthWithoutTie().lt(duration)) {
                         duration = note.calculateNoteLengthWithoutTie();
@@ -212,14 +212,14 @@ export class SourceStaffEntry {
     public calculateMaxNoteLength(): Fraction {
         let duration: Fraction = new Fraction(0, 1);
         for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
-            let voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
             for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) {
-                let note: Note = voiceEntry.Notes[idx2];
+                const note: Note = voiceEntry.Notes[idx2];
                 if (note.NoteTie !== undefined) {
                     if (duration < note.calculateNoteLengthWithoutTie()) {
                         duration = note.calculateNoteLengthWithoutTie();
                         for (let idx3: number = 0, len3: number = note.NoteTie.Fractions.length; idx3 < len3; ++idx3) {
-                            let fraction: Fraction = note.NoteTie.Fractions[idx3];
+                            const fraction: Fraction = note.NoteTie.Fractions[idx3];
                             duration.Add(fraction);
                         }
                     }
@@ -233,7 +233,7 @@ export class SourceStaffEntry {
 
     public hasNotes(): boolean {
         for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
-            let voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
             if (voiceEntry.Notes.length > 0) {
                 return true;
             }
@@ -243,7 +243,7 @@ export class SourceStaffEntry {
 
     public hasTie(): boolean {
         for (let idx: number = 0, len: number = this.VoiceEntries.length; idx < len; ++idx) {
-            let voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            const voiceEntry: VoiceEntry = this.VoiceEntries[idx];
             if (voiceEntry.hasTie()) {
                 return true;
             }
@@ -253,9 +253,9 @@ export class SourceStaffEntry {
 
     public findLinkedNotes(linkedNotes: Note[]): void {
         for (let idx: number = 0, len: number = this.voiceEntries.length; idx < len; ++idx) {
-            let voiceEntry: VoiceEntry = this.voiceEntries[idx];
+            const voiceEntry: VoiceEntry = this.voiceEntries[idx];
             for (let idx2: number = 0, len2: number = voiceEntry.Notes.length; idx2 < len2; ++idx2) {
-                let note: Note = voiceEntry.Notes[idx2];
+                const note: Note = voiceEntry.Notes[idx2];
                 if (note.ParentStaffEntry === this) {
                     linkedNotes.push(note);
                 }

+ 1 - 1
src/MusicalScore/VoiceData/Tie.ts

@@ -68,7 +68,7 @@ export class Tie extends BaseIdClass {
         this.noteHasBeenCreated = new Array(this.fractions.length);
     }
     public allGraphicalNotesHaveBeenCreated(): boolean {
-        for (let b of this.noteHasBeenCreated) {
+        for (const b of this.noteHasBeenCreated) {
             if (!b) {
                 return false;
             }

+ 1 - 1
src/MusicalScore/VoiceData/Tuplet.ts

@@ -39,7 +39,7 @@ export class Tuplet {
     }
 
     /**
-     * Return the index of the first List (notes[0], notes[1],...).
+     * Returns the index of the given Note in the Tuplet List (notes[0], notes[1],...).
      * @param note
      * @returns {number}
      */

+ 0 - 2
src/MusicalScore/VoiceData/VerticalSourceStaffEntryContainer.ts

@@ -9,13 +9,11 @@ export class VerticalSourceStaffEntryContainer {
 
     constructor(parentMeasure: SourceMeasure, timestamp: Fraction, size: number) {
         this.timestamp = timestamp;
-        this.size = size;
         this.staffEntries = new Array(size);
         this.parentMeasure = parentMeasure;
     }
 
     private timestamp: Fraction;
-    private size: number;
     private staffEntries: SourceStaffEntry[] = [];
     private comments: Comment[] = [];
     private parentMeasure: SourceMeasure;

+ 50 - 50
src/MusicalScore/VoiceData/VoiceEntry.ts

@@ -102,28 +102,28 @@ export class VoiceEntry {
     }
     public hasTie(): boolean {
         for (let idx: number = 0, len: number = this.Notes.length; idx < len; ++idx) {
-            let note: Note = this.Notes[idx];
+            const note: Note = this.Notes[idx];
             if (note.NoteTie !== undefined) { return true; }
         }
         return false;
     }
     public hasSlur(): boolean {
         for (let idx: number = 0, len: number = this.Notes.length; idx < len; ++idx) {
-            let note: Note = this.Notes[idx];
+            const note: Note = this.Notes[idx];
             if (note.NoteSlurs.length > 0) { return true; }
         }
         return false;
     }
     public isStaccato(): boolean {
         for (let idx: number = 0, len: number = this.Articulations.length; idx < len; ++idx) {
-            let articulation: ArticulationEnum = this.Articulations[idx];
+            const articulation: ArticulationEnum = this.Articulations[idx];
             if (articulation === ArticulationEnum.staccato) { return true; }
         }
         return false;
     }
     public isAccent(): boolean {
         for (let idx: number = 0, len: number = this.Articulations.length; idx < len; ++idx) {
-            let articulation: ArticulationEnum = this.Articulations[idx];
+            const articulation: ArticulationEnum = this.Articulations[idx];
             if (articulation === ArticulationEnum.accent || articulation === ArticulationEnum.strongaccent) {
                 return true;
             }
@@ -146,20 +146,20 @@ export class VoiceEntry {
         if (voiceEntryWithOrnament === undefined) {
             voiceEntryWithOrnament = this;
         }
-        let voiceEntries: VoiceEntry[] = [];
+        const voiceEntries: VoiceEntry[] = [];
         if (voiceEntryWithOrnament.ornamentContainer === undefined) {
             return;
         }
-        let baseNote: Note = this.notes[0];
-        let baselength: Fraction = baseNote.calculateNoteLengthWithoutTie();
-        let baseVoice: Voice = voiceEntryWithOrnament.ParentVoice;
-        let baseTimestamp: Fraction = voiceEntryWithOrnament.Timestamp;
+        const baseNote: Note = this.notes[0];
+        const baselength: Fraction = baseNote.calculateNoteLengthWithoutTie();
+        const baseVoice: Voice = voiceEntryWithOrnament.ParentVoice;
+        const baseTimestamp: Fraction = voiceEntryWithOrnament.Timestamp;
         let currentTimestamp: Fraction = Fraction.createFromFraction(baseTimestamp);
         //let length: Fraction;
         switch (voiceEntryWithOrnament.ornamentContainer.GetOrnament) {
             case OrnamentEnum.Trill: {
-                let length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 8);
-                let higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 8);
+                const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
                 let alteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
                 if (voiceEntryWithOrnament.OrnamentContainer.AccidentalAbove !== AccidentalEnum.NONE) {
                     alteration = <AccidentalEnum><number>voiceEntryWithOrnament.ornamentContainer.AccidentalAbove;
@@ -172,14 +172,14 @@ export class VoiceEntry {
                         this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, alteration, voiceEntries);
                     }
                 }
-            }
                 break;
+            }
             case OrnamentEnum.Turn: {
-                let length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
-                let lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
-                let lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
-                let higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
-                let higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
                 this.createAlteratedVoiceEntry(
                     currentTimestamp, length, baseVoice, higherPitch, higherAlteration, voiceEntries
                 );
@@ -191,14 +191,14 @@ export class VoiceEntry {
                 );
                 currentTimestamp.Add(length);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
-            }
                 break;
+            }
             case OrnamentEnum.InvertedTurn: {
-                let length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
-                let lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
-                let lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
-                let higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
-                let higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
                 this.createAlteratedVoiceEntry(
                     currentTimestamp, length, baseVoice, lowerPitch, lowerAlteration, voiceEntries
                 );
@@ -210,14 +210,14 @@ export class VoiceEntry {
                 );
                 currentTimestamp.Add(length);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
-            }
                 break;
+            }
             case OrnamentEnum.DelayedTurn: {
-                let length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 2);
-                let lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
-                let lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
-                let higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
-                let higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 2);
+                const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
                 currentTimestamp = Fraction.plus(baseTimestamp, length);
                 length.Denominator = baselength.Denominator * 8;
@@ -228,14 +228,14 @@ export class VoiceEntry {
                 this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, lowerPitch, lowerAlteration, voiceEntries);
                 currentTimestamp.Add(length);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
-            }
                 break;
+            }
             case OrnamentEnum.DelayedInvertedTurn: {
-                let length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 2);
-                let lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
-                let lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
-                let higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
-                let higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 2);
+                const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                const lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                const higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
                 currentTimestamp = Fraction.plus(baseTimestamp, length);
                 length.Denominator = baselength.Denominator * 8;
@@ -246,32 +246,32 @@ export class VoiceEntry {
                 this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, higherAlteration, voiceEntries);
                 currentTimestamp.Add(length);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
-            }
                 break;
+            }
             case OrnamentEnum.Mordent: {
-                let length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
-                let higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
-                let alteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                const higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                const alteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
                 currentTimestamp.Add(length);
                 this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, alteration, voiceEntries);
                 length.Denominator = baselength.Denominator * 2;
                 currentTimestamp = Fraction.plus(baseTimestamp, length);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
-            }
                 break;
+            }
             case OrnamentEnum.InvertedMordent: {
-                let length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
-                let lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
-                let alteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                const length: Fraction = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                const lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                const alteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
                 currentTimestamp.Add(length);
                 this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, lowerPitch, alteration, voiceEntries);
                 length.Denominator = baselength.Denominator * 2;
                 currentTimestamp = Fraction.plus(baseTimestamp, length);
                 this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
-            }
                 break;
+            }
             default:
                 throw new RangeError();
         }
@@ -280,9 +280,9 @@ export class VoiceEntry {
     private createBaseVoiceEntry(
         currentTimestamp: Fraction, length: Fraction, baseVoice: Voice, baseNote: Note, voiceEntries: VoiceEntry[]
     ): void {
-        let voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, baseNote.ParentStaffEntry);
-        let pitch: Pitch = new Pitch(baseNote.Pitch.FundamentalNote, baseNote.Pitch.Octave, baseNote.Pitch.Accidental);
-        let note: Note = new Note(voiceEntry, undefined, length, pitch);
+        const voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, baseNote.ParentStaffEntry);
+        const pitch: Pitch = new Pitch(baseNote.Pitch.FundamentalNote, baseNote.Pitch.Octave, baseNote.Pitch.Accidental);
+        const note: Note = new Note(voiceEntry, undefined, length, pitch);
         voiceEntry.Notes.push(note);
         voiceEntries.push(voiceEntry);
     }
@@ -290,9 +290,9 @@ export class VoiceEntry {
         currentTimestamp: Fraction, length: Fraction, baseVoice: Voice, higherPitch: Pitch,
         alteration: AccidentalEnum, voiceEntries: VoiceEntry[]
     ): void {
-        let voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, undefined);
-        let pitch: Pitch = new Pitch(higherPitch.FundamentalNote, higherPitch.Octave, alteration);
-        let note: Note = new Note(voiceEntry, undefined, length, pitch);
+        const voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, undefined);
+        const pitch: Pitch = new Pitch(higherPitch.FundamentalNote, higherPitch.Octave, alteration);
+        const note: Note = new Note(voiceEntry, undefined, length, pitch);
         voiceEntry.Notes.push(note);
         voiceEntries.push(voiceEntry);
     }

+ 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;
+    const curs: HTMLElement = document.createElement("img");
+    curs.style.position = "absolute";
+    curs.style.zIndex = "-1";
+    this.cursorElement = <HTMLImageElement>curs;
+    this.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;
+    const 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);
+    const voiceEntry: VoiceEntry = iterator.CurrentVoiceEntries[0];
+    const measureIndex: number = voiceEntry.ParentSourceStaffEntry.VerticalContainerParent.ParentMeasure.measureListIndex;
+    const staffIndex: number = voiceEntry.ParentSourceStaffEntry.ParentStaff.idInMusicSheet;
+    const 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;
+    const musicSystem: MusicSystem = gse.parentMeasure.parentMusicSystem;
+    y = musicSystem.PositionAndShape.AbsolutePosition.y + musicSystem.StaffLines[0].PositionAndShape.RelativePosition.y;
+    const 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:
+    const 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);
+    const 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
+    const c: HTMLCanvasElement = document.createElement("canvas");
+    c.width = this.cursorElement.width;
+    c.height = 1;
+    const ctx: CanvasRenderingContext2D = c.getContext("2d");
+    ctx.globalAlpha = 0.5;
+    // Generate the gradient
+    const 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");
+  }
 }

+ 43 - 34
src/OSMD/OSMD.ts

@@ -1,15 +1,17 @@
 import {IXmlElement} from "./../Common/FileIO/Xml";
 import {VexFlowMusicSheetCalculator} from "./../MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator";
+import {VexFlowBackend} from "./../MusicalScore/Graphical/VexFlow/VexFlowBackend";
 import {MusicSheetReader} from "./../MusicalScore/ScoreIO/MusicSheetReader";
 import {GraphicalMusicSheet} from "./../MusicalScore/Graphical/GraphicalMusicSheet";
 import {MusicSheetCalculator} from "./../MusicalScore/Graphical/MusicSheetCalculator";
 import {VexFlowMusicSheetDrawer} from "./../MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer";
+import {SvgVexFlowBackend} from "./../MusicalScore/Graphical/VexFlow/SvgVexFlowBackend";
+import {CanvasVexFlowBackend} from "./../MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend";
 import {MusicSheet} from "./../MusicalScore/MusicSheet";
 import {Cursor} from "./Cursor";
 import {MXLHelper} from "../Common/FileIO/Mxl";
 import {Promise} from "es6-promise";
 import {AJAX} from "./AJAX";
-import {Logging} from "../Common/Logging";
 import * as log from "loglevel";
 
 export class OSMD {
@@ -18,7 +20,7 @@ export class OSMD {
      * @param container is either the ID, or the actual "div" element which will host the music sheet
      * @autoResize automatically resize the sheet to full page width on window resize
      */
-    constructor(container: string|HTMLElement, autoResize: boolean = false) {
+    constructor(container: string|HTMLElement, autoResize: boolean = false, backend: string = "canvas") {
         // Store container element
         if (typeof container === "string") {
             // ID passed
@@ -30,17 +32,22 @@ export class OSMD {
         if (!this.container) {
             throw new Error("Please pass a valid div container to OSMD");
         }
-        // Create the elements inside the container
-        this.canvas = document.createElement("canvas");
-        this.canvas.style.zIndex = "0";
-        let inner: HTMLElement = document.createElement("div");
-        inner.style.position = "relative";
-        inner.appendChild(this.canvas);
-        this.container.appendChild(inner);
+
+        if (backend === "svg") {
+            this.backend = new SvgVexFlowBackend();
+        } else {
+            this.backend = new CanvasVexFlowBackend();
+        }
+
+        this.backend.initialize(this.container);
+        this.canvas = this.backend.getCanvas();
+        const inner: HTMLElement = this.backend.getInnerElement();
+
         // Create the drawer
-        this.drawer = new VexFlowMusicSheetDrawer(this.canvas);
+        this.drawer = new VexFlowMusicSheetDrawer(this.canvas, this.backend, false);
         // Create the cursor
         this.cursor = new Cursor(inner, this);
+
         if (autoResize) {
             this.autoResize();
         }
@@ -50,7 +57,8 @@ export class OSMD {
     public zoom: number = 1.0;
 
     private container: HTMLElement;
-    private canvas: HTMLCanvasElement;
+    private canvas: HTMLElement;
+    private backend: VexFlowBackend;
     private sheet: MusicSheet;
     private drawer: VexFlowMusicSheetDrawer;
     private graphic: GraphicalMusicSheet;
@@ -63,23 +71,23 @@ export class OSMD {
         // Warning! This function is asynchronous! No error handling is done here.
         this.reset();
         if (typeof content === "string") {
-            let str: string = <string>content;
-            let self: OSMD = this;
+            const str: string = <string>content;
+            const self: OSMD = this;
             if (str.substr(0, 4) === "\x50\x4b\x03\x04") {
                 // This is a zip file, unpack it first
                 return MXLHelper.MXLtoXMLstring(str).then(
-                    (str: string) => {
-                        return self.load(str);
+                    (x: string) => {
+                        return self.load(x);
                     },
                     (err: any) => {
-                        Logging.debug(err);
+                        log.debug(err);
                         throw new Error("OSMD: Invalid MXL file");
                     }
                 );
             }
             if (str.substr(0, 5) === "<?xml") {
                 // Parse the string representing an xml file
-                let parser: DOMParser = new DOMParser();
+                const parser: DOMParser = new DOMParser();
                 content = parser.parseFromString(str, "text/xml");
             } else if (str.length < 2083) {
                 // Assume now "str" is a URL
@@ -94,10 +102,10 @@ export class OSMD {
         if (!content || !(<any>content).nodeName) {
             return Promise.reject(new Error("OSMD: The document which was provided is invalid"));
         }
-        let children: NodeList = (<Document>content).childNodes;
+        const children: NodeList = (<Document>content).childNodes;
         let elem: Element;
         for (let i: number = 0, length: number = children.length; i < length; i += 1) {
-            let node: Node = children[i];
+            const node: Node = children[i];
             if (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === "score-partwise") {
                 elem = <Element>node;
                 break;
@@ -106,9 +114,9 @@ export class OSMD {
         if (!elem) {
             return Promise.reject(new Error("OSMD: Document is not a valid 'partwise' MusicXML"));
         }
-        let score: IXmlElement = new IXmlElement(elem);
-        let calc: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
-        let reader: MusicSheetReader = new MusicSheetReader();
+        const score: IXmlElement = new IXmlElement(elem);
+        const calc: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
+        const reader: MusicSheetReader = new MusicSheetReader();
         this.sheet = reader.createMusicSheet(score, "Unknown path");
         this.graphic = new GraphicalMusicSheet(this.sheet, calc);
         this.cursor.init(this.sheet.MusicPartManager, this.graphic);
@@ -123,7 +131,7 @@ export class OSMD {
         if (!this.graphic) {
             throw new Error("OSMD: Before rendering a music sheet, please load a MusicXML file");
         }
-        let width: number = this.container.offsetWidth;
+        const width: number = this.container.offsetWidth;
         // Before introducing the following optimization (maybe irrelevant), tests
         // have to be modified to ensure that width is > 0 when executed
         //if (isNaN(width) || width === 0) {
@@ -144,7 +152,8 @@ export class OSMD {
         this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(6, 4), OutlineAndFillStyleEnum.PlaybackCursor));
         this.graphic.Cursors.push(this.graphic.calculateCursorLineAtTimestamp(new Fraction(7, 4), OutlineAndFillStyleEnum.PlaybackCursor));*/
         // Update Sheet Page
-        let height: number = this.graphic.MusicPages[0].PositionAndShape.BorderBottom * 10.0 * this.zoom;
+        const height: number = this.graphic.MusicPages[0].PositionAndShape.BorderBottom * 10.0 * this.zoom;
+        this.drawer.clear();
         this.drawer.resize(width, height);
         this.drawer.scale(this.zoom);
         // Finally, draw
@@ -161,23 +170,23 @@ export class OSMD {
     public setLogLevel(level: string): void {
         switch (level) {
             case "trace":
-                log.setDefaultLevel(LogLevel.TRACE);
+                log.setLevel(log.levels.WARN);
                 break;
             case "debug":
-                log.setDefaultLevel(LogLevel.DEBUG);
+                log.setLevel(log.levels.DEBUG);
                 break;
             case "info":
-                log.setDefaultLevel(LogLevel.INFO);
+                log.setLevel(log.levels.INFO);
                 break;
             case "warn":
-                log.setDefaultLevel(LogLevel.WARN);
+                log.setLevel(log.levels.WARN);
                 break;
             case "error":
-                log.setDefaultLevel(LogLevel.ERROR);
+                log.setLevel(log.levels.ERROR);
                 break;
             default:
                 log.warn(`Could not set log level to ${level}. Using warn instead.`);
-                log.setDefaultLevel(LogLevel.WARN);
+                log.setLevel(log.levels.WARN);
                 break;
         }
     }
@@ -191,15 +200,15 @@ export class OSMD {
         this.sheet = undefined;
         this.graphic = undefined;
         this.zoom = 1.0;
-        this.canvas.width = 0;
-        this.canvas.height = 0;
+        // this.canvas.width = 0;
+        // this.canvas.height = 0;
     }
 
     /**
      * Attach the appropriate handler to the window.onResize event
      */
     private autoResize(): void {
-        let self: OSMD = this;
+        const self: OSMD = this;
         this.handleResize(
             () => {
                 // empty
@@ -228,7 +237,7 @@ export class OSMD {
     private handleResize(startCallback: () => void, endCallback: () => void): void {
         let rtime: number;
         let timeout: number = undefined;
-        let delta: number = 200;
+        const delta: number = 200;
 
         function resizeEnd(): void {
             timeout = undefined;

+ 3 - 3
src/Util/CollectionUtil.ts

@@ -28,9 +28,9 @@ export class CollectionUtil {
      */
     public static removeDictElementIfTrue<S, T, V>(thisPointer: S, dict: Dictionary<T, V>,
                                                    iterationFunction: (thisPointer: S, key: T, value: V) => boolean): void {
-        let toDeleteEntries: T[] = [];
+        const toDeleteEntries: T[] = [];
         dict.forEach(function (key: T, value: V): void {
-            let shallDelete: boolean = iterationFunction(thisPointer, key, value);
+            const shallDelete: boolean = iterationFunction(thisPointer, key, value);
             if (shallDelete) {
                 toDeleteEntries.push(key);
             }
@@ -53,7 +53,7 @@ export class CollectionUtil {
         let mid: number = 1;
         while (startIndex < endIndex) {
             mid = Math.floor((startIndex + endIndex) / 2);
-            let c: number = cmp(array[mid], element);
+            const c: number = cmp(array[mid], element);
             if (c === 0) {
                 return mid;
             }

+ 1 - 1
src/Util/PSMath.ts

@@ -26,7 +26,7 @@ export class PSMath {
         let sumWeigtedValues: number = 0;
         let sumWeights: number = 0;
         for (let i: number = 0; i < values.length; i++) {
-            let weight: number = weights[i];
+            const weight: number = weights[i];
             sumWeigtedValues += values[i] * weight;
             sumWeights += weight;
         }

+ 2 - 35
test/Common/DataObjects/Fraction_Test.ts

@@ -2,12 +2,10 @@
  * 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", () => {
-        let f1: Fraction = new Fraction(2, 6);
+        const f1: Fraction = new Fraction(2, 6);
 
         it("Numerator and Denominator", (done: MochaDone) => {
             chai.expect(f1.Numerator).to.equal(1);
@@ -23,7 +21,7 @@ describe("Fraction Unit Tests:", () => {
     describe("Compare fractions", () => {
       let f1: Fraction;
       let f2: Fraction;
-      let rand: () => number = function(): number {
+      const rand: () => number = function(): number {
         return Math.floor(Math.random() * 500) + 1;
       };
       it("lt attribute", (done: MochaDone) => {
@@ -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();
-        });
-    });
 });

+ 25 - 25
test/Common/DataObjects/Pitch_Test.ts

@@ -2,10 +2,10 @@ import { Pitch, NoteEnum, AccidentalEnum } from "../../../src/Common/DataObjects
 
 describe("Pitch Unit Tests:", () => {
     describe("transpose Pitch", () => {
-        let pitch: Pitch = new Pitch(NoteEnum.A, 1, AccidentalEnum.NONE);
-        let transposedFundamentalAndOctave: {value: number; overflow: number; } =
+        const pitch: Pitch = new Pitch(NoteEnum.A, 1, AccidentalEnum.NONE);
+        const transposedFundamentalAndOctave: {value: number; overflow: number; } =
           Pitch.CalculateTransposedHalfTone(pitch, 12);
-        let higherTransposedFundamentalAndOctave: {value: number; overflow: number; } =
+        const higherTransposedFundamentalAndOctave: {value: number; overflow: number; } =
           Pitch.CalculateTransposedHalfTone(pitch, 26);
 
         it("should be 1 octave higher and same fundamental", (done: MochaDone) => {
@@ -18,13 +18,13 @@ describe("Pitch Unit Tests:", () => {
     });
 
     describe("calculate Frequency from Pitch", () => {
-        let pitch1: Pitch = new Pitch(NoteEnum.A, 1, AccidentalEnum.NONE);
-        let pitch2: Pitch = new Pitch(NoteEnum.B, 1, AccidentalEnum.DOUBLEFLAT);
-        let pitch3: Pitch = new Pitch(NoteEnum.G, 1, AccidentalEnum.DOUBLESHARP);
+        const pitch1: Pitch = new Pitch(NoteEnum.A, 1, AccidentalEnum.NONE);
+        const pitch2: Pitch = new Pitch(NoteEnum.B, 1, AccidentalEnum.DOUBLEFLAT);
+        const pitch3: Pitch = new Pitch(NoteEnum.G, 1, AccidentalEnum.DOUBLESHARP);
 
-        let frequency1: number = Pitch.calcFrequency(Pitch.calcFractionalKey(pitch1.Frequency));
-        let frequency2: number = Pitch.calcFrequency(Pitch.calcFractionalKey(pitch2.Frequency));
-        let frequency3: number = Pitch.calcFrequency(Pitch.calcFractionalKey(pitch3.Frequency));
+        const frequency1: number = Pitch.calcFrequency(Pitch.calcFractionalKey(pitch1.Frequency));
+        const frequency2: number = Pitch.calcFrequency(Pitch.calcFractionalKey(pitch2.Frequency));
+        const frequency3: number = Pitch.calcFrequency(Pitch.calcFractionalKey(pitch3.Frequency));
 
         it("should be 440Hz", (done: MochaDone) => {
             chai.expect(pitch1.Frequency).to.equal(440);
@@ -39,17 +39,17 @@ describe("Pitch Unit Tests:", () => {
 
     describe("calculate fractional key", () => {
         // the values are validated against the C# output. TODO: ask mauz about the shift
-        let pitch1: Pitch = new Pitch(NoteEnum.C, 6, AccidentalEnum.SHARP);   // C#6 -> 109
-        let pitch2: Pitch = new Pitch(NoteEnum.B, 1, AccidentalEnum.NONE);    // B1 -> 59
-        let pitch3: Pitch = new Pitch(NoteEnum.F, 4, AccidentalEnum.DOUBLEFLAT);  // Fbb4 -> 87
-        let pitch4: Pitch = new Pitch(NoteEnum.E, -1, AccidentalEnum.DOUBLESHARP);    // E##-1 -> 30
-        let pitch5: Pitch = new Pitch(NoteEnum.A, 1, AccidentalEnum.NONE);    // A1 -> 57
-
-        let key1: number = Pitch.calcFractionalKey(pitch1.Frequency);
-        let key2: number = Pitch.calcFractionalKey(pitch2.Frequency);
-        let key3: number = Pitch.calcFractionalKey(pitch3.Frequency);
-        let key4: number = Pitch.calcFractionalKey(pitch4.Frequency);
-        let key5: number = Pitch.calcFractionalKey(pitch5.Frequency);
+        const pitch1: Pitch = new Pitch(NoteEnum.C, 6, AccidentalEnum.SHARP);   // C#6 -> 109
+        const pitch2: Pitch = new Pitch(NoteEnum.B, 1, AccidentalEnum.NONE);    // B1 -> 59
+        const pitch3: Pitch = new Pitch(NoteEnum.F, 4, AccidentalEnum.DOUBLEFLAT);  // Fbb4 -> 87
+        const pitch4: Pitch = new Pitch(NoteEnum.E, -1, AccidentalEnum.DOUBLESHARP);    // E##-1 -> 30
+        const pitch5: Pitch = new Pitch(NoteEnum.A, 1, AccidentalEnum.NONE);    // A1 -> 57
+
+        const key1: number = Pitch.calcFractionalKey(pitch1.Frequency);
+        const key2: number = Pitch.calcFractionalKey(pitch2.Frequency);
+        const key3: number = Pitch.calcFractionalKey(pitch3.Frequency);
+        const key4: number = Pitch.calcFractionalKey(pitch4.Frequency);
+        const key5: number = Pitch.calcFractionalKey(pitch5.Frequency);
 
         it("pitch key should equal midi key", (done: MochaDone) => {
             chai.expect(key1).to.equal(109);
@@ -62,8 +62,8 @@ describe("Pitch Unit Tests:", () => {
     });
 
     describe("calculate Pitch from Frequency", () => {
-        let octave: number = 1;
-        let accidentals: number[] = [AccidentalEnum.DOUBLEFLAT,
+        const octave: number = 1;
+        const accidentals: number[] = [AccidentalEnum.DOUBLEFLAT,
             AccidentalEnum.FLAT,
             AccidentalEnum.NONE,
             AccidentalEnum.SHARP,
@@ -90,8 +90,8 @@ describe("Pitch Unit Tests:", () => {
     });
 
     describe("get Pitch from fractional key", () => {
-        let octave: number = 5;
-        let accidentals: number[] = [AccidentalEnum.DOUBLEFLAT,
+        const octave: number = 5;
+        const accidentals: number[] = [AccidentalEnum.DOUBLEFLAT,
             AccidentalEnum.FLAT,
             AccidentalEnum.NONE,
             AccidentalEnum.SHARP,
@@ -104,7 +104,7 @@ describe("Pitch Unit Tests:", () => {
         for (let i: number = 0; i < Pitch.pitchEnumValues.length; i++) {
             for (let j: number = 0; j < accidentals.length; j++) {
                 pitch = new Pitch(Pitch.pitchEnumValues[i], octave, accidentals[j]);
-                let halftone: number = pitch.getHalfTone();
+                const halftone: number = pitch.getHalfTone();
                 calcedPitch = Pitch.fromHalftone(halftone);
 
                 it( "calcedPitch equals original, " +

+ 5 - 4
test/Common/FileIO/Mxl_Test.ts

@@ -2,12 +2,13 @@ import { IXmlElement } from "../../../src/Common/FileIO/Xml";
 import { TestUtils } from "../../Util/TestUtils";
 import { MXLHelper } from "../../../src/Common/FileIO/Mxl";
 
+/* tslint:disable:no-unused-expression */
 describe("MXL Tests", () => {
   // Generates a test for a mxl file name
   function testFile(scoreName: string): void {
-    it(scoreName, (done: MochaDone) => {
+    it(`reads ${scoreName}`, (done: MochaDone) => {
       // Load the xml file content
-      let mxl: string = TestUtils.getMXL(scoreName);
+      const mxl: string = TestUtils.getMXL(scoreName);
       chai.expect(mxl).to.not.be.undefined;
       // Extract XML from MXL
       // Warning: the sheet is loaded asynchronously,
@@ -26,10 +27,10 @@ describe("MXL Tests", () => {
   }
 
   // Test all the following mxl files:
-  let scores: string[] = [
+  const scores: string[] = [
     "MozartTrio.mxl",
   ];
-  for (let score of scores) {
+  for (const score of scores) {
     testFile(score);
   }
 

+ 11 - 11
test/Common/FileIO/Xml_Test.ts

@@ -3,7 +3,7 @@ import {TestUtils} from "../../Util/TestUtils";
 import {OSMD} from "../../../src/OSMD/OSMD";
 
 // Test XML simple document
-let xmlTestData: string = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
+const xmlTestData: string = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
 <!DOCTYPE score-partwise PUBLIC \"-//Recordare//DTD MusicXML 2.0 Partwise//EN\" \"http://www.musicxml.org/dtds/partwise.dtd\">\
 <score-partwise>  <identification>    <encoding>      <software>Example Software name</software>      \
 <encoding-date>2016-04-04</encoding-date>      </encoding>    </identification>   <credit page=\"1\"> \
@@ -11,13 +11,13 @@ let xmlTestData: string = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
 
 
 describe("XML interface", () => {
-    let parser: DOMParser = new DOMParser();
-    let doc: Document = parser.parseFromString(xmlTestData, "text/xml");
-    let documentElement: IXmlElement = new IXmlElement(doc.documentElement);
+    const parser: DOMParser = new DOMParser();
+    const doc: Document = parser.parseFromString(xmlTestData, "text/xml");
+    const documentElement: IXmlElement = new IXmlElement(doc.documentElement);
 
 
     // Test all the following xml files:
-    let xmlTestset: string[] = [
+    const xmlTestset: string[] = [
         "ActorPreludeSample.xml",
         "Beethoven_AnDieFerneGeliebte.xml",
         "CharlesGounod_Meditation.xml",
@@ -38,7 +38,7 @@ describe("XML interface", () => {
         "TelemannWV40.102_Sonate-Nr.1.1-Dolce.xml",
         "TelemannWV40.102_Sonate-Nr.1.2-Allegro-F-Dur.xml",
     ];
-    for (let score of xmlTestset) {
+    for (const score of xmlTestset) {
         testFile(score);
     }
 
@@ -46,12 +46,12 @@ describe("XML interface", () => {
     function testFile(scoreName: string): void {
         it(scoreName, (done: MochaDone) => {
             // Load the xml file content
-            let score: Document = TestUtils.getScore(scoreName);
-            let div: HTMLElement = document.createElement("div");
-            let osmd: OSMD = new OSMD(div);
+            const score: Document = TestUtils.getScore(scoreName);
+            const div: HTMLElement = document.createElement("div");
+            const osmd: OSMD = new OSMD(div);
             osmd.load(score);
             done();
-        });
+        }).timeout(3000);
     }
 
     it("test IXmlElement", (done: MochaDone) => {
@@ -73,7 +73,7 @@ describe("XML interface", () => {
             documentElement.element("credit").attributes()[0].name
         ).to.equal("page");
 
-        let creditWords: IXmlElement =
+        const creditWords: IXmlElement =
             documentElement.element("credit").element("credit-words");
         // Test attributes method
         chai.expect(creditWords.attributes().length).to.equal(2);

+ 32 - 32
test/Common/OSMD/OSMD_Test.ts

@@ -14,7 +14,7 @@ describe("OSMD Main Export", () => {
     });
 
     it("container", (done: MochaDone) => {
-        let div: HTMLElement = document.createElement("div");
+        const div: HTMLElement = document.createElement("div");
         chai.expect(() => {
             return new OSMD(div);
         }).to.not.throw(Error);
@@ -22,9 +22,9 @@ describe("OSMD Main Export", () => {
     });
 
     it("load MXL from string", (done: MochaDone) => {
-        let mxl: string = TestUtils.getMXL("MozartTrio.mxl");
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const mxl: string = TestUtils.getMXL("MozartTrio.mxl");
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         osmd.load(mxl).then(
             (_: {}) => {
                 osmd.render();
@@ -35,9 +35,9 @@ describe("OSMD Main Export", () => {
     });
 
     it("load invalid MXL from string", (done: MochaDone) => {
-        let mxl: string = "\x50\x4b\x03\x04";
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const mxl: string = "\x50\x4b\x03\x04";
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         osmd.load(mxl).then(
             (_: {}) => {
                 done(new Error("Corrupted MXL appears to be loaded correctly"));
@@ -53,10 +53,10 @@ describe("OSMD Main Export", () => {
     });
 
     it("load XML string", (done: MochaDone) => {
-        let score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
-        let xml: string = new XMLSerializer().serializeToString(score);
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
+        const xml: string = new XMLSerializer().serializeToString(score);
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         osmd.load(xml).then(
             (_: {}) => {
                 osmd.render();
@@ -67,9 +67,9 @@ describe("OSMD Main Export", () => {
     });
 
     it("load XML Document", (done: MochaDone) => {
-        let score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         osmd.load(score).then(
             (_: {}) => {
                 osmd.render();
@@ -80,9 +80,9 @@ describe("OSMD Main Export", () => {
     });
 
     it("load MXL Document by URL", (done: MochaDone) => {
-        let url: string = "base/test/data/MozartTrio.mxl";
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const url: string = "base/test/data/MozartTrio.mxl";
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         osmd.load(url).then(
             (_: {}) => {
                 osmd.render();
@@ -93,9 +93,9 @@ describe("OSMD Main Export", () => {
     });
 
     it("load MXL Document by invalid URL", (done: MochaDone) => {
-        let url: string = "http://www.google.com";
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const url: string = "https://www.google.com";
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         osmd.load(url).then(
             (_: {}) => {
                 done(new Error("Invalid URL appears to be loaded correctly"));
@@ -108,12 +108,12 @@ describe("OSMD Main Export", () => {
                 }
             }
         );
-    });
+    }).timeout(5000);
 
     it("load invalid XML string", (done: MochaDone) => {
-        let xml: string = "<?xml";
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const xml: string = "<?xml";
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         osmd.load(xml).then(
             (_: {}) => {
                 done(new Error("Corrupted XML appears to be loaded correctly"));
@@ -129,8 +129,8 @@ describe("OSMD Main Export", () => {
     });
 
     it("render without loading", (done: MochaDone) => {
-        let div: HTMLElement = document.createElement("div");
-        let osmd: OSMD = new OSMD(div);
+        const div: HTMLElement = document.createElement("div");
+        const osmd: OSMD = new OSMD(div);
         chai.expect(() => {
             return osmd.render();
         }).to.throw(/load/);
@@ -148,10 +148,10 @@ describe("OSMD Main Export", () => {
     });
 
     it("test width 500", (done: MochaDone) => {
-        let div: HTMLElement = container1;
+        const div: HTMLElement = container1;
         div.style.width = "500px";
-        let osmd: OSMD = new OSMD(div);
-        let score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
+        const osmd: OSMD = new OSMD(div);
+        const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         osmd.load(score).then(
             (_: {}) => {
                 osmd.render();
@@ -163,10 +163,10 @@ describe("OSMD Main Export", () => {
     });
 
     it("test width 200", (done: MochaDone) => {
-        let div: HTMLElement = container1;
+        const div: HTMLElement = container1;
         div.style.width = "200px";
-        let osmd: OSMD = new OSMD(div);
-        let score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
+        const osmd: OSMD = new OSMD(div);
+        const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         osmd.load(score).then(
             (_: {}) => {
                 osmd.render();

+ 76 - 0
test/MusicalScore/Graphical/VexFlow/VexFlowConverter_Clef_Test.ts

@@ -0,0 +1,76 @@
+import {IXmlElement} from "../../../../src/Common/FileIO/Xml";
+import {MusicSheet} from "../../../../src/MusicalScore/MusicSheet";
+import {MusicSheetReader} from "../../../../src/MusicalScore/ScoreIO/MusicSheetReader";
+
+/* tslint:disable:no-unused-expression */
+describe("Clef Converter MusicXML to VexFlow", () => {
+
+    let reader: MusicSheetReader;
+    let parser: DOMParser;
+
+    before((): void => {
+      reader = new MusicSheetReader();
+      parser = new DOMParser();
+    });
+
+    it("reads treble key", (done: MochaDone) => {
+      getMusicSheetWithClef("G").getStaffFromIndex(0);
+      done();
+    });
+
+    /**
+     * Simulates loading a [[MusicSheet]] with the specified clef.
+     *
+     * @see https://usermanuals.musicxml.com/MusicXML/Content/EL-MusicXML-clef.htm
+     */
+    function getMusicSheetWithClef(sign: string, line?: number, clefOcatveChange?: number, additional?: string, size?: string): MusicSheet {
+      const doc: Document = parser.parseFromString(getMusicXmlWithClef(sign, line, clefOcatveChange, additional, size), "text/xml");
+      chai.expect(doc).to.not.be.undefined;
+      const score: IXmlElement = new IXmlElement(doc.getElementsByTagName("score-partwise")[0]);
+      chai.expect(score).to.not.be.undefined;
+      return reader.createMusicSheet(score, "template.xml");
+    }
+
+    function getMusicXmlWithClef(sign: string, line?: number, clefOcatveChange?: number, additional?: string, size?: string): string {
+      // let modeElement: string = mode ? `<mode>${mode}</mode>` : "";
+      // let fifthsElement: string = fifths ? `<fifths>${fifths}</fifths>` : "";
+      return `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+              <!DOCTYPE score-partwise PUBLIC
+                  "-//Recordare//DTD MusicXML 3.0 Partwise//EN"
+                  "http://www.musicxml.org/dtds/partwise.dtd">
+              <score-partwise version="3.0">
+                <part-list>
+                  <score-part id="P1">
+                    <part-name>Music</part-name>
+                  </score-part>
+                </part-list>
+                <part id="P1">
+                  <measure number="1">
+                    <attributes>
+                      <divisions>1</divisions>
+                      <key>
+
+                      </key>
+                      <time>
+                        <beats>4</beats>
+                        <beat-type>4</beat-type>
+                      </time>
+                      <clef>
+                        <sign>G</sign>
+                        <line>2</line>
+                      </clef>
+                    </attributes>
+                    <note>
+                      <pitch>
+                        <step>C</step>
+                        <octave>4</octave>
+                      </pitch>
+                      <duration>4</duration>
+                      <type>whole</type>
+                    </note>
+                  </measure>
+                </part>
+              </score-partwise>`;
+    }
+
+});

+ 17 - 16
test/MusicalScore/Graphical/VexFlow/VexFlowMeasure_Test.ts

@@ -9,42 +9,43 @@ import {SourceStaffEntry} from "../../../../src/MusicalScore/VoiceData/SourceSta
 import {StaffMeasure} from "../../../../src/MusicalScore/Graphical/StaffMeasure";
 import {MusicSheetCalculator} from "../../../../src/MusicalScore/Graphical/MusicSheetCalculator";
 
+/* tslint:disable:no-unused-expression */
 describe("VexFlow Measure", () => {
 
    it.skip("GraphicalMusicSheet", (done: MochaDone) => {
-      let path: string = "test/data/MuzioClementi_SonatinaOpus36No1_Part1.xml";
-      let score: Document = TestUtils.getScore(path);
+      const path: string = "test/data/MuzioClementi_SonatinaOpus36No1_Part1.xml";
+      const score: Document = TestUtils.getScore(path);
       chai.expect(score).to.not.be.undefined;
-      let partwise: Element = TestUtils.getPartWiseElement(score);
+      const partwise: Element = TestUtils.getPartWiseElement(score);
       chai.expect(partwise).to.not.be.undefined;
-      let calc: VexFlowMusicSheetCalculator = new VexFlowMusicSheetCalculator();
-      let reader: MusicSheetReader = new MusicSheetReader();
-      let sheet: MusicSheet = reader.createMusicSheet(new IXmlElement(partwise), path);
-      let gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
+      const calc: VexFlowMusicSheetCalculator = new VexFlowMusicSheetCalculator();
+      const reader: MusicSheetReader = new MusicSheetReader();
+      const sheet: MusicSheet = reader.createMusicSheet(new IXmlElement(partwise), path);
+      const gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
       console.log(gms);
       done();
    });
 
    it.skip("Simple Measure", (done: MochaDone) => {
-      let sheet: MusicSheet = new MusicSheet();
-      let measure: SourceMeasure = new SourceMeasure(1);
+      const sheet: MusicSheet = new MusicSheet();
+      const measure: SourceMeasure = new SourceMeasure(1);
       sheet.addMeasure(measure);
-      let calc: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
-      let gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
+      const calc: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
+      const gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
       chai.expect(gms.MeasureList.length).to.equal(1);
       chai.expect(gms.MeasureList[0].length).to.equal(1);
-      let gm: StaffMeasure = gms.MeasureList[0][0];
+      const gm: StaffMeasure = gms.MeasureList[0][0];
       console.log(gm);
       done();
    });
 
    it.skip("Empty Measure", (done: MochaDone) => {
-      let sheet: MusicSheet = new MusicSheet();
-      let measure: SourceMeasure = new SourceMeasure(1);
+      const sheet: MusicSheet = new MusicSheet();
+      const measure: SourceMeasure = new SourceMeasure(1);
       measure.FirstInstructionsStaffEntries[0] = new SourceStaffEntry(undefined, undefined);
       sheet.addMeasure(measure);
-      let calc: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
-      let gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
+      const calc: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
+      const gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
       chai.expect(gms.MeasureList.length).to.equal(1);
       chai.expect(gms.MeasureList[0].length).to.equal(0);
       done();

+ 25 - 18
test/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer_Test.ts

@@ -7,40 +7,47 @@ import {VexFlowMusicSheetCalculator} from "../../../../src/MusicalScore/Graphica
 import {TestUtils} from "../../../Util/TestUtils";
 import {IXmlElement} from "../../../../src/Common/FileIO/Xml";
 import {Fraction} from "../../../../src/Common/DataObjects/Fraction";
+import {VexFlowBackend} from "../../../../src/MusicalScore/Graphical/VexFlow/VexFlowBackend";
+import {CanvasVexFlowBackend} from "../../../../src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend";
 
+/* tslint:disable:no-unused-expression */
 describe("VexFlow Music Sheet Drawer", () => {
 
-    it(".drawSheet (Clementi pt. 1)", (done: MochaDone) => {
-        let score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
+    it("draws sheet \"Clementi pt. 1\"", (done: MochaDone) => {
+        const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         chai.expect(score).to.not.be.undefined;
-        let partwise: Element = TestUtils.getPartWiseElement(score);
+        const partwise: Element = TestUtils.getPartWiseElement(score);
         chai.expect(partwise).to.not.be.undefined;
-        let calc: VexFlowMusicSheetCalculator = new VexFlowMusicSheetCalculator();
-        let reader: MusicSheetReader = new MusicSheetReader();
-        let sheet: MusicSheet = reader.createMusicSheet(new IXmlElement(partwise), "** missing path **");
-        let gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
+        const calc: VexFlowMusicSheetCalculator = new VexFlowMusicSheetCalculator();
+        const reader: MusicSheetReader = new MusicSheetReader();
+        const sheet: MusicSheet = reader.createMusicSheet(new IXmlElement(partwise), "** missing path **");
+        const gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
 
         // Create the canvas in the document:
-        let canvas: HTMLCanvasElement = document.createElement("canvas");
-        let drawer: VexFlowMusicSheetDrawer = new VexFlowMusicSheetDrawer(canvas);
+        const canvas: HTMLCanvasElement = document.createElement("canvas");
+        const backend: VexFlowBackend = new CanvasVexFlowBackend();
+        backend.initialize(canvas);
+        const drawer: VexFlowMusicSheetDrawer = new VexFlowMusicSheetDrawer(canvas, backend);
         drawer.drawSheet(gms);
         done();
     });
 
-    it.skip("With cursor (as rectangle)", (done: MochaDone) => {
-        let score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
+    it.skip("draws cursor (as rectangle)", (done: MochaDone) => {
+        const score: Document = TestUtils.getScore("MuzioClementi_SonatinaOpus36No1_Part1.xml");
         chai.expect(score).to.not.be.undefined;
-        let partwise: Element = TestUtils.getPartWiseElement(score);
+        const partwise: Element = TestUtils.getPartWiseElement(score);
         chai.expect(partwise).to.not.be.undefined;
-        let calc: VexFlowMusicSheetCalculator = new VexFlowMusicSheetCalculator();
-        let reader: MusicSheetReader = new MusicSheetReader();
-        let sheet: MusicSheet = reader.createMusicSheet(new IXmlElement(partwise), "** missing path **");
-        let gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
+        const calc: VexFlowMusicSheetCalculator = new VexFlowMusicSheetCalculator();
+        const reader: MusicSheetReader = new MusicSheetReader();
+        const sheet: MusicSheet = reader.createMusicSheet(new IXmlElement(partwise), "** missing path **");
+        const gms: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calc);
         gms.Cursors.push(gms.calculateCursorLineAtTimestamp(new Fraction(0, 4), OutlineAndFillStyleEnum.PlaybackCursor));
 
         // Create the canvas in the document:
-        let canvas: HTMLCanvasElement = document.createElement("canvas");
-        let drawer: VexFlowMusicSheetDrawer = new VexFlowMusicSheetDrawer(canvas);
+        const canvas: HTMLCanvasElement = document.createElement("canvas");
+        const backend: VexFlowBackend = new CanvasVexFlowBackend();
+        backend.initialize(canvas);
+        const drawer: VexFlowMusicSheetDrawer = new VexFlowMusicSheetDrawer(canvas, backend);
         drawer.drawSheet(gms);
         done();
     });

+ 8 - 24
test/MusicalScore/ScoreCalculation/MusicSheetCalculator_Test.ts

@@ -1,6 +1,3 @@
-/**
- * Created by Matthias on 21.06.2016.
- */
 import {MusicSheetReader} from "../../../src/MusicalScore/ScoreIO/MusicSheetReader";
 import {MusicSheet} from "../../../src/MusicalScore/MusicSheet";
 import {IXmlElement} from "../../../src/Common/FileIO/Xml";
@@ -10,38 +7,25 @@ import {GraphicalMusicSheet} from "../../../src/MusicalScore/Graphical/Graphical
 import {VexFlowTextMeasurer} from "../../../src/MusicalScore/Graphical/VexFlow/VexFlowTextMeasurer";
 import {TestUtils} from "../../Util/TestUtils";
 
-
-describe("Music Sheet Calculator Tests", () => {
-    // Initialize variables
-    let filename: string = "MuzioClementi_SonatinaOpus36No1_Part1.xml";
-    let reader: MusicSheetReader = new MusicSheetReader();
-    let calculator: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
+/* tslint:disable:no-unused-expression */
+describe("Music Sheet Calculator", () => {
+    const filename: string = "MuzioClementi_SonatinaOpus36No1_Part1.xml";
+    const reader: MusicSheetReader = new MusicSheetReader();
+    const calculator: MusicSheetCalculator = new VexFlowMusicSheetCalculator();
     let score: IXmlElement;
     let sheet: MusicSheet;
 
-    before((): void => {
-        // ???
-    });
-
-    beforeEach((): void => {
-        // ???
-    });
-
-    afterEach((): void => {
-        // cleanup?
-    });
-
-    it("Do Calculation", (done: MochaDone) => {
+    it("calculates music sheet", (done: MochaDone) => {
         this.timeout = 10000;
         MusicSheetCalculator.TextMeasurer = new VexFlowTextMeasurer();
         // Load the XML file
-        let xml: Document = TestUtils.getScore(filename);
+        const xml: Document = TestUtils.getScore(filename);
         chai.expect(xml).to.not.be.undefined;
         score = new IXmlElement(TestUtils.getPartWiseElement(xml));
         chai.expect(score).to.not.be.undefined;
         sheet = reader.createMusicSheet(score, "path-of-" + filename);
 
-        let graphicalSheet: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calculator);
+        const graphicalSheet: GraphicalMusicSheet = new GraphicalMusicSheet(sheet, calculator);
         graphicalSheet.reCalculate();
         done();
     });

+ 358 - 0
test/MusicalScore/ScoreIO/Key_Test.ts

@@ -0,0 +1,358 @@
+import { MusicSheetReader }       from "../../../src/MusicalScore/ScoreIO/MusicSheetReader";
+import { MusicSheet }             from "../../../src/MusicalScore/MusicSheet";
+import { IXmlElement }            from "../../../src/Common/FileIO/Xml";
+import { KeyInstruction }         from "../../../src/MusicalScore/VoiceData/Instructions/KeyInstruction";
+import { KeyEnum as KeyModeEnum } from "../../../src/MusicalScore/VoiceData/Instructions/KeyInstruction";
+import * as chai                  from "chai";
+
+let reader: MusicSheetReader;
+let parser: DOMParser;
+
+/* tslint:disable:no-unused-expression */
+describe("MusicXML parser for element 'key'", () => {
+
+  before((): void => {
+    reader = new MusicSheetReader();
+    parser = new DOMParser();
+  });
+
+  describe("for group traditional keys", () => {
+
+    xit("enforces single occurrence of element 'fifths'", (done: MochaDone) => {
+      const keyInstruction: KeyInstruction = getIllegalMusicXmlWithTwoFifthsElements().getFirstSourceMeasure().getKeyInstruction(0);
+      // TODO Make sure we detect the multiple fifths and react properly
+      chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.none);
+      done();
+    });
+
+    it("reads key signature with no optional 'mode' element present", (done: MochaDone) => {
+      const keyInstruction: KeyInstruction = getMusicSheetWithKey(0, undefined).getFirstSourceMeasure().getKeyInstruction(0);
+      chai.expect(keyInstruction.Key).to.equal(0);
+      chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.none);
+      done();
+    });
+
+    describe("major keys", () => {
+
+      it("reads key signature C-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(0, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(0);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature G-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(1, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(1);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature D-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(2, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(2);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature A-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(3, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(3);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature E-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(4, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(4);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature B-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(5, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(5);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature Fis-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(6, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(6);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature Cis-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(7, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(7);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature Gis-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(8, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(8);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature F-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-1, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-1);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature B-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-2, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-2);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature Es-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-3, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-3);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature As-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-4, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-4);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature Des-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-5, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-5);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature Ges-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-6, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-6);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+
+      it("reads key signature Fes-major", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-8, "major").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-8);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
+        done();
+      });
+    });
+
+    describe("minor keys", () => {
+
+      it("reads key signature a-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(0, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(0);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature e-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(1, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(1);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature b-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(2, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(2);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature fis-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(3, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(3);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature cis-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(4, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(4);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature gis-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(5, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(5);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature dis-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(6, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(6);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature ais-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(7, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(7);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature d-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-1, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-1);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature g-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-2, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-2);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature c-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-3, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-3);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature f-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-4, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-4);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature bb-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-5, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-5);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature es-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-6, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-6);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+
+      it("reads key signature as-minor", (done: MochaDone) => {
+        const keyInstruction: KeyInstruction = getMusicSheetWithKey(-7, "minor").getFirstSourceMeasure().getKeyInstruction(0);
+        chai.expect(keyInstruction.Key).to.equal(-7);
+        chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
+        done();
+      });
+    });
+  });
+});
+
+function getMusicSheetWithKey(fifths: number = undefined, mode: string = undefined): MusicSheet {
+  const doc: Document = parser.parseFromString(getMusicXmlWithKey(fifths, mode), "text/xml");
+  chai.expect(doc).to.not.be.undefined;
+  const score: IXmlElement = new IXmlElement(doc.getElementsByTagName("score-partwise")[0]);
+  chai.expect(score).to.not.be.undefined;
+  return reader.createMusicSheet(score, "template.xml");
+}
+
+function getMusicXmlWithKey(fifths: number = undefined, mode: string = undefined): string {
+  const modeElement: string = mode ? `<mode>${mode}</mode>` : "";
+  const fifthsElement: string = fifths ? `<fifths>${fifths}</fifths>` : "";
+  return `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+          <!DOCTYPE score-partwise PUBLIC
+              "-//Recordare//DTD MusicXML 3.0 Partwise//EN"
+              "http://www.musicxml.org/dtds/partwise.dtd">
+          <score-partwise version="3.0">
+            <part-list>
+              <score-part id="P1">
+                <part-name>Music</part-name>
+              </score-part>
+            </part-list>
+            <part id="P1">
+              <measure number="1">
+                <attributes>
+                  <divisions>1</divisions>
+                  <key>
+                    ${fifthsElement}
+                    ${modeElement}
+                  </key>
+                  <time>
+                    <beats>4</beats>
+                    <beat-type>4</beat-type>
+                  </time>
+                  <clef>
+                    <sign>G</sign>
+                    <line>2</line>
+                  </clef>
+                </attributes>
+                <note>
+                  <pitch>
+                    <step>C</step>
+                    <octave>4</octave>
+                  </pitch>
+                  <duration>4</duration>
+                  <type>whole</type>
+                </note>
+              </measure>
+            </part>
+          </score-partwise>`;
+}
+
+function getIllegalMusicXmlWithTwoFifthsElements(): MusicSheet {
+  const doc: Document = parser.parseFromString(
+    `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+      <!DOCTYPE score-partwise PUBLIC
+          "-//Recordare//DTD MusicXML 3.0 Partwise//EN"
+          "http://www.musicxml.org/dtds/partwise.dtd">
+      <score-partwise version="3.0">
+        <part-list>
+          <score-part id="P1">
+            <part-name>Music</part-name>
+          </score-part>
+        </part-list>
+        <part id="P1">
+          <measure number="1">
+            <attributes>
+              <divisions>1</divisions>
+              <key>
+                <fifths>1</fifths>
+                <fifths>2</fifths>
+                <fifths>3</fifths>
+              </key>
+              <time>
+                <beats>4</beats>
+                <beat-type>4</beat-type>
+              </time>
+              <clef>
+                <sign>G</sign>
+                <line>2</line>
+              </clef>
+            </attributes>
+            <note>
+              <pitch>
+                <step>C</step>
+                <octave>4</octave>
+              </pitch>
+              <duration>4</duration>
+              <type>whole</type>
+            </note>
+          </measure>
+        </part>
+      </score-partwise>`,
+    "text/xml"
+  );
+  chai.expect(doc).to.not.be.undefined;
+  const score: IXmlElement = new IXmlElement(doc.getElementsByTagName("score-partwise")[0]);
+  chai.expect(score).to.not.be.undefined;
+  return reader.createMusicSheet(score, "template.xml");
+}

+ 12 - 22
test/MusicalScore/ScoreIO/MusicSheetReader_Test.ts

@@ -2,12 +2,10 @@ import {MusicSheetReader} from "../../../src/MusicalScore/ScoreIO/MusicSheetRead
 import {MusicSheet} from "../../../src/MusicalScore/MusicSheet";
 import {IXmlElement} from "../../../src/Common/FileIO/Xml";
 
-
-
-describe("Music Sheet Reader Tests", () => {
-    // Initialize variables
-    let path: string = "test/data/MuzioClementi_SonatinaOpus36No1_Part1.xml";
-    let reader: MusicSheetReader = new MusicSheetReader();
+/* tslint:disable:no-unused-expression */
+describe("Music Sheet Reader", () => {
+    const path: string = "test/data/MuzioClementi_SonatinaOpus36No1_Part1.xml";
+    const reader: MusicSheetReader = new MusicSheetReader();
     let score: IXmlElement;
     let sheet: MusicSheet;
 
@@ -17,37 +15,29 @@ describe("Music Sheet Reader Tests", () => {
 
     before((): void => {
         // Load the xml file
-        let doc: Document = getSheet(path);
+        const doc: Document = getSheet(path);
         chai.expect(doc).to.not.be.undefined;
         score = new IXmlElement(doc.getElementsByTagName("score-partwise")[0]);
         // chai.expect(score).to.not.be.undefined;
         sheet = reader.createMusicSheet(score, path);
     });
 
-    beforeEach((): void => {
-      // ???
-    });
-
-    afterEach((): void => {
-      // cleanup?
+    it("checks XML", (done: MochaDone) => {
+      done(); // TODO implement test
     });
 
-    it("Check XML", (done: MochaDone) => {
-      done();
-    });
-
-    it("Read title and composer", (done: MochaDone) => {
+    it("reads title and composer", (done: MochaDone) => {
         chai.expect(sheet.TitleString).to.equal("Sonatina Op.36 No 1 Teil 1 Allegro");
         chai.expect(sheet.ComposerString).to.equal("Muzio Clementi");
         done();
     });
 
-    it("Measures", (done: MochaDone) => {
+    it("reads measures", (done: MochaDone) => {
         chai.expect(sheet.SourceMeasures.length).to.equal(38);
         done();
     });
 
-    it("Instruments", (done: MochaDone) => {
+    it("reads instruments", (done: MochaDone) => {
         chai.expect(reader.CompleteNumberOfStaves).to.equal(2);
         chai.expect(sheet.Instruments.length).to.equal(2);
         chai.expect(sheet.InstrumentalGroups.length).to.equal(2);
@@ -56,9 +46,9 @@ describe("Music Sheet Reader Tests", () => {
         done();
     });
 
-    it("Notes", (done: MochaDone) => {
+    it("reads notes", (done: MochaDone) => {
+        // TODO implement test
         // Staff Entries on first measure
-
         // chai.expect(sheet.SourceMeasures[0].VerticalSourceStaffEntryContainers[0].StaffEntries.length).to.equal(4);
         done();
     });

+ 4 - 4
test/Util/TestUtils.ts

@@ -6,12 +6,12 @@
 export class TestUtils {
 
     public static getScore(name: string): Document {
-        let path: string = "test/data/" + name;
+        const path: string = "test/data/" + name;
         return ((window as any).__xml__)[path];
     }
 
     public static getMXL(scoreName: string): string {
-        let path: string = "test/data/" + scoreName;
+        const path: string = "test/data/" + scoreName;
         return ((window as any).__raw__)[path];
     }
 
@@ -21,9 +21,9 @@ export class TestUtils {
      * @returns {Element}
      */
     public static getPartWiseElement(doc: Document): Element {
-        let nodes: NodeList = doc.childNodes;
+        const nodes: NodeList = doc.childNodes;
         for (let i: number = 0, length: number = nodes.length; i < length; i += 1) {
-            let node: Node = nodes[i];
+            const node: Node = nodes[i];
             if (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === "score-partwise") {
                 return <Element>node;
             }

+ 37 - 0
test/data/HelloWorld.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE score-partwise PUBLIC
+    "-//Recordare//DTD MusicXML 3.0 Partwise//EN"
+    "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="3.0">
+  <part-list>
+    <score-part id="P1">
+      <part-name>Music</part-name>
+    </score-part>
+  </part-list>
+  <part id="P1">
+    <measure number="1">
+      <attributes>
+        <divisions>1</divisions>
+        <key>
+          <fifths>0</fifths>
+        </key>
+        <time>
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+        </time>
+        <clef>
+          <sign>G</sign>
+          <line>2</line>
+        </clef>
+      </attributes>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <type>whole</type>
+      </note>
+    </measure>
+  </part>
+</score-partwise>

BIN
test/data/Parlez-moi.mxl


+ 4 - 23
tslint.json

@@ -22,18 +22,12 @@
     "interface-name": false,
     "jsdoc-format": true,
     "label-position": true,
-    "label-undefined": true,
     "max-line-length": [
       true,
       160
     ],
     "member-access": true,
-    "member-ordering": [
-      true,
-      "public-before-private",
-      "static-before-instance",
-      "variables-before-functions"
-    ],
+    "member-ordering": false,
     "no-any": false,
     "no-arg": true,
     "no-bitwise": true,
@@ -48,9 +42,8 @@
       "trace"
     ],
     "no-construct": true,
-    "no-constructor-vars": true,
+    "no-parameter-properties": true,
     "no-debugger": true,
-    "no-duplicate-key": true,
     "no-duplicate-variable": true,
     "no-empty": true,
     "no-eval": true,
@@ -62,13 +55,12 @@
     "no-string-literal": true,
     "no-switch-case-fall-through": true,
     "no-trailing-whitespace": true,
-    "no-unreachable": true,
     "no-unused-expression": true,
     "no-unused-variable": true,
-    "no-use-before-declare": true,
     "no-var-keyword": true,
     "no-var-requires": true,
     "object-literal-sort-keys": true,
+    "prefer-const": true,
     "one-line": [
       true,
       "check-open-brace",
@@ -84,13 +76,7 @@
     "radix": true,
     "semicolon": true,
     "switch-default": true,
-    "trailing-comma": [
-      true,
-      {
-        "multiline": "always",
-        "singleline": "never"
-      }
-    ],
+    "trailing-comma": false,
     "triple-equals": [
       true,
       "allow-null-check"
@@ -113,11 +99,6 @@
         "variable-declaration": "nospace"
       }
     ],
-    "use-strict": [
-      true,
-      "check-module",
-      "check-function"
-    ],
     "variable-name": [
       true,
       "check-format",

+ 0 - 12
typings.json

@@ -1,12 +0,0 @@
-{
-  "globalDependencies": {
-    "chai": "registry:dt/chai#3.4.0+20160317120654",
-    "loglevel": "registry:dt/loglevel#1.4.0+20160412141402",
-    "mocha": "registry:dt/mocha#2.2.5+20160317120654",
-    "shortid": "registry:dt/shortid#0.0.0+20160316155526"
-  },
-  "dependencies": {
-    "es6-promise": "registry:npm/es6-promise#3.0.0+20160211003958",
-    "jszip": "github:sebastianhaas/typed-jszip"
-  }
-}

+ 63 - 0
webpack.config.js

@@ -0,0 +1,63 @@
+var path = require('path');
+var webpack = require('webpack');
+
+module.exports = {
+  entry: {
+    'osmd': './src/OSMD/OSMD.ts', // Main library
+    'demo': './demo/index.js' // Demo index
+  },
+  output: {
+      path: path.resolve(__dirname, 'build'),
+      filename: '[name].js',
+   },
+   resolve: {
+       // Add '.ts' and '.tsx' as a resolvable extension.
+       extensions: ['.webpack.js', '.web.js', '.ts', '.tsx', '.js']
+   },
+   module: {
+       loaders: [
+           // all files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'
+           { test: /\.tsx?$/, loader: 'ts-loader' },
+           // all files with a '.js' extension. Mostly for the web demo.
+           { test: /\.jsx?$/, loader: 'babel-loader', exclude: /(node_modules|bower_components)/,
+              query: {
+                presets: ['es2015'] 
+              }
+          },
+       ]
+   },
+   plugins: [
+     // build optimization plugins
+     new webpack.LoaderOptionsPlugin({
+      minimize: true,
+      debug: true
+    }),
+    new webpack.ProvidePlugin({
+      $: 'jquery',
+      jQuery: 'jquery'
+    }),
+    new webpack.EnvironmentPlugin({
+      NODE_ENV: 'development', // use 'development' unless process.env.NODE_ENV is defined
+      DEBUG: false,
+      DRAW_BOUNDING_BOX_ELEMENT: false, //  Specifies the element to draw bounding boxes for (e.g. 'GraphicalLabels'). If 'all', bounding boxes are drawn for all elements.
+    }),
+    // FIXME: use environment variable to control uglify.
+    // new webpack.optimize.UglifyJsPlugin({
+    //     warnings: false,
+    //     beautify: false,
+    //     compress: true,
+    //     comments: false,
+    //     sourceMap: true
+    //   })
+  ],
+  devServer: {
+    contentBase: [
+      path.join(__dirname, 'test/data'),
+      path.join(__dirname, 'build'),
+      path.join(__dirname, 'demo')
+      // TODO: fill in paths for demo data
+    ],
+    port: 8000,
+    compress: false,
+  },
+};

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است