Browse Source

initial commit: osmd-extended: audio player, transpose, click to set position

sschmid 4 years ago
commit
22e89a30b9
100 changed files with 20585 additions and 0 deletions
  1. 21 0
      .appveyor.yml
  2. 33 0
      .editorconfig
  3. 6 0
      .eslintignore
  4. 230 0
      .eslintrc.js
  5. 6 0
      .eslintrc.yml
  6. 67 0
      .gitignore
  7. 10 0
      AUTHORS
  8. 3 0
      LICENSE
  9. 3033 0
      demo/BrahWiMeSample.musicxml
  10. 5929 0
      demo/BrookeWestSample.musicxml
  11. 471 0
      demo/annotations-ui.css
  12. 41 0
      demo/demo.css
  13. 117 0
      demo/embedded_demo.html
  14. BIN
      demo/favicon.ico
  15. BIN
      demo/fonts/Gonville-18.ttf
  16. BIN
      demo/fonts/Gonville-18.woff
  17. BIN
      demo/fonts/Gonville-18.woff2
  18. 210 0
      demo/index.html
  19. 1002 0
      demo/index.js
  20. 121 0
      karma.conf.js
  21. 140 0
      package.json
  22. 11 0
      src/Common/Algorithms/Controller/AbstractNumberController.ts
  23. 37 0
      src/Common/Algorithms/Controller/BrowserScrollController.ts
  24. 20 0
      src/Common/DataObjects/CursorPosChangedData.ts
  25. 487 0
      src/Common/DataObjects/Fraction.ts
  26. 58 0
      src/Common/DataObjects/Matrix2D.ts
  27. 25 0
      src/Common/DataObjects/MusicSheetErrors.ts
  28. 76 0
      src/Common/DataObjects/OSMDColor.ts
  29. 444 0
      src/Common/DataObjects/Pitch.ts
  30. 84 0
      src/Common/DataObjects/PlaybackSettings.ts
  31. 20 0
      src/Common/DataObjects/PointF2D.ts
  32. 36 0
      src/Common/DataObjects/RectangleF2D.ts
  33. 12 0
      src/Common/DataObjects/SizeF2D.ts
  34. 10 0
      src/Common/DataObjects/index.ts
  35. 18 0
      src/Common/Enums/FontStyles.ts
  36. 20 0
      src/Common/Enums/Fonts.ts
  37. 7 0
      src/Common/Enums/InteractionType.ts
  38. 10 0
      src/Common/Enums/PsEnums.ts
  39. 43 0
      src/Common/Enums/TextAlignment.ts
  40. 10 0
      src/Common/Enums/TieTypes.ts
  41. 6 0
      src/Common/Enums/index.ts
  42. 80 0
      src/Common/FileIO/Mxl.ts
  43. 106 0
      src/Common/FileIO/Xml.ts
  44. 4 0
      src/Common/FileIO/index.ts
  45. 15 0
      src/Common/Interfaces/AClassHierarchyTrackable.ts
  46. 12 0
      src/Common/Interfaces/IAudioMetronomePlayer.ts
  47. 36 0
      src/Common/Interfaces/IAudioPlayer.ts
  48. 3 0
      src/Common/Interfaces/IControllerOutputListener.ts
  49. 9 0
      src/Common/Interfaces/IDisplayInteractionListener.ts
  50. 17 0
      src/Common/Interfaces/IInstrument.ts
  51. 4 0
      src/Common/Interfaces/IMessageViewer.ts
  52. 10 0
      src/Common/Interfaces/IPlaybackListener.ts
  53. 9 0
      src/Common/Interfaces/IPlaybackParametersListener.ts
  54. 9 0
      src/Common/Interfaces/IRepetition.ts
  55. 20 0
      src/Common/Interfaces/ISettableInstrument.ts
  56. 20 0
      src/Common/Interfaces/ITimingSource.ts
  57. 6 0
      src/Common/Interfaces/IUserDisplayInteractionListener.ts
  58. 12 0
      src/Common/Interfaces/IZoomView.ts
  59. 14 0
      src/Common/Interfaces/index.ts
  60. 6 0
      src/Common/Strings/StringUtil.ts
  61. 12 0
      src/Common/Strings/TextTranslation.ts
  62. 3 0
      src/Common/Strings/index.ts
  63. 4 0
      src/Common/index.ts
  64. 134 0
      src/Display/AbstractDisplayInteractionManager.ts
  65. 313 0
      src/Display/AbstractZoomView.ts
  66. 27 0
      src/Display/PlaybackCursorUserInteractionManager.ts
  67. 217 0
      src/Display/ScreenViewingRegion.ts
  68. 562 0
      src/Display/SheetRenderingManager.ts
  69. 134 0
      src/Display/WebDisplayInteractionManager.ts
  70. 6 0
      src/Display/index.ts
  71. 30 0
      src/MusicalScore/Exceptions.ts
  72. 38 0
      src/MusicalScore/Graphical/AbstractGraphicalExpression.ts
  73. 16 0
      src/MusicalScore/Graphical/AbstractGraphicalInstruction.ts
  74. 128 0
      src/MusicalScore/Graphical/AccidentalCalculator.ts
  75. 743 0
      src/MusicalScore/Graphical/BoundingBox.ts
  76. 5 0
      src/MusicalScore/Graphical/Clickable.ts
  77. 131 0
      src/MusicalScore/Graphical/DrawingEnums.ts
  78. 26 0
      src/MusicalScore/Graphical/DrawingMode.ts
  79. 256 0
      src/MusicalScore/Graphical/DrawingParameters.ts
  80. 823 0
      src/MusicalScore/Graphical/EngravingRules.ts
  81. 34 0
      src/MusicalScore/Graphical/GraphicalChordSymbolContainer.ts
  82. 367 0
      src/MusicalScore/Graphical/GraphicalContinuousDynamicExpression.ts
  83. 49 0
      src/MusicalScore/Graphical/GraphicalCurve.ts
  84. 37 0
      src/MusicalScore/Graphical/GraphicalInstantaneousDynamicExpression.ts
  85. 21 0
      src/MusicalScore/Graphical/GraphicalInstantaneousTempoExpression.ts
  86. 163 0
      src/MusicalScore/Graphical/GraphicalLabel.ts
  87. 22 0
      src/MusicalScore/Graphical/GraphicalLayer.ts
  88. 40 0
      src/MusicalScore/Graphical/GraphicalLine.ts
  89. 64 0
      src/MusicalScore/Graphical/GraphicalLyricEntry.ts
  90. 43 0
      src/MusicalScore/Graphical/GraphicalLyricWord.ts
  91. 17 0
      src/MusicalScore/Graphical/GraphicalMarkedArea.ts
  92. 359 0
      src/MusicalScore/Graphical/GraphicalMeasure.ts
  93. 90 0
      src/MusicalScore/Graphical/GraphicalMusicPage.ts
  94. 1006 0
      src/MusicalScore/Graphical/GraphicalMusicSheet.ts
  95. 79 0
      src/MusicalScore/Graphical/GraphicalNote.ts
  96. 16 0
      src/MusicalScore/Graphical/GraphicalObject.ts
  97. 49 0
      src/MusicalScore/Graphical/GraphicalOctaveShift.ts
  98. 18 0
      src/MusicalScore/Graphical/GraphicalRectangle.ts
  99. 924 0
      src/MusicalScore/Graphical/GraphicalSlur.ts
  100. 313 0
      src/MusicalScore/Graphical/GraphicalStaffEntry.ts

+ 21 - 0
.appveyor.yml

@@ -0,0 +1,21 @@
+image: Visual Studio 2017
+environment:
+  timeout: 10000
+  matrix:
+    # - nodejs_version: "8" 
+    # - nodejs_version: "10"
+    - nodejs_version: "12"
+platform:
+  # - x86
+  - x64
+install:
+  - ps: Install-Product node $env:nodejs_version $env:platform
+  - npm install
+  - node --version
+  - npm --version
+  - npm run fix-memory-limit
+build_script:
+  - npm run lint
+  - npm run build
+test_script:
+  - npm run test

+ 33 - 0
.editorconfig

@@ -0,0 +1,33 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+
+# Matches multiple files with brace expansion notation
+# Set default charset
+[*.{js,py,ts}]
+charset = utf-8
+
+# 4 space indentation
+[*.py,ts]
+indent_style = space
+indent_size = 4
+
+# Tab indentation (no size specified)
+[Makefile]
+indent_style = tab
+
+# Indentation override for all JS under lib directory
+[lib/**.js]
+indent_style = space
+indent_size = 2
+
+# Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml}]
+indent_style = space
+indent_size = 2

+ 6 - 0
.eslintignore

@@ -0,0 +1,6 @@
+node_modules
+dist
+build
+bin
+demo
+src/VexFlowPatch

+ 230 - 0
.eslintrc.js

@@ -0,0 +1,230 @@
+/*
+👋 Hi! This file was autogenerated by tslint-to-eslint-config.
+https://github.com/typescript-eslint/tslint-to-eslint-config
+
+It represents the closest reasonable ESLint configuration to this
+project's original TSLint configuration.
+
+We recommend eventually switching this configuration to extend from
+the recommended rulesets in typescript-eslint. 
+https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md
+
+Happy linting! 💖
+*/
+module.exports = {
+    "env": {
+        "browser": true,
+        "es6": true,
+        "node": true
+    },
+    "parser": "@typescript-eslint/parser",
+    "parserOptions": {
+        "project": "tsconfig.json",
+        "sourceType": "module"
+    },
+    "plugins": [
+        "eslint-plugin-jsdoc",
+        "eslint-plugin-no-null",
+        "@typescript-eslint",
+        //"@typescript-eslint/tslint"
+    ],
+    "overrides": [
+        {
+          "files": ["test/Util/*.js"],
+          "rules": {
+            "@typescript-eslint/explicit-function-return-type": "off",
+            "@typescript-eslint/typedef": "off",
+          }
+        }
+    ],
+    "ignorePatterns": ["webpack*.js"],
+    "rules": {
+        "@typescript-eslint/dot-notation": "error",
+        "@typescript-eslint/explicit-function-return-type": "error",
+        "@typescript-eslint/explicit-member-accessibility": [
+            "off",
+            {
+                "accessibility": "explicit"
+            }
+        ],
+        "@typescript-eslint/indent": [
+            "off",
+            2,
+            {
+                "CallExpression": {
+                    "arguments": "first"
+                },
+                "FunctionDeclaration": {
+                    "parameters": "first"
+                },
+                "FunctionExpression": {
+                    "parameters": "first"
+                }
+            }
+        ],
+        "@typescript-eslint/member-delimiter-style": [
+            "error",
+            {
+                "multiline": {
+                    "delimiter": "semi",
+                    "requireLast": true
+                },
+                "singleline": {
+                    "delimiter": "comma",
+                    "requireLast": false
+                }
+            }
+        ],
+        "@typescript-eslint/member-ordering": "off",
+        "@typescript-eslint/naming-convention": "off",
+        "@typescript-eslint/no-empty-function": "error",
+        "@typescript-eslint/no-explicit-any": "off",
+        "@typescript-eslint/no-inferrable-types": "off",
+        "@typescript-eslint/no-parameter-properties": "error",
+        "@typescript-eslint/no-require-imports": "off",
+        "@typescript-eslint/no-shadow": [
+            "error",
+            {
+                "hoist": "all"
+            }
+        ],
+        "@typescript-eslint/no-unused-expressions": "error",
+        "@typescript-eslint/no-var-requires": "error",
+        "@typescript-eslint/prefer-namespace-keyword": "error",
+        "@typescript-eslint/quotes": [
+            "error",
+            "double",
+            {
+                "avoidEscape": true
+            }
+        ],
+        "@typescript-eslint/semi": [
+            "error"
+        ],
+        "@typescript-eslint/typedef": [
+            "error",
+            {
+              // we could add this requirement for arrow (function) parameters too,
+              //   but we have a lot of arrow parameters without types already (~25),
+              //   and a lot of them look ugly and unnecessarily explicit with types,
+              //   the type info is usually obvious there.
+              "arrowParameter": false,
+              "variableDeclaration": true
+            }
+        ],
+        "@typescript-eslint/type-annotation-spacing": "error",
+        "brace-style": [
+            "off",
+            "1tbs"
+        ],
+        "comma-dangle": "off",
+        "curly": "error",
+        "default-case": "error",
+        "eol-last": "error",
+        "eqeqeq": [
+            "error",
+            "smart"
+        ],
+        "guard-for-in": "error",
+        // this misfires in Typescript
+        /*"id-blacklist": [
+            "error",
+            "any",
+            "Number",
+            "number",
+            "String",
+            "string",
+            "Boolean",
+            "boolean",
+            //"Undefined",
+            //"undefined"
+        ],*/
+        "id-match": "error",
+        "jsdoc/check-alignment": "error",
+        "jsdoc/check-indentation": "off",
+        "jsdoc/newline-after-description": "off",
+        "max-len": [
+            "error",
+            {
+                "code": 160
+            }
+        ],
+        "no-bitwise": "error",
+        "no-caller": "error",
+        "no-cond-assign": "error",
+        "no-console": [
+            "error",
+            {
+                "allow": [
+                    "log",
+                    "warn",
+                    "dir",
+                    "timeLog",
+                    "assert",
+                    "clear",
+                    "count",
+                    "countReset",
+                    "group",
+                    "groupEnd",
+                    "table",
+                    "dirxml",
+                    "error",
+                    "groupCollapsed",
+                    "Console",
+                    "profile",
+                    "profileEnd",
+                    "timeStamp",
+                    "context"
+                ]
+            }
+        ],
+        "no-debugger": "error",
+        "no-empty": "error",
+        "no-eval": "error",
+        "no-fallthrough": "error",
+        "no-multiple-empty-lines": "off",
+        "no-new-wrappers": "error",
+        "no-null/no-null": "off",
+        "no-redeclare": "error",
+        "no-trailing-spaces": "error",
+        "no-underscore-dangle": "off",
+        "no-unused-labels": "error",
+        "no-var": "error",
+        "prefer-const": "error",
+        "radix": "error",
+        "spaced-comment": [
+            "off",
+            "always",
+            {
+                "markers": [
+                    "/"
+                ]
+            }
+        ],
+        // using this requires two extra modules: tslint and @typescript-eslint/tslint.
+        // "@typescript-eslint/tslint/config": [
+        //     "error",
+        //     {
+        //         "rules": {
+        //             "object-literal-sort-keys": true,
+        //             "typedef": [
+        //                 true,
+        //                 "call-signature",
+        //                 "parameter",
+        //                 "property-declaration",
+        //                 "variable-declaration",
+        //                 "member-variable-declaration"
+        //             ],
+        //             "whitespace": [
+        //                 true,
+        //                 "check-branch",
+        //                 "check-decl",
+        //                 "check-operator",
+        //                 "check-separator",
+        //                 "check-type"
+        //             ]
+        //         }
+        //     }
+        // ]
+    }
+};

+ 6 - 0
.eslintrc.yml

@@ -0,0 +1,6 @@
+parserOptions: {
+        ecmaVersion: 8, // 8 = ECMA2017 necessary for promises/async. The ecmaVersion isn't set in stone, for now mostly adapted for eslint.
+    }
+extends: standard
+rules:
+  indent: [2, 4]

+ 67 - 0
.gitignore

@@ -0,0 +1,67 @@
+# Build
+build
+
+# Dist
+dist
+
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# optional npm script-generated data
+visual_regression/
+export/
+
+# Documentation
+docs
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directory
+# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
+node_modules/*
+!node_modules/karma-musicxml2js-preprocessor/
+
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
+
+# TypeScript compiler cache directory
+.tscache
+
+# TypeScript typings
+typings
+*.tmp.*
+.baseDir.ts
+.idea/
+.vscode/
+.idea/encodings.xml
+*.md
+node_modules/
+
+# Private key for GH pages deploy
+bin/gh_pages_deploy_key
+bin/gh_pages_deploy_key.pub
+package-lock.json
+
+#local env files
+webpack.local.js

+ 10 - 0
AUTHORS

@@ -0,0 +1,10 @@
+Andrea Condoluci <a.condoluci@phonicscore.com> (http://llliii.ooo)
+Oliver Hörbinger <o.hoerbinger@phonicscore.com> ()
+Matthias Uiberacker <m.uiberacker@phonicscore.com> ()
+Sebastian Haas <s.haas@phonicscore.com> (http://sebastianhaas.at)
+Benjamin Giesinger <benjamin.giesinger@gmail.com> (http://benjamingiesinger.de)
+Simon Schmid <s.schmid@phonicscore.com> (https://github.com/sschmidTU)
+
+Contributors:
+Pieter Hartzer (https://github.com/PieterHartzer) (https://github.com/opensheetmusicdisplay/opensheetmusicdisplay/pull/327)
+(https://github.com/opensheetmusicdisplay/opensheetmusicdisplay/graphs/contributors)

+ 3 - 0
LICENSE

@@ -0,0 +1,3 @@
+Copyright 2019 PhonicScore
+
+based on OpenSheetMusicDisplay, licensed under BSD-3-Clause, also authored by PhonicScore.

+ 3033 - 0
demo/BrahWiMeSample.musicxml

@@ -0,0 +1,3033 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="3.1">
+  <movement-title>Wie Melodien zieht es mir (Page 1)</movement-title>
+  <identification>
+    <creator type="composer">Johannes Brahms</creator>
+    <creator type="lyricist">Klaus Groth</creator>
+    <rights>Copyright © 2002 MakeMusic, Inc.</rights>
+    <encoding>
+      <software>Finale v25 for Mac</software>
+      <encoding-date>2017-12-12</encoding-date>
+      <supports attribute="new-system" element="print" type="yes" value="yes"/>
+      <supports attribute="new-page" element="print" type="yes" value="yes"/>
+      <supports element="accidental" type="yes"/>
+      <supports element="beam" type="yes"/>
+      <supports element="stem" type="yes"/>
+    </encoding>
+  </identification>
+  <defaults>
+    <scaling>
+      <millimeters>6.35</millimeters>
+      <tenths>40</tenths>
+    </scaling>
+    <page-layout>
+      <page-height>1760</page-height>
+      <page-width>1360</page-width>
+      <page-margins type="both">
+        <left-margin>80</left-margin>
+        <right-margin>80</right-margin>
+        <top-margin>80</top-margin>
+        <bottom-margin>80</bottom-margin>
+      </page-margins>
+    </page-layout>
+    <system-layout>
+      <system-margins>
+        <left-margin>0</left-margin>
+        <right-margin>0</right-margin>
+      </system-margins>
+      <system-distance>130</system-distance>
+      <top-system-distance>70</top-system-distance>
+    </system-layout>
+    <staff-layout>
+      <staff-distance>80</staff-distance>
+    </staff-layout>
+    <appearance>
+      <line-width type="stem">0.8333</line-width>
+      <line-width type="beam">5</line-width>
+      <line-width type="staff">1.25</line-width>
+      <line-width type="light barline">1.875</line-width>
+      <line-width type="heavy barline">5</line-width>
+      <line-width type="leger">1.875</line-width>
+      <line-width type="ending">0.8333</line-width>
+      <line-width type="wedge">1.25</line-width>
+      <line-width type="enclosure">1.25</line-width>
+      <line-width type="tuplet bracket">0.8333</line-width>
+      <note-size type="grace">60</note-size>
+      <note-size type="cue">60</note-size>
+      <distance type="hyphen">60</distance>
+      <distance type="beam">8</distance>
+    </appearance>
+    <music-font font-family="Maestro,engraved" font-size="18"/>
+    <word-font font-family="Times New Roman" font-size="9"/>
+    <lyric-font font-family="Times New Roman" font-size="10"/>
+  </defaults>
+  <credit page="1">
+    <credit-type>page number</credit-type>
+    <credit-words default-x="80" default-y="1680" font-size="12" valign="top">2</credit-words>
+  </credit>
+  <credit page="1">
+    <credit-type>rights</credit-type>
+    <credit-words default-x="680" default-y="80" font-size="9" halign="center" valign="bottom">Copyright © 2002 MakeMusic, Inc.</credit-words>
+  </credit>
+  <credit page="1">
+    <credit-type>title</credit-type>
+    <credit-words default-x="680" default-y="1640" font-size="24" justify="center" valign="top">Wie Melodien zieht es mir</credit-words>
+  </credit>
+  <credit page="1">
+    <credit-words default-x="680" default-y="1580" font-size="14" justify="center" valign="top">Op. 105, No. 1</credit-words>
+  </credit>
+  <credit page="1">
+    <credit-type>lyricist</credit-type>
+    <credit-words default-x="80" default-y="1500" font-size="10" valign="bottom">Klaus Groth</credit-words>
+  </credit>
+  <credit page="1">
+    <credit-type>composer</credit-type>
+    <credit-words default-x="1280" default-y="1500" font-size="10" halign="right" valign="bottom">Johannes Brahms</credit-words>
+  </credit>
+  <part-list>
+    <score-part id="P1">
+      <part-name>Voice</part-name>
+      <score-instrument id="P1-I1">
+        <instrument-name>Voice</instrument-name>
+        <instrument-sound>voice.vocals</instrument-sound>
+        <solo/>
+      </score-instrument>
+      <midi-instrument id="P1-I1">
+        <midi-channel>1</midi-channel>
+        <midi-program>53</midi-program>
+        <volume>80</volume>
+        <pan>0</pan>
+      </midi-instrument>
+    </score-part>
+    <score-part id="P2">
+      <part-name>Piano</part-name>
+      <score-instrument id="P2-I2">
+        <instrument-name>Acoustic Grand Piano</instrument-name>
+        <instrument-sound>keyboard.piano</instrument-sound>
+      </score-instrument>
+      <midi-instrument id="P2-I2">
+        <midi-channel>2</midi-channel>
+        <midi-program>1</midi-program>
+        <volume>80</volume>
+        <pan>0</pan>
+      </midi-instrument>
+    </score-part>
+  </part-list>
+  <!--=========================================================-->
+  <part id="P1">
+    <measure number="1" width="340">
+      <print page-number="2">
+        <system-layout>
+          <system-margins>
+            <left-margin>120</left-margin>
+            <right-margin>0</right-margin>
+          </system-margins>
+          <top-system-distance>230</top-system-distance>
+        </system-layout>
+        <measure-numbering>system</measure-numbering>
+      </print>
+      <attributes>
+        <divisions>2</divisions>
+        <key>
+          <fifths>3</fifths>
+          <mode>major</mode>
+        </key>
+        <time symbol="cut">
+          <beats>2</beats>
+          <beat-type>2</beat-type>
+        </time>
+        <clef>
+          <sign>G</sign>
+          <line>2</line>
+        </clef>
+      </attributes>
+      <direction directive="yes" placement="above">
+        <direction-type>
+          <words default-y="15" font-size="10.5" font-weight="bold">Zart</words>
+        </direction-type>
+        <sound tempo="96"/>
+      </direction>
+      <note default-x="139">
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+      <note default-x="189">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-14">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>Wie</text>
+        </lyric>
+      </note>
+      <note default-x="239">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-4">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>begin</syllabic>
+          <text>Me</text>
+        </lyric>
+      </note>
+      <note default-x="289">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="11">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>middle</syllabic>
+          <text>lo</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="2" width="220">
+      <note default-x="18">
+        <pitch>
+          <step>D</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-45.5">down</stem>
+        <notations>
+          <slur number="1" placement="above" type="start"/>
+        </notations>
+        <lyric default-y="-80" number="1">
+          <syllabic>middle</syllabic>
+          <text>di</text>
+        </lyric>
+      </note>
+      <note default-x="68">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-50.5">down</stem>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="118">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-55.5">down</stem>
+        <notations>
+          <slur number="1" placement="above" type="start"/>
+        </notations>
+        <lyric default-y="-80" number="1">
+          <syllabic>end</syllabic>
+          <text>en</text>
+          <extend/>
+        </lyric>
+      </note>
+      <note default-x="168">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="11">up</stem>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="3" width="217">
+      <note default-x="18">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="6">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>zieht</text>
+        </lyric>
+      </note>
+      <note default-x="116">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="1">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>es</text>
+        </lyric>
+      </note>
+      <note default-x="166">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="11">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>mir</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="4" width="303">
+      <note default-x="26">
+        <pitch>
+          <step>F</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <accidental>natural</accidental>
+        <stem default-y="1">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>begin</syllabic>
+          <text>lei</text>
+        </lyric>
+      </note>
+      <note default-x="132">
+        <pitch>
+          <step>G</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <accidental>natural</accidental>
+        <stem default-y="6">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>end</syllabic>
+          <text>se</text>
+        </lyric>
+      </note>
+      <note default-x="175">
+        <pitch>
+          <step>F</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="1">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>durch</text>
+        </lyric>
+      </note>
+      <note default-x="265">
+        <pitch>
+          <step>G</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="6">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>den</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="5" width="371">
+      <print new-system="yes">
+        <system-layout>
+          <system-distance>165</system-distance>
+        </system-layout>
+      </print>
+      <note default-x="107">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="-4">up</stem>
+        <lyric default-y="-80" number="1" relative-x="3">
+          <syllabic>single</syllabic>
+          <text>Sinn,</text>
+        </lyric>
+      </note>
+      <note default-x="243">
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+      <note default-x="304">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-50.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>wie</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="6" width="315">
+      <note default-x="18">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="-55.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>begin</syllabic>
+          <text>Früh</text>
+        </lyric>
+      </note>
+      <note default-x="124">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="1">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>middle</syllabic>
+          <text>lings</text>
+        </lyric>
+      </note>
+      <note default-x="168">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="6">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>middle</syllabic>
+          <text>blu</text>
+        </lyric>
+      </note>
+      <note default-x="274">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-4">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>end</syllabic>
+          <text>men</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="7" width="230">
+      <note default-x="18">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="-55.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>blüht</text>
+        </lyric>
+      </note>
+      <note default-x="123">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="11">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>es</text>
+        </lyric>
+      </note>
+      <note default-x="175">
+        <pitch>
+          <step>E</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-40.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>und</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="8" width="284">
+      <note default-x="27">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <accidental>sharp</accidental>
+        <stem default-y="-45.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>schwebt</text>
+        </lyric>
+      </note>
+      <note default-x="120">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-50.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>wie</text>
+        </lyric>
+      </note>
+      <note default-x="163">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="-55.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>Duft</text>
+        </lyric>
+      </note>
+      <note default-x="249">
+        <pitch>
+          <step>F</step>
+          <alter>2</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <accidental>double-sharp</accidental>
+        <stem default-y="1">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>begin</syllabic>
+          <text>da</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="9" width="296">
+      <print new-system="yes">
+        <system-layout>
+          <system-distance>165</system-distance>
+        </system-layout>
+      </print>
+      <note default-x="113">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="6">up</stem>
+        <lyric default-y="-80" number="1" relative-x="3">
+          <syllabic>end</syllabic>
+          <text>hin,</text>
+        </lyric>
+      </note>
+      <note default-x="210">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="10" width="202">
+      <note default-x="16">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+      <note default-x="118">
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+      <note default-x="159">
+        <pitch>
+          <step>B</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <accidental>sharp</accidental>
+        <stem default-y="-55.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>und</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="11" width="251">
+      <note default-x="39">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <accidental>sharp</accidental>
+        <stem default-y="-45.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>schwebt</text>
+        </lyric>
+      </note>
+      <note default-x="108">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-50.5">down</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>wie</text>
+        </lyric>
+      </note>
+      <note default-x="151">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="11">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>single</syllabic>
+          <text>Duft</text>
+        </lyric>
+      </note>
+      <note default-x="221">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <accidental>sharp</accidental>
+        <stem default-y="-9">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>begin</syllabic>
+          <text>da</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="12" width="220">
+      <note default-x="24">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="-4">up</stem>
+        <lyric default-y="-80" number="1">
+          <syllabic>end</syllabic>
+          <text>hin.</text>
+        </lyric>
+      </note>
+      <note default-x="120">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="13" width="231">
+      <note>
+        <rest measure="yes"/>
+        <duration>8</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+  </part>
+  <!--=========================================================-->
+  <part id="P2">
+    <measure number="1" width="340">
+      <print>
+        <staff-layout number="1">
+          <staff-distance>100</staff-distance>
+        </staff-layout>
+        <staff-layout number="2">
+          <staff-distance>60</staff-distance>
+        </staff-layout>
+        <measure-numbering>none</measure-numbering>
+      </print>
+      <attributes>
+        <divisions>8</divisions>
+        <key>
+          <fifths>3</fifths>
+          <mode>major</mode>
+        </key>
+        <time symbol="cut">
+          <beats>2</beats>
+          <beat-type>2</beat-type>
+        </time>
+        <staves>2</staves>
+        <clef number="1">
+          <sign>F</sign>
+          <line>4</line>
+        </clef>
+        <clef number="2">
+          <sign>F</sign>
+          <line>4</line>
+        </clef>
+      </attributes>
+      <direction placement="below">
+        <direction-type>
+          <dynamics default-y="-80" halign="left">
+            <p/>
+          </dynamics>
+        </direction-type>
+        <staff>1</staff>
+        <sound dynamics="54"/>
+      </direction>
+      <note default-x="139">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <direction placement="below">
+        <direction-type>
+          <words default-y="-80" font-style="italic" relative-x="14">sempre dolce</words>
+        </direction-type>
+        <staff>1</staff>
+      </direction>
+      <note default-x="164">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-50">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur default-x="7" default-y="14" number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="189">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-48">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="214">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-45">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="239">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-55">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+      </note>
+      <note default-x="264">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-60.5">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="289">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="36">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="313">
+        <pitch>
+          <step>A</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="30">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="139">
+        <pitch>
+          <step>A</step>
+          <octave>1</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>3</voice>
+        <type>half</type>
+        <stem default-y="1">up</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="139">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>3</voice>
+        <type>half</type>
+        <stem>up</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="239">
+        <rest/>
+        <duration>8</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <staff>2</staff>
+      </note>
+      <forward>
+        <duration>8</duration>
+        <voice>3</voice>
+        <staff>2</staff>
+      </forward>
+    </measure>
+    <!--=======================================================-->
+    <measure number="2" width="220">
+      <note default-x="18">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="43">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-35">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur default-x="7" default-y="20" number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="68">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-32">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="93">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-30">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="118">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-55">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+      </note>
+      <note default-x="143">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-60.5">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="168">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="36">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="193">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="30">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="18">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>3</voice>
+        <type>half</type>
+        <stem default-y="-19">up</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="119">
+        <rest/>
+        <duration>8</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <staff>2</staff>
+      </note>
+      <forward>
+        <duration>8</duration>
+        <voice>3</voice>
+        <staff>2</staff>
+      </forward>
+    </measure>
+    <!--=======================================================-->
+    <measure number="3" width="217">
+      <forward>
+        <duration>32</duration>
+        <voice>1</voice>
+        <staff>1</staff>
+      </forward>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="18">
+        <pitch>
+          <step>D</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="29">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="43">
+        <pitch>
+          <step>A</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="35">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="68">
+        <pitch>
+          <step>D</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="41">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+        <notations>
+          <slur default-x="6" default-y="-37" number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="92">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-61">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="92">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="116">
+        <pitch>
+          <step>D</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="29">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="141">
+        <pitch>
+          <step>D</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="35">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="166">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="41">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+        <notations>
+          <slur default-x="6" default-y="-26" number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="191">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-61">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="191">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="4" width="303">
+      <forward>
+        <duration>32</duration>
+        <voice>1</voice>
+        <staff>1</staff>
+      </forward>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="26">
+        <pitch>
+          <step>D</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="29.5">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="62">
+        <pitch>
+          <step>B</step>
+          <alter>-1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <accidental>flat</accidental>
+        <stem default-y="35">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="90">
+        <pitch>
+          <step>D</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="39.5">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+        <notations>
+          <slur default-x="8" default-y="-37" number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="132">
+        <pitch>
+          <step>F</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <accidental>natural</accidental>
+        <stem default-y="-60.5">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="132">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <alter>-1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <accidental>flat</accidental>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="175">
+        <pitch>
+          <step>D</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="29">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="204">
+        <pitch>
+          <step>D</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="34.5">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="237">
+        <pitch>
+          <step>F</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <accidental>natural</accidental>
+        <stem default-y="41">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+        <notations>
+          <slur default-x="6" default-y="-26" number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="265">
+        <pitch>
+          <step>B</step>
+          <alter>-1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-60.5">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="265">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="5" width="371">
+      <print new-system="yes">
+        <staff-layout number="2">
+          <staff-distance>70</staff-distance>
+        </staff-layout>
+      </print>
+      <forward>
+        <duration>16</duration>
+        <voice>1</voice>
+        <staff>1</staff>
+      </forward>
+      <attributes>
+        <clef number="1">
+          <sign>G</sign>
+          <line>2</line>
+        </clef>
+      </attributes>
+      <note default-x="243">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="271">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-4">up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="271">
+        <chord/>
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="304">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="337">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="11">up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="337">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="107">
+        <pitch>
+          <step>A</step>
+          <octave>1</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="34">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="136">
+        <pitch>
+          <step>A</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="40">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="164">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="46">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+        <notations>
+          <slur default-x="6" default-y="-35" number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="194">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-66">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="194">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="243">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-35.5">down</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="271">
+        <rest/>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <staff>2</staff>
+      </note>
+      <note default-x="304">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="11">up</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="337">
+        <rest/>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <staff>2</staff>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="6" width="315">
+      <note default-x="18">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="52">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-19">up</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="start"/>
+        </notations>
+      </note>
+      <note default-x="96">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="1">up</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="96">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="168">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="202">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-19">up</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="start"/>
+        </notations>
+      </note>
+      <note default-x="247">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-4">up</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="247">
+        <chord/>
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="18">
+        <pitch>
+          <step>D</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="-19">up</stem>
+        <staff>2</staff>
+        <notations>
+          <slur number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="124">
+        <pitch>
+          <step>D</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-55.5">down</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="168">
+        <pitch>
+          <step>D</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="-19">up</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="274">
+        <pitch>
+          <step>D</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-55.5">down</stem>
+        <staff>2</staff>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="7" width="230">
+      <note default-x="18">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="44">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-5">up</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="70">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-5">up</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="96">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-5">up</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="123">
+        <rest/>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="175">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-50.5">down</stem>
+        <staff>1</staff>
+        <notations>
+          <slur number="2" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="175">
+        <chord/>
+        <pitch>
+          <step>E</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="18">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>3</voice>
+        <type>half</type>
+        <stem default-y="-19">up</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="123">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="35">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+      </note>
+      <note default-x="149">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="33.5">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="175">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="32">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="201">
+        <pitch>
+          <step>A</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="30">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="8" width="284">
+      <note default-x="27">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="-55.5">down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="27">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <accidental>sharp</accidental>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="120">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-58">down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="120">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="163">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="16">up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="163">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="249">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <accidental>sharp</accidental>
+        <stem default-y="1">up</stem>
+        <staff>1</staff>
+        <notations>
+          <slur number="2" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="249">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>2</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <accidental>double-sharp</accidental>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="27">
+        <pitch>
+          <step>B</step>
+          <octave>1</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="10">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="56">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="12">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="91">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <accidental>sharp</accidental>
+        <stem default-y="15">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur default-x="6" default-y="-36" number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="120">
+        <rest/>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <staff>2</staff>
+      </note>
+      <note default-x="163">
+        <rest/>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <staff>2</staff>
+      </note>
+      <note default-x="191">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-65">down</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur default-x="6" default-y="-15" number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="220">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-60">down</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="249">
+        <rest/>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <staff>2</staff>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="9" width="296">
+      <print new-system="yes">
+        <staff-layout number="2">
+          <staff-distance>90</staff-distance>
+        </staff-layout>
+      </print>
+      <note default-x="113">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="6">up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="113">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="159">
+        <pitch>
+          <step>E</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="-40.5">down</stem>
+        <staff>1</staff>
+        <notations>
+          <slur number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="159">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="253">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <accidental>sharp</accidental>
+        <stem default-y="-45.5">down</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="start"/>
+        </notations>
+      </note>
+      <note default-x="253">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>down</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="start"/>
+        </notations>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="113">
+        <pitch>
+          <step>E</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="35">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="2" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="136">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="37">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="159">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="38.5">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="182">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="40">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="212">
+        <pitch>
+          <step>B</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <accidental>sharp</accidental>
+        <stem default-y="-30.5">down</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="235">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <stem default-y="-40.5">down</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="272">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-50.5">down</stem>
+        <staff>2</staff>
+        <notations>
+          <slur number="2" type="stop"/>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="10" width="202">
+      <note default-x="18">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-45.5">down</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="18">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>down</stem>
+        <staff>1</staff>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="63">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="-50.5">down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="63">
+        <chord/>
+        <pitch>
+          <step>E</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>16</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="159">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="16">up</stem>
+        <staff>1</staff>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="159">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <accidental>sharp</accidental>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="18">
+        <pitch>
+          <step>E</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-85">down</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur bezier-x="25" bezier-y="74" default-x="6" default-y="-25" number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="41">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-83">down</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="63">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-81.5">down</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="86">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-80">down</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="118">
+        <pitch>
+          <step>D</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <accidental>natural</accidental>
+        <stem default-y="-20.5">down</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="141">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <stem default-y="-40.5">down</stem>
+        <staff>2</staff>
+      </note>
+      <note default-x="177">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="-50.5">down</stem>
+        <staff>2</staff>
+        <notations>
+          <slur bezier-x="-42" bezier-y="44" default-x="6" default-y="5" number="1" type="stop"/>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="11" width="251">
+      <note default-x="39">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <accidental>natural</accidental>
+        <stem default-y="-55.5">down</stem>
+        <staff>1</staff>
+        <notations>
+          <slur number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="39">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <accidental>sharp</accidental>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="108">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-58">down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="108">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>down</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="151">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem default-y="11">up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="151">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>12</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <dot/>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <note default-x="221">
+        <pitch>
+          <step>A</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-9">up</stem>
+        <staff>1</staff>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="221">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <accidental>sharp</accidental>
+        <stem>up</stem>
+        <staff>1</staff>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="39">
+        <pitch>
+          <step>A</step>
+          <octave>1</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="20">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur bezier-x="30" bezier-y="1" default-x="7" default-y="-82" number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="62">
+        <pitch>
+          <step>A</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="22">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="85">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="23.5">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="108">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="25">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur bezier-x="-6" bezier-y="-30" default-x="7" default-y="-24" number="1" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="151">
+        <rest/>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <staff>2</staff>
+      </note>
+      <note default-x="175">
+        <pitch>
+          <step>B</step>
+          <octave>1</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="20">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur bezier-x="24" bezier-y="-1" default-x="7" default-y="-77" number="1" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="198">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="23">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="221">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="25">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur bezier-x="-2" bezier-y="-25" default-x="6" default-y="-35" number="1" type="stop"/>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="12" width="220">
+      <forward>
+        <duration>16</duration>
+        <voice>1</voice>
+        <staff>1</staff>
+      </forward>
+      <forward>
+        <duration>8</duration>
+        <voice>1</voice>
+        <staff>1</staff>
+      </forward>
+      <direction placement="below">
+        <direction-type>
+          <wedge default-y="-73" type="crescendo"/>
+        </direction-type>
+        <offset>-1</offset>
+        <staff>1</staff>
+      </direction>
+      <note default-x="168">
+        <rest>
+          <display-step>B</display-step>
+          <display-octave>4</display-octave>
+        </rest>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <direction>
+        <direction-type>
+          <wedge spread="12" type="stop"/>
+        </direction-type>
+        <offset>2</offset>
+        <staff>1</staff>
+      </direction>
+      <note default-x="191">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="6">up</stem>
+        <staff>1</staff>
+        <notations>
+          <slur number="1" placement="above" type="start"/>
+        </notations>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="24">
+        <rest>
+          <display-step>B</display-step>
+          <display-octave>4</display-octave>
+        </rest>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <staff>1</staff>
+      </note>
+      <note default-x="47">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <stem default-y="-75">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur bezier-x="19" bezier-y="45" default-x="6" default-y="-7" number="2" placement="above" type="start"/>
+        </notations>
+      </note>
+      <note default-x="76">
+        <pitch>
+          <step>D</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <accidental>natural</accidental>
+        <stem default-y="-72">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="98">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <stem default-y="-70">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <note default-x="122">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <stem default-y="-80">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+      </note>
+      <note default-x="145">
+        <pitch>
+          <step>E</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <stem default-y="-84">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="168">
+        <pitch>
+          <step>D</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <stem default-y="44.5">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="191">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>2</voice>
+        <type>eighth</type>
+        <stem default-y="40">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="24">
+        <pitch>
+          <step>E</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="25">up</stem>
+        <staff>2</staff>
+        <beam number="1">begin</beam>
+        <notations>
+          <slur number="3" placement="below" type="start"/>
+        </notations>
+      </note>
+      <note default-x="47">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="27">up</stem>
+        <staff>2</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="76">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <stem default-y="30">up</stem>
+        <staff>2</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur number="3" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="98">
+        <rest/>
+        <duration>4</duration>
+        <voice>3</voice>
+        <type>eighth</type>
+        <staff>2</staff>
+      </note>
+      <note default-x="122">
+        <rest/>
+        <duration>8</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <staff>2</staff>
+      </note>
+      <forward>
+        <duration>8</duration>
+        <voice>3</voice>
+        <staff>2</staff>
+      </forward>
+    </measure>
+    <!--=======================================================-->
+    <measure number="13" width="231">
+      <direction placement="below">
+        <direction-type>
+          <wedge default-y="-73" spread="12" type="diminuendo"/>
+        </direction-type>
+        <staff>1</staff>
+      </direction>
+      <note default-x="15">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-60">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+      </note>
+      <note default-x="38">
+        <pitch>
+          <step>D</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-61.5">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="61">
+        <pitch>
+          <step>B</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-63">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <direction>
+        <direction-type>
+          <wedge type="stop"/>
+        </direction-type>
+        <offset>1</offset>
+        <staff>1</staff>
+      </direction>
+      <note default-x="84">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-65">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+      </note>
+      <attributes>
+        <clef number="1">
+          <sign>F</sign>
+          <line>4</line>
+        </clef>
+      </attributes>
+      <note default-x="136">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-35">down</stem>
+        <staff>1</staff>
+        <beam number="1">begin</beam>
+      </note>
+      <note default-x="160">
+        <pitch>
+          <step>D</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-36.5">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="183">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-38">down</stem>
+        <staff>1</staff>
+        <beam number="1">continue</beam>
+      </note>
+      <note default-x="206">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-40">down</stem>
+        <staff>1</staff>
+        <beam number="1">end</beam>
+        <notations>
+          <slur number="1" type="stop"/>
+        </notations>
+      </note>
+      <backup>
+        <duration>32</duration>
+      </backup>
+      <note default-x="15">
+        <pitch>
+          <step>E</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>8</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <stem default-y="-50.5">down</stem>
+        <staff>2</staff>
+        <notations>
+          <slur bezier-x="-32" bezier-y="118" default-x="7" default-y="-5" number="2" type="stop"/>
+        </notations>
+      </note>
+      <note default-x="61">
+        <rest/>
+        <duration>8</duration>
+        <voice>3</voice>
+        <type>quarter</type>
+        <staff>2</staff>
+      </note>
+      <note default-x="134">
+        <rest/>
+        <duration>16</duration>
+        <voice>3</voice>
+        <type>half</type>
+        <staff>2</staff>
+      </note>
+    </measure>
+  </part>
+  <!--=========================================================-->
+</score-partwise>

+ 5929 - 0
demo/BrookeWestSample.musicxml

@@ -0,0 +1,5929 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.1 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="3.1">
+  <movement-title>West Point</movement-title>
+  <identification>
+    <creator type="composer">Jonatha Brooke</creator>
+    <rights>© 1995 Dog Dream Music. All rights reserved.</rights>
+    <encoding>
+      <software>Finale v25 for Mac</software>
+      <encoding-date>2017-12-12</encoding-date>
+      <supports attribute="new-system" element="print" type="yes" value="yes"/>
+      <supports attribute="new-page" element="print" type="yes" value="yes"/>
+      <supports element="accidental" type="yes"/>
+      <supports element="beam" type="yes"/>
+      <supports element="stem" type="yes"/>
+    </encoding>
+  </identification>
+  <defaults>
+    <scaling>
+      <millimeters>7.2319</millimeters>
+      <tenths>40</tenths>
+    </scaling>
+    <page-layout>
+      <page-height>1545</page-height>
+      <page-width>1194</page-width>
+      <page-margins type="both">
+        <left-margin>140</left-margin>
+        <right-margin>70</right-margin>
+        <top-margin>70</top-margin>
+        <bottom-margin>70</bottom-margin>
+      </page-margins>
+    </page-layout>
+    <system-layout>
+      <system-margins>
+        <left-margin>0</left-margin>
+        <right-margin>0</right-margin>
+      </system-margins>
+      <system-distance>181</system-distance>
+      <top-system-distance>70</top-system-distance>
+    </system-layout>
+    <staff-layout>
+      <staff-distance>81</staff-distance>
+    </staff-layout>
+    <appearance>
+      <line-width type="stem">0.957</line-width>
+      <line-width type="beam">5</line-width>
+      <line-width type="staff">1.4583</line-width>
+      <line-width type="light barline">1.4583</line-width>
+      <line-width type="heavy barline">5</line-width>
+      <line-width type="leger">1.875</line-width>
+      <line-width type="ending">1.4583</line-width>
+      <line-width type="wedge">0.9375</line-width>
+      <line-width type="enclosure">1.4583</line-width>
+      <line-width type="tuplet bracket">1.4583</line-width>
+      <note-size type="grace">50</note-size>
+      <note-size type="cue">50</note-size>
+      <distance type="hyphen">60</distance>
+      <distance type="beam">8</distance>
+    </appearance>
+    <music-font font-family="Jazz,handwritten" font-size="20.5"/>
+    <word-font font-family="JazzText" font-size="10.25"/>
+    <lyric-font font-family="JazzText" font-size="10.25"/>
+  </defaults>
+  <credit page="1">
+    <credit-type>composer</credit-type>
+    <credit-words default-x="1124" default-y="1393" font-size="12" font-weight="bold" halign="right" justify="center" valign="top" xml:space="preserve">Words and Music by
+Jonatha Brooke</credit-words>
+  </credit>
+  <credit page="1">
+    <credit-type>rights</credit-type>
+    <credit-words default-x="632" default-y="44" font-size="10" justify="center" valign="bottom">© 1995 Dog Dream Music. All rights reserved. Transcription by Ken Temple, Marian Russell, and Michael Good.</credit-words>
+  </credit>
+  <credit page="1">
+    <credit-type>title</credit-type>
+    <credit-words default-x="632" default-y="1458" font-size="24" font-weight="bold" justify="center" valign="top">West Point</credit-words>
+  </credit>
+  <part-list>
+    <score-part id="P1">
+      <part-name print-object="no">Voice</part-name>
+      <score-instrument id="P1-I3">
+        <instrument-name>Voice</instrument-name>
+        <instrument-sound>voice.vocals</instrument-sound>
+        <solo/>
+      </score-instrument>
+      <midi-instrument id="P1-I3">
+        <midi-channel>1</midi-channel>
+        <midi-program>55</midi-program>
+        <volume>80</volume>
+        <pan>0</pan>
+      </midi-instrument>
+    </score-part>
+    <score-part id="P2">
+      <part-name print-object="no">Guitar</part-name>
+      <score-instrument id="P2-I2">
+        <instrument-name>Acoustic Guitar (steel)</instrument-name>
+        <instrument-sound>pluck.guitar.steel-string</instrument-sound>
+      </score-instrument>
+      <midi-instrument id="P2-I2">
+        <midi-channel>2</midi-channel>
+        <midi-program>26</midi-program>
+        <volume>80</volume>
+        <pan>0</pan>
+      </midi-instrument>
+    </score-part>
+  </part-list>
+  <!--=========================================================-->
+  <part id="P1">
+    <measure number="1">
+      <print>
+        <measure-numbering>none</measure-numbering>
+      </print>
+      <attributes>
+        <divisions>4</divisions>
+        <key>
+          <fifths>6</fifths>
+          <mode>major</mode>
+        </key>
+        <time symbol="common">
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+        </time>
+        <clef>
+          <sign>G</sign>
+          <line>2</line>
+        </clef>
+        <staff-details print-object="no"/>
+      </attributes>
+      <sound tempo="84"/>
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="2">
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="3">
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="4">
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="5">
+      <print new-system="yes"/>
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="6">
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="7">
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="8">
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="9">
+      <note>
+        <rest measure="yes"/>
+        <duration>16</duration>
+        <voice>1</voice>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="10" width="313">
+      <print new-system="yes">
+        <system-layout>
+          <system-distance>83</system-distance>
+        </system-layout>
+      </print>
+      <attributes>
+        <staff-details print-object="yes"/>
+      </attributes>
+      <note default-x="140">
+        <rest/>
+        <duration>8</duration>
+        <voice>1</voice>
+        <type>half</type>
+      </note>
+      <note default-x="216">
+        <rest/>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+      <note default-x="257">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">begin</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>I'm</text>
+        </lyric>
+      </note>
+      <note default-x="284">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="10">up</stem>
+        <beam number="1">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>begin</syllabic>
+          <text>re</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="11" width="357">
+      <note default-x="16">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">forward hook</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>middle</syllabic>
+          <text>tra</text>
+        </lyric>
+      </note>
+      <note default-x="52">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>middle</syllabic>
+          <text>vel</text>
+        </lyric>
+      </note>
+      <note default-x="93">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>end</syllabic>
+          <text>ling</text>
+        </lyric>
+      </note>
+      <note default-x="134">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>this</text>
+        </lyric>
+      </note>
+      <note default-x="172">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">backward hook</beam>
+        <notations>
+          <tied type="start"/>
+        </notations>
+        <lyric default-y="-97" number="1">
+          <syllabic>begin</syllabic>
+          <text>life</text>
+        </lyric>
+      </note>
+      <note default-x="219">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">forward hook</beam>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="246">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem default-y="2.5">up</stem>
+        <beam number="1">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>end</syllabic>
+          <text>line</text>
+        </lyric>
+      </note>
+      <note default-x="293">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">begin</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>that's</text>
+        </lyric>
+      </note>
+      <note default-x="331">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="10">up</stem>
+        <beam number="1">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>so</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="12" width="313">
+      <note default-x="25">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem default-y="5">up</stem>
+        <beam number="1">begin</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>close</text>
+        </lyric>
+      </note>
+      <note default-x="63">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="2.5">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">backward hook</beam>
+        <notations>
+          <tied type="start"/>
+        </notations>
+        <lyric default-y="-97" justify="left" number="1">
+          <syllabic>single</syllabic>
+          <text>to</text>
+          <extend/>
+        </lyric>
+      </note>
+      <note default-x="102">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-5">up</stem>
+        <beam number="1">begin</beam>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="139">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-7">up</stem>
+        <beam number="1">end</beam>
+        <notations>
+          <tied type="start"/>
+        </notations>
+        <lyric default-y="-97" justify="left" number="1">
+          <syllabic>single</syllabic>
+          <text>home</text>
+          <extend/>
+        </lyric>
+      </note>
+      <note default-x="187">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-4">up</stem>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="228">
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+      </note>
+      <note default-x="251">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-10">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">begin</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>We</text>
+        </lyric>
+      </note>
+      <note default-x="283">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-7">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>are</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="13" width="570">
+      <print new-system="yes">
+        <system-layout>
+          <system-distance>83</system-distance>
+        </system-layout>
+      </print>
+      <note default-x="142">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="0">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">forward hook</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>on</text>
+        </lyric>
+      </note>
+      <note default-x="176">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="0">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>our</text>
+        </lyric>
+      </note>
+      <note default-x="219">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="0">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>way</text>
+        </lyric>
+      </note>
+      <note default-x="260">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="0">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>to</text>
+        </lyric>
+      </note>
+      <note default-x="303">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="0">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">backward hook</beam>
+        <notations>
+          <tied type="start"/>
+        </notations>
+        <lyric default-y="-97" justify="left" number="1">
+          <syllabic>single</syllabic>
+          <text>West</text>
+          <extend/>
+        </lyric>
+      </note>
+      <note default-x="357">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-15">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">forward hook</beam>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="393">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem default-y="-17">up</stem>
+        <beam number="1">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>Point</text>
+        </lyric>
+      </note>
+      <note default-x="440">
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+      </note>
+      <note default-x="483">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-10">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">begin</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>Where</text>
+        </lyric>
+      </note>
+      <note default-x="533">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-7.5">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>your</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="14" width="413">
+      <note default-x="15">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-5">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">begin</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>begin</syllabic>
+          <text>per</text>
+        </lyric>
+      </note>
+      <note default-x="57">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-7.5">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>end</syllabic>
+          <text>fect,</text>
+        </lyric>
+      </note>
+      <note default-x="93">
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+      </note>
+      <note default-x="133">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem default-y="-9.5">up</stem>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>blond</text>
+        </lyric>
+      </note>
+      <note default-x="195">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">forward hook</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>begin</syllabic>
+          <text>cou</text>
+        </lyric>
+      </note>
+      <note default-x="233">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>end</syllabic>
+          <text>sin</text>
+        </lyric>
+      </note>
+      <note default-x="278">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>will</text>
+        </lyric>
+      </note>
+      <note default-x="333">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>throw</text>
+        </lyric>
+      </note>
+      <note default-x="381">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">backward hook</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>his</text>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="15" width="408">
+      <print new-system="yes">
+        <system-layout>
+          <system-distance>77</system-distance>
+        </system-layout>
+      </print>
+      <note default-x="146">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-19">up</stem>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>hat</text>
+        </lyric>
+      </note>
+      <note default-x="177">
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+      </note>
+      <note default-x="209">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="5">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">begin</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>in</text>
+        </lyric>
+      </note>
+      <note default-x="238">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="7.5">up</stem>
+        <beam number="1">continue</beam>
+        <beam number="2">end</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>the</text>
+        </lyric>
+      </note>
+      <note default-x="268">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="10">up</stem>
+        <beam number="1">end</beam>
+        <notations>
+          <tied type="start"/>
+        </notations>
+        <lyric default-y="-97" justify="left" number="1">
+          <syllabic>single</syllabic>
+          <text>air</text>
+          <extend/>
+        </lyric>
+      </note>
+      <note default-x="310">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="stop"/>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="10.5">up</stem>
+        <notations>
+          <tied type="stop"/>
+          <tied type="start"/>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="16" width="328">
+      <note default-x="10">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>8</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>half</type>
+        <stem default-y="10.5">up</stem>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="104">
+        <rest/>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+      </note>
+      <note default-x="151">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-19">up</stem>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>And</text>
+        </lyric>
+      </note>
+      <note default-x="185">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">forward hook</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>we</text>
+        </lyric>
+      </note>
+      <note default-x="223">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>will</text>
+        </lyric>
+      </note>
+      <note default-x="273">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-20">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">backward hook</beam>
+        <notations>
+          <tied type="start"/>
+        </notations>
+        <lyric default-y="-97" justify="left" number="1">
+          <syllabic>single</syllabic>
+          <text>watch</text>
+          <extend/>
+        </lyric>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="17" width="247">
+      <note default-x="13">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-15">up</stem>
+        <beam number="1">begin</beam>
+        <beam number="2">forward hook</beam>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+      <note default-x="37">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem default-y="-16">up</stem>
+        <beam number="1">continue</beam>
+        <lyric default-y="-97" number="1">
+          <syllabic>single</syllabic>
+          <text>it</text>
+        </lyric>
+      </note>
+      <note default-x="70">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <tie type="start"/>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem default-y="-17.5">up</stem>
+        <beam number="1">end</beam>
+        <beam number="2">backward hook</beam>
+        <notations>
+          <tied type="start"/>
+        </notations>
+        <lyric default-y="-97" justify="left" number="1">
+          <syllabic>single</syllabic>
+          <text>fall</text>
+          <extend/>
+        </lyric>
+      </note>
+      <note default-x="120">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>12</duration>
+        <tie type="stop"/>
+        <voice>1</voice>
+        <type>half</type>
+        <dot/>
+        <stem default-y="-19">up</stem>
+        <notations>
+          <tied type="stop"/>
+        </notations>
+      </note>
+    </measure>
+  </part>
+  <!--=========================================================-->
+  <part id="P2">
+    <measure number="1" width="268">
+      <print>
+        <system-layout>
+          <top-system-distance>211</top-system-distance>
+        </system-layout>
+        <measure-numbering>none</measure-numbering>
+      </print>
+      <attributes>
+        <divisions>4</divisions>
+        <key print-object="no">
+          <fifths>6</fifths>
+          <mode>major</mode>
+        </key>
+        <clef>
+          <sign>TAB</sign>
+          <line>5</line>
+        </clef>
+        <staff-details>
+          <staff-lines>6</staff-lines>
+          <staff-tuning line="1">
+            <tuning-step>D</tuning-step>
+            <tuning-octave>2</tuning-octave>
+          </staff-tuning>
+          <staff-tuning line="2">
+            <tuning-step>A</tuning-step>
+            <tuning-octave>2</tuning-octave>
+          </staff-tuning>
+          <staff-tuning line="3">
+            <tuning-step>D</tuning-step>
+            <tuning-octave>3</tuning-octave>
+          </staff-tuning>
+          <staff-tuning line="4">
+            <tuning-step>G</tuning-step>
+            <tuning-octave>3</tuning-octave>
+          </staff-tuning>
+          <staff-tuning line="5">
+            <tuning-step>B</tuning-step>
+            <tuning-octave>3</tuning-octave>
+          </staff-tuning>
+          <staff-tuning line="6">
+            <tuning-step>D</tuning-step>
+            <tuning-octave>4</tuning-octave>
+          </staff-tuning>
+          <capo>4</capo>
+          <staff-size>183</staff-size>
+        </staff-details>
+      </attributes>
+      <sound tempo="84"/>
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>B</root-step>
+        </root>
+        <kind halign="left" text="Maj7">major-seventh</kind>
+        <bass>
+          <bass-step>D</bass-step>
+          <bass-alter>1</bass-alter>
+        </bass>
+      </harmony>
+      <direction placement="above">
+        <direction-type>
+          <words default-y="72" relative-x="-22">Tuning D-A-D-G-B-D, Capo 4th fret</words>
+        </direction-type>
+      </direction>
+      <note default-x="41">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="58">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="86">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="114">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="131" print-dot="no">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="168">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="196">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="213">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="230" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="2" width="214">
+      <note default-x="11">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="26">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="52">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="76">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="91" print-dot="no">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="125">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="149">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="165">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="181" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="3" width="218">
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>B</root-step>
+        </root>
+        <kind halign="left" text="Maj7">major-seventh</kind>
+      </harmony>
+      <note default-x="12" print-dot="no">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="12" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="11" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="11" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="50" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="49" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="88" print-dot="no">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="88" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="86" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="87" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="125" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="125" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="163">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="163">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="162">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="162">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="180" print-dot="no">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="4" width="284">
+      <note default-x="12" print-dot="no">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="12" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="11" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="11" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="58" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="58" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="105">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="105">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="103">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="125">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="161">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="196">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="216">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <pull-off number="1" type="start">P</pull-off>
+            <string>5</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="237" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <pull-off number="1" type="stop"/>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="5" width="206">
+      <print new-system="yes">
+        <system-layout>
+          <system-distance>83</system-distance>
+        </system-layout>
+      </print>
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>G</root-step>
+          <root-alter>1</root-alter>
+        </root>
+        <kind halign="left" text="m9">minor-ninth</kind>
+      </harmony>
+      <note default-x="11">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="26">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="51" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="51" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="51" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="51" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="83" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="83" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="84" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="84" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="149">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="149">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="150">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="150">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="165">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="165">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="165">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="165">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="189">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="6" width="206">
+      <note default-x="12">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="27">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="51" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="51" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="51" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="84" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="84" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="84" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="84" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="117" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="150">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="150">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="150">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="150">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="165">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="166">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="166">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="166">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="190">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="7" width="190">
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>F</root-step>
+          <root-alter>1</root-alter>
+        </root>
+        <kind halign="left" text="">major</kind>
+      </harmony>
+      <note default-x="12" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="12" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="44" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>C</root-step>
+          <root-alter>1</root-alter>
+        </root>
+        <kind halign="left" text="7sus4">suspended-fourth</kind>
+        <degree print-object="no">
+          <degree-value>7</degree-value>
+          <degree-alter>0</degree-alter>
+          <degree-type>add</degree-type>
+        </degree>
+      </harmony>
+      <note default-x="77" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="76" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="77" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="109" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="142">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="142">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="142">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="157" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="8" width="190">
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>F</root-step>
+          <root-alter>1</root-alter>
+        </root>
+        <kind halign="left" text="">major</kind>
+      </harmony>
+      <note default-x="11" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="11" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="44" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>C</root-step>
+          <root-alter>1</root-alter>
+        </root>
+        <kind halign="left" text="7sus4">suspended-fourth</kind>
+        <degree print-object="no">
+          <degree-value>7</degree-value>
+          <degree-alter>0</degree-alter>
+          <degree-type>add</degree-type>
+        </degree>
+      </harmony>
+      <note default-x="77" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="76" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="77" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="109" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="142">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="142">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="142">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="157" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="9" width="191">
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>F</root-step>
+          <root-alter>1</root-alter>
+        </root>
+        <kind halign="left" text="">major</kind>
+      </harmony>
+      <note default-x="11" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="11" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="44" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <harmony default-y="40" font-size="15.4">
+        <root>
+          <root-step>C</root-step>
+          <root-alter>1</root-alter>
+        </root>
+        <kind halign="left" text="7sus4">suspended-fourth</kind>
+        <degree print-object="no">
+          <degree-value>7</degree-value>
+          <degree-alter>0</degree-alter>
+          <degree-type>add</degree-type>
+        </degree>
+      </harmony>
+      <note default-x="77" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="77" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="77" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="109" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="110" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="143">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="142">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="143">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="157" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="10" width="313">
+      <print new-system="yes"/>
+      <note default-x="143" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="143" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="170" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="198" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="198" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="198" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="230" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="230" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="231" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="230" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="258">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="258">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="258">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="272" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="11" width="357">
+      <note default-x="17">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="53">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="94">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="135">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="154" print-dot="no">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="247">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="278">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="293">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="313" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="12" width="313">
+      <note default-x="26">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="39">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="64">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="111">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="139" print-dot="no">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="195">
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="214">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="228">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="243" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="13" width="570">
+      <print new-system="yes"/>
+      <note default-x="144" print-dot="no">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="144" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="143" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="143" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="220" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="220" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="284" print-dot="no">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="284" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="282" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="283" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="395" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="395" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="441">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="441">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="440">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="440">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="463" print-dot="no">
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="14" width="413">
+      <note default-x="17" print-dot="no">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="17" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="16" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="16" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="115" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="115" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="163">
+        <pitch>
+          <step>B</step>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="163">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="162">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="181">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="235">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="280">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>5</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="306">
+        <pitch>
+          <step>E</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <pull-off number="1" type="start">P</pull-off>
+            <string>5</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="335" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <pull-off number="1" type="stop"/>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="15" width="408">
+      <print new-system="yes"/>
+      <note default-x="147">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="162">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="190" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="190" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="190" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="190" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="269" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="269" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="269" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="269" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="319" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="319" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="319" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="319" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="351">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="351">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="351">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="351">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="367">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="367">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="367">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="367">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="391">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="16" width="328">
+      <note default-x="11">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="26">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="50" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="50" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="50" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="83" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="83" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="83" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="83" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="120" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="121" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="121" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="121" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="186">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="186">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="186">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="186">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="224">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="224">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="224">
+        <chord/>
+        <pitch>
+          <step>D</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="224">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="274">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+    <!--=======================================================-->
+    <measure number="17" width="247">
+      <note default-x="14" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>2</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>6</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="14" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="71" print-dot="no">
+        <pitch>
+          <step>A</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>4</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="138" print-dot="no">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="138" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="138" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="169" print-dot="no">
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="169" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="170" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>2</string>
+            <fret>3</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="169" print-dot="no">
+        <chord/>
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>4</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>1</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="200">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>5</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="200">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>2</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="200">
+        <chord/>
+        <pitch>
+          <step>B</step>
+          <octave>3</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>16th</type>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>3</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+      <note default-x="216" print-dot="no">
+        <pitch>
+          <step>F</step>
+          <alter>1</alter>
+          <octave>3</octave>
+        </pitch>
+        <duration>3</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+        <dot/>
+        <stem>none</stem>
+        <notations>
+          <technical>
+            <string>4</string>
+            <fret>0</fret>
+          </technical>
+        </notations>
+      </note>
+    </measure>
+  </part>
+  <!--=========================================================-->
+</score-partwise>

+ 471 - 0
demo/annotations-ui.css

@@ -0,0 +1,471 @@
+@font-face {
+    font-family: Gonville;
+    src: url("fonts/Gonville-18.woff2") format("woff2"), url("fonts/Gonville-18.woff") format("woff"), url("fonts/Gonville-18.ttf")  format("truetype");
+}
+
+body {
+    --mdc-theme-primary: #eb6201;
+    --mdc-theme-secondary:  #eb6201;
+}
+/* tooltip styles. Unused for now - Perhaps remove if it remains so */
+[data-md-tooltip] {
+position: relative;
+}
+[data-md-tooltip]:before {
+    content: attr(data-md-tooltip);
+    position: absolute;
+    bottom: 8px;
+    left: 50%;
+    padding: 1px 8px;
+    transform: translateX(-50%) scale(0);
+    transition: transform 0.3s ease-in-out;
+    transition-delay: 0.7s;
+    transform-origin: top;
+    background: #616161;
+    color: white;
+    border-radius: 2px;
+    font-size: 12px;
+    font-family: Roboto,sans-serif;
+    font-weight: 400;
+    z-index: 99999;
+}
+.mdc-tab--active[data-md-tooltip]:before {
+    background: var(--mdc-theme-primary);
+}
+[data-md-tooltip]:hover:before {
+transform: translateX(-50%) scale(1); 
+}
+/* POSITIONING */
+
+.left {
+    text-align: left;
+  }
+  
+  .right {
+    text-align: right;
+  }
+  
+  .center {
+    text-align: center;
+    margin-left: auto;
+    margin-right: auto;
+  }
+  
+  .justify {
+    text-align: justify;
+  }
+
+  .d-inline-block{
+      display: inline-block;
+  }
+
+  .d-block{
+      display: block;
+  }
+
+  .d-inline{
+      display: inline;
+  }
+
+  .d-none{
+      display: none;
+  }
+
+  .v-align-middle{
+      vertical-align: middle;
+  }
+
+  .v-align-top{
+      vertical-align: top;
+  }
+
+  .v-align-bottom{
+      vertical-align: bottom;
+  }
+  
+  /* ==== GRID SYSTEM ==== */
+  
+  .container {
+    width: 90%;
+    margin-left: auto;
+    margin-right: auto;
+  }
+  
+  .row {
+    position: relative;
+    width: 100%;
+  }
+  
+  .row [class^="col"] {
+    float: left;
+    margin: 0.5rem 2%;
+    min-height: 0.125rem;
+  }
+
+.col-1 {
+    width: 6.3333%;
+}
+
+.col-2 {
+    width: 14.6666%;
+}
+
+.col-3 {
+    width: 23%;
+}
+
+.col-4 {
+    width: 31.3333%;
+}
+
+.col-5 {
+    width: 39.6666%;
+}
+
+.col-6 {
+    width: 48%;
+}
+
+.col-7 {
+    width: 56.3333%;
+}
+
+.col-8 {
+    width: 64.6666%;
+}
+
+.col-9 {
+    width: 73%;
+}
+
+.col-10 {
+    width: 81.3333%;
+}
+
+.col-11 {
+    width: 89.6666%;
+}
+
+.col-12 {
+    width: 98%;
+}
+
+.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-10, .col-11, .col-12{
+    display: inline-block;
+}
+
+.mdc-touch-target-wrapper{
+    z-index: 99;
+}
+.annotation-ui-container{
+    font-family: 'Roboto', sans-serif;
+}
+
+.toolbar{
+    padding: 8px;
+    border-bottom: solid 1px #888888;
+}
+
+.text-center{
+    text-align: center;
+}
+
+.half-container{
+    display: inline-block;
+    width: 49.2%;
+    vertical-align: middle;
+}
+
+.settings-button-container{
+    position:fixed;
+    bottom: 15px;
+    left: 5px;
+    z-index: 50;
+}
+
+.settings-button-container .mdc-fab{
+    margin-left: 5px;
+    margin-right: 5px;
+}
+
+.control-panel{
+    position:fixed;
+    bottom: 60px;
+    left: 0;
+    padding: 0 5px;
+    width: 100%;
+    overflow: hidden;
+    background: transparent;
+}
+
+.controls-container{
+    width: 350px;
+}
+
+.playback-title-bar{
+    margin-bottom: 8px;
+}
+
+.controls-container .volume-toolbar, .controls-container .metronome-toolbar{
+    padding-left: 10px;
+    padding-right: 10px;
+}
+
+.controls-container .metronome-toolbar{
+    margin-top: 10px;
+}
+
+.controls-container .mdc-button.mdc-button--outlined {
+    height: 28px;
+    padding: 0px;
+}
+
+.controls-container .mdc-button.mdc-button--outlined.mdc-icon-button--on .mdc-button__ripple{
+    background-color: rgba(241, 154, 92, 0.25);
+    transition: background-color 0.5s ease;
+}
+
+.playback-buttons{
+    position: fixed;
+    bottom: 5px;
+    left: calc(50% - 56px);
+}
+
+.playpause-button .pause-icon {
+    display: none;
+}
+
+.playpause-button.playing .pause-icon {
+    display:block;
+}
+
+.playpause-button.playing .play-icon {
+    display:none;
+}
+
+.slider-container{
+    margin-left: 10px;
+}
+
+.annotation-menu{
+    position:fixed;
+    bottom: 60px;
+    left: 5px;
+    width: 375px;
+    max-width: 90%;
+    overflow-x: hidden;
+    background-color: #FFFFFF;
+}
+
+.preview-container{
+    position: fixed;
+    bottom: 60px;
+    left: 385px;
+    width: 90px;
+    height: 90px;
+    max-width: 10%;
+    background-color: #FFFFFF;
+}
+
+.preview-container > #render-element{
+    text-align: center;
+    width: 100%;
+    line-height: 1.5;
+    margin-top: 38px;
+    max-height: 100%;
+}
+
+.hide {
+    visibility: hidden !important;
+    display: none !important;
+    transition: display 0.5s ease;
+    transition: visibility 0.5s ease;
+}
+
+.comment-input-dragger, .symbol-placer-dragger{
+    font-size: 1.25rem;
+    cursor: pointer;
+    z-index: 999;
+    vertical-align: top;
+}
+
+.comment-input {
+    background-color: rgba(255, 255, 128, .4);
+    border: dotted 1px blue;
+    resize: none;
+    overflow: hidden;
+    font-family: Times New Roman;
+    line-height: 1.1;
+    z-index: 1000;
+}
+
+.mdc-tab-scroller__scroll-content{
+    overflow-y: hidden;
+}
+
+#add-symbol-mode{
+    overflow-y: hidden;
+}
+
+.gonville-icon{
+    font-family: Gonville;
+    max-height: 100%;
+    margin-top: -18px;
+}
+/*Special rules for custom SVG icon*/
+.symbol-icon-group{
+    fill: var(--mdc-theme-text-secondary-on-background);
+    stroke: var(--mdc-theme-text-secondary-on-background);
+}
+
+.mdc-tab--active .symbol-icon-group{
+    fill: var(--mdc-theme-primary);
+    stroke: var(--mdc-theme-primary);
+}
+
+.gonville-icon div span{
+    padding: 0px 2px;
+}
+
+.symbol-render{
+    font-family: Gonville;
+    display: inline-block;
+    z-index: 1000;
+    line-height: 1;
+}
+
+.symbol-render-measure{
+    position: absolute;
+    visibility: hidden;
+    font-family: Gonville;
+    display: inline-block;
+    z-index: -99999;
+    line-height: 1;
+}
+
+.comment-input:focus {
+    border-width: 2px;
+    outline: none;
+    outline-offset: 0px;
+}
+
+#text-measure-element{
+    position: absolute;
+    visibility: hidden;
+    line-height: 1;
+    z-index: -99999;
+}
+
+#dragger-measure-element{
+    font-size: 1.25rem;
+    position: absolute;
+    visibility: hidden;
+    z-index: -99999;
+}
+
+#text-measure-element.symbol{
+    font-family: Gonville;
+}
+
+.color-swatch-list {
+    display: inline-block;
+    overflow-x: hidden;
+    white-space: nowrap;
+    margin: 0;
+    font: inherit;
+    vertical-align: baseline;
+    list-style: none;
+}
+
+.color-swatch-list .color-swatch{
+    display: inline-block;
+    border: 0;
+    vertical-align: baseline;
+    color: #fff;
+    cursor: pointer;
+    outline: 0;
+    position: relative;
+    width: 28px;
+    height: 28px;
+    margin: 2px;
+    list-style-type: none;
+    transition: border-width 0.6s linear;
+}
+
+.color-swatch-list .color-swatch.selected{
+    outline: 2px solid;
+}
+
+.color-swatch-list .color-swatch.selected{
+    outline-color: #000000;
+}
+
+.color-swatch-list .color-swatch.selected.negative{
+    outline-color: #666666;
+}
+
+.symbol-swatch-list .symbol-swatch.selected{
+    background-color: rgba(0, 0, 0, 0.3);
+    border-radius: 80px;
+}
+
+.symbol-swatch-list .symbol-swatch, .preview-container > #render-element, .gonville-icons{
+    font-family: Gonville;
+}
+
+.layer-list-item{
+    border-bottom: 1px solid #666666;
+    font-weight: bold;
+    color: #333333;
+    cursor: pointer;
+    transition: background-color 0.5s ease;
+}
+
+.layer-list-item .text-content{
+    padding-top: 15px;
+    padding-bottom: 15px;
+}
+
+.layer-list-item:hover{
+    background-color: rgba(0,0,0,0.05);
+}
+
+.layer-list-item.selected {
+    background-color: #eb620160;
+}
+
+.layer-list-item .mdc-icon-button, .add-layer-controls-container .mdc-icon-button{
+    float: right;
+}
+
+.layer-list-item .list-buttons {
+    z-index: 50;
+}
+
+.splide{
+    padding: 2rem 3rem;
+}
+
+.splide.vertical{
+    padding: 3.5rem 2rem;
+}
+
+.splide.splide.vertical .splide__list{
+    border-top: 1px solid #666666;
+}
+
+.splide.vertical .splide__list{
+    width: 100%;
+}
+
+.splide__arrow{
+    z-index: 20;
+}
+
+.splide__pagination__page{
+    background-color: #aaa;
+}
+
+.splide__pagination__page.is-active {
+    background-color: #ccc;
+}

+ 41 - 0
demo/demo.css

@@ -0,0 +1,41 @@
+p {
+  margin: 0px 8px 8px 8px;
+}
+
+/* the select widths are not used for some reason, even if we don't set the style in index.html */
+select {
+  width: 100px;
+  margin: 2px 8px 8px 8px;
+}
+
+#selectSample {
+  width: 320px;
+}
+
+#selectBounding {
+  width: 80%;
+}
+
+.bignum {
+  width: 1em;
+  text-align: center;
+  font-size: 4em;
+  color: white;
+  background-color: black;
+  padding: 0.3em;
+  border-right: 0.3em solid white;
+}
+
+#error-tr {
+  background-color: red;
+  text-align: center;
+}
+
+#error-td {
+  padding: 1em;
+  color: white;
+}
+
+table {
+    width: 100%;
+}

+ 117 - 0
demo/embedded_demo.html

@@ -0,0 +1,117 @@
+<!doctype html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <title>OpenSheetMusicDisplay as an embedded iframe</title>
+    <meta name="description" content="A showcase for OpenSheetMusicDisplay.">
+    <meta name="author" content="OpenSheetMusicDisplay contributors">
+
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.0/semantic.min.js"
+        type="text/javascript"></script>
+    <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.0/semantic.css" media="all" rel="stylesheet" />
+    <link rel="icon" href="./favicon.ico?" type="image/x-icon" />
+</head>
+
+<body>
+    <br>
+    <div style="text-align: center;width: 60%;margin:0 auto">
+        <h1 class="ui centered header" id="header">
+            <img src="./favicon.ico?" class="ui image">
+
+        </h1>
+        <h2>
+            OpenSheetMusicDisplay as an embedded iframe
+        </h2>
+    </div>
+    <div style="padding: 40px;margin:0 auto">
+        <h3>
+            Use parameters:
+        </h3>
+        <p>
+            <table class="ui table celled ">
+                <tr>
+                    <th>Parameter</th>
+                    <th>Values</th>
+                    <th>Default</th>
+                    <th>Description</th>
+                </tr>
+                <tr>
+                    <td><b>embedded</b></td>
+                    <td></td>
+                    <td></td>
+                    <td>Activates the embedded mode: controls are hidden (unless other parameters specified)
+                    </td>
+                </tr>
+                <tr>
+                    <td>showControls</td>
+                    <td>"0" and "1"</td>
+                    <td>"0" = OFF</td>
+                    <td>If active, the controls of OSMD are shown like usually.</td>
+                </tr>
+                <tr>
+                    <td>showZoomControl</td>
+                    <td>"0" and "1"</td>
+                    <td>"0" = OFF</td>
+                    <td>If showControls == 0 and showZoomControl == 1, a small zoomControl widget will be displayed to safe space
+                    </td>
+                </tr>
+                <tr>
+                    <td>showHeader</td>
+                    <td>"0" and "1"</td>
+                    <td>"0" = OFF</td>
+                    <td>If activated, the OSMD title will be rendered on top of the sheet</td>
+                </tr>
+                <tr>
+                    <td>zoom</td>
+                    <td>floating number between 0.1 and 5.0</td>
+                    <td>1.0</td>
+                    <td>If given, the OSMD zoom level will be set at loading time</td>
+                </tr>
+                <tr>
+                    <td>overflow</td>
+                    <td>"hidden" , "auto", "scroll", "visible"</td>
+                    <td>"auto"</td>
+                    <td>If given, this attribute will refresh the state of the css attribute overflow to control the
+                        scrollbar.
+                    </td>
+                </tr>
+                <tr>
+                    <td>openUrl</td>
+                    <td>valid URL pointing to a valid musicxml file</td>
+                    <td>"auto"</td>
+                    <td>If given, this attribute open the given musicxml file and display it.
+                        <p>
+                            <h5>Important:</h5>
+                            For now, the resources must be hosted on the same server, otherwise it will be blocked by
+                            <a href="https://de.wikipedia.org/wiki/Cross-Origin_Resource_Sharing">CORS policy</a>.
+                        </p>
+                        <p>
+                            <h5>Examples:</h5>
+                            <a
+                                href="http://localhost:8000/?embedded&openUrl=http://localhost:8000/BrookeWestSample.musicxml">
+                                http://localhost:8000/?embedded&openUrl=http://localhost:8000/BrookeWestSample.musicxml</a>
+                                <br>
+                            <a
+                                href="http://localhost:8000/?embedded&openUrl=https://wpmedia.musicxml.com/wp-content/uploads/2017/12/MahlFaGe4Sample.mxl">http://localhost:8000/?embedded&openUrl=https://wpmedia.musicxml.com/wp-content/uploads/2017/12/MahlFaGe4Sample.mxl</a>
+
+                        </p>
+                    </td>
+                </tr>
+            </table>
+    </div>
+    <div>
+        <center>
+            <h4>Example: http://localhost:8000/?embedded&showZoomControl=1&zoom=0.5</h4>
+            <iframe src="http://localhost:8000/?embedded&showZoomControl=1&zoom=0.5" width="800" height="1500"
+                frameborder="1"></iframe>
+        </center>
+    </div>
+
+
+</body>
+
+</html>

BIN
demo/favicon.ico


BIN
demo/fonts/Gonville-18.ttf


BIN
demo/fonts/Gonville-18.woff


BIN
demo/fonts/Gonville-18.woff2


+ 210 - 0
demo/index.html

@@ -0,0 +1,210 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <title><%= htmlWebpackPlugin.options.title %></title>
+    <meta name="description" content="A showcase for OpenSheetMusicDisplay.">
+    <meta name="author" content="OpenSheetMusicDisplay contributors">
+    <!-- Demo index.js file is included automatically by webpack during build -->
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>    
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.0/semantic.min.js" type="text/javascript"></script>    
+    <link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.0/semantic.css" media="all" rel="stylesheet"/>
+    <link href="https://unpkg.com/material-components-web@7.0.0/dist/material-components-web.min.css" rel="stylesheet">
+    <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet"> 
+    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/splide@latest/dist/css/splide.min.css">
+    <link href="annotations-ui.css" media="all" rel="stylesheet"/>
+    <link rel="icon" href="./favicon.ico?" type="image/x-icon"/>
+</head>
+<body>
+<h1 class="ui centered header" id="header" style="opacity: 0.0">
+    <img src="./favicon.ico?" class="ui image">
+    <%= htmlWebpackPlugin.options.title %>
+</h1>
+<div class="ui four column grid container" id="divControls" style="visibility: hidden; opacity: 0.0">
+    <div class="column">
+        <h3 class="ui header">Select a sample:</h3>
+        <select class="ui selection dropdown" id="selectSample" style="width:320px; height:38%; visibility: hidden"></select>
+    </div>
+    <div class="column" id="backend-select-div" style="visibility: hidden">
+        <h3 class="ui header">Render backend:</h3>
+        <select class="ui selection dropdown" id="backend-select" value="svg" style="height:38%; visibility: hidden;">
+            <option value="svg">SVG</option>
+            <option value="canvas">Canvas</option>>
+        </select>
+    </div>
+    <div class="column">
+        <h3 class="ui header">Cursor controls:</h3>
+        <div>
+            <div class="ui vertical buttons">
+                <div class="ui animated fade button" id="show-cursor-btn">
+                    <div class="visible content">Show</div>
+                    <div class="hidden content">
+                        <i class="eye icon"></i>
+                    </div>
+                </div>
+                <div class="ui animated fade button" id="hide-cursor-btn">
+                    <div class="visible content">Hide</div>
+                    <div class="hidden content">
+                        <i class="eye slash icon"></i>
+                    </div>
+                </div>
+            </div>
+            <div class="ui vertical buttons">
+                <div class="ui animated fade button" id="next-cursor-btn">
+                    <div class="visible content">Next</div>
+                    <div class="hidden content">
+                        <i class="arrow right icon"></i>
+                    </div>
+                </div>
+                <div class="ui animated fade button" id="reset-cursor-btn">
+                    <div class="visible content">Reset</div>
+                    <div class="hidden content">
+                        <i class="undo icon"></i>
+                    </div>
+                </div>
+            </div>
+            <div class="item">
+                <div class="ui toggle checkbox">
+                    <input type="checkbox" name="public" id="follow-cursor-checkbox" checked="true">
+                    <label>Follow Cursor</label>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="column" id="zoomControls">
+        <h3 class="ui header">Zoom controls:</h3>
+        <div class="ui buttons" id="zoomControlsButtons">
+            <div class="ui button" id="zoom-in-btn">
+                <i class="search plus icon"></i>
+            </div>
+            <div class="ui button" id="zoom-out-btn">
+                <i class="search minus icon"></i>
+            </div>
+        </div>
+        <h4 class="ui header" id="zoom-str">???</h4>
+    </div>
+    <div class="column">
+        <h3 class="ui header">Show bounding box for:</h3>
+        <select class="ui selection dropdown" id="selectBounding" style="visibility: hidden;">
+            <option value="none">None</option>
+            <option value="all">All</option>
+            <option value="VexFlowMeasure">Measures</option>
+            <option value="VexFlowGraphicalNote">GraphicalNotes</option>
+            <option value="VexFlowVoiceEntry">VoiceEntries</option>
+            <option value="VexFlowStaffEntry">StaffEntries</option>
+            <option value="GraphicalLabel">Labels</option>
+            <option value="VexFlowStaffLine">StaffLines</option>
+            <option value="SystemLine">SystemLines</option>
+            <option value="StaffLineActivitySymbol">ActivitySymbols</option>
+            <option value="VexFlowContinuousDynamicExpression">DynamicExpressions</option>
+        </select>
+    </div>
+    <div class="column">
+        <h3 class="ui header">Show debug information:</h3>
+        <div class="ui relaxed list">
+            <div class="item">
+                <div class="ui toggle checkbox">
+                    <input type="checkbox" name="public" id="skylineDebug">
+                    <label>Skyline</label>
+                </div>
+            </div>
+            <div class="item">
+                <div class="ui toggle checkbox">
+                    <input type="checkbox" name="public" id="bottomlineDebug">
+                    <label>Bottomline</label>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="column">
+        <h3 class="ui header">Debug controls:</h3>
+        <div>
+            <div class="ui vertical buttons">
+                <div class="ui button" id="debug-re-render-btn">Re-render</div>
+
+            </div>
+            <div class="ui vertical buttons">
+                <div class="ui button" id="debug-clear-btn">Clear</div>
+            </div>
+        </div>
+    </div>
+    <div class="column">
+        <h3 class="ui header">Page size:</h3>
+        <select class="ui selection dropdown" id="selectPageSize"  style="visibility: hidden;">
+            <option value="endless">endless</option>
+            <option value="A3 P">A3 Portrait</option>
+            <option value="A3 L">A3 Landscape</option>
+            <option value="A4 P">A4 Portrait</option>
+            <option value="A4 L">A4 Landscape</option>
+            <option value="A5 P">A5 Portrait</option>
+            <option value="A5 L">A5 Landscape</option>
+            <option value="Letter P">Letter Portrait</option>
+            <option value="Letter L">Letter Landscape</option>
+        </select>
+        <div class="ui button" id="print-pdf-btn">Print to Pdf</div>
+    </div>
+    <div class="column">
+        <h3 class="ui header">Transpose by Semitone(s):</h3>
+        <div class="ui action input">
+            <input type="number" id="transpose" value="0"/>
+            <button class="ui button" id="transpose-btn">Transpose</button>
+        </div>
+    </div>
+</div>
+<div id="optionalControls" style="opacity: 0.0; width: 95%; display: block">
+    <div class="ui three column grid container" style="padding: 10px; margin-right: auto; margin-left: auto" id="optionalControlsColumnContainer">
+        <div class="column" id="zoomControlsButtons-optional-column" style="min-width: 30%; opacity: 0.0">
+            <div class="ui buttons" id="zoomControlsButtons-optional">
+                <div class="ui button" id="zoom-in-btn-optional">
+                    <i class="search plus icon"></i>
+                </div>
+                <div class="ui button" id="zoom-out-btn-optional">
+                    <i class="search minus icon"></i>
+                </div>
+            </div>
+            <h4 id="zoom-str-optional">???</h4>
+        </div>
+        <div class="column" id="print-pdf-btn-optional-column" style="opacity: 0.0; max-width: 25%;">
+            <div class="ui button" id="print-pdf-btn-optional">Print to Pdf</div>
+        </div>
+        <div class="column" id="selectPageSize-optional-column" style="opacity: 0.0; min-width: 35%">
+            <div class="ui two column grid container">
+            <div class="column" style="margin-top: 8px">
+            <h3>Format:</h3>
+            </div>
+            <div class="column">
+            <select class="ui selection dropdown" id="selectPageSize-optional">
+                <option value="endless">endless</option>
+                <option value="A3 P">A3 Portrait</option>
+                <option value="A3 L">A3 Landscape</option>
+                <option value="A4 P">A4 Portrait</option>
+                <option value="A4 L">A4 Landscape</option>
+                <option value="A5 P">A5 Portrait</option>
+                <option value="A5 L">A5 Landscape</option>
+                <option value="Letter P">Letter Portrait</option>
+                <option value="Letter L">Letter Landscape</option>
+            </select>
+            </div>
+            </div>
+        </div>
+    </div>
+</div>
+<div>
+    <table cellspacing="0" style="max-width:700px;">
+        <tr id="error-tr">
+            <td></td>
+            <td id="error-td"></td>
+        </tr>
+    </table>
+</div>
+<div class="settings-button-container">
+    <button class="mdc-fab mdc-fab--mini playback-settings-button" id="playback-settings-button" aria-label="Playback Settings">
+        <div class="mdc-fab__ripple"></div>
+        <span class="mdc-fab__icon material-icons">settings</span>
+    </button>
+</div>
+</body>
+</html>

+ 1002 - 0
demo/index.js

@@ -0,0 +1,1002 @@
+import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMusicDisplay';
+import { BackendType } from '../src/OpenSheetMusicDisplay/OSMDOptions';
+import { PlaybackManager, LinearTimingSource, BasicAudioPlayer, ControlPanel } from '../src/Playback';
+import * as jsPDF  from '../node_modules/jspdf-yworks/dist/jspdf.min';
+import * as svg2pdf from '../node_modules/svg2pdf.js/dist/svg2pdf.min';
+import { TransposeCalculator } from '../src/Plugins/Transpose/TransposeCalculator';
+
+/*jslint browser:true */
+(function () {
+    "use strict";
+    var openSheetMusicDisplay;
+    var sampleFolder = process.env.STATIC_FILES_SUBFOLDER ? process.env.STATIC_FILES_SUBFOLDER + "/" : "",
+        samples = {
+            "Beethoven, L.v. - An die ferne Geliebte": "Beethoven_AnDieFerneGeliebte.xml",
+            "Clementi, M. - Sonatina Op.36 No.1 Pt.1": "MuzioClementi_SonatinaOpus36No1_Part1.xml",
+            "Clementi, M. - Sonatina Op.36 No.1 Pt.2": "MuzioClementi_SonatinaOpus36No1_Part2.xml",
+            "Clementi, M. - Sonatina Op.36 No.3 Pt.1": "MuzioClementi_SonatinaOpus36No3_Part1.xml",
+            "Clementi, M. - Sonatina Op.36 No.3 Pt.2": "MuzioClementi_SonatinaOpus36No3_Part2.xml",
+            "Bach, J.S. - Praeludium in C-Dur BWV846 1": "JohannSebastianBach_PraeludiumInCDur_BWV846_1.xml",
+            "Bach, J.S. - Air": "JohannSebastianBach_Air.xml",
+            "Gounod, C. - Méditation": "CharlesGounod_Meditation.xml",
+            "Haydn, J. - Concertante Cello": "JosephHaydn_ConcertanteCello.xml",
+            "Joplin, S. - Elite Syncopations": "ScottJoplin_EliteSyncopations.xml",
+            "Joplin, S. - The Entertainer": "ScottJoplin_The_Entertainer.xml",
+            "Mozart, W.A. - An Chloe": "Mozart_AnChloe.xml",
+            "Mozart, W.A. - Das Veilchen": "Mozart_DasVeilchen.xml",
+            "Mozart, W.A. - Clarinet Quintet (Excerpt)": "Mozart_Clarinet_Quintet_Excerpt.mxl",
+            "Mozart, W.A. - String Quartet in G, K. 387, 1st Mvmt Excerpt": "Mozart_String_Quartet_in_G_K._387_1st_Mvmnt_excerpt.musicxml",
+            "Mozart/Holzer - Land der Berge (national anthem of Austria)": "Land_der_Berge.musicxml",
+            "OSMD Function Test - All": "OSMD_function_test_all.xml",
+            "OSMD Function Test - Accidentals": "OSMD_function_test_accidentals.musicxml",
+            "OSMD Function Test - Autobeam": "OSMD_function_test_autobeam.musicxml",
+            "OSMD Function Test - Auto-/Custom-Coloring": "OSMD_function_test_auto-custom-coloring-entchen.musicxml",
+            "OSMD Function Test - Bar lines": "OSMD_function_test_bar_lines.musicxml",
+            "OSMD Function Test - Chord Symbols": "OSMD_function_test_chord_symbols.musicxml",
+            "OSMD Function Test - Chord Spacing": "OSMD_function_test_chord_spacing.mxl",
+            "OSMD Function Test - Chord Symbols - Various Chords": "OSMD_function_test_chord_tests_various.musicxml",
+            "OSMD Function Test - Chord Symbols - BrookeWestSample": "BrookeWestSample.mxl",
+            "OSMD Function Test - Color (from XML)": "OSMD_function_test_color.musicxml",
+            "OSMD Function Test - Container height (compacttight mode)": "OSMD_Function_Test_Container_height.musicxml",
+            "OSMD Function Test - Drumset": "OSMD_function_test_drumset.musicxml",
+            "OSMD Function Test - Drums on one Line": "OSMD_Function_Test_Drums_one_line_snare_plus_piano.musicxml", 
+            "OSMD Function Test - Expressions": "OSMD_function_test_expressions.musicxml",
+            "OSMD Function Test - Expressions Overlap": "OSMD_function_test_expressions_overlap.musicxml",
+            "OSMD Function Test - Grace Notes": "OSMD_function_test_GraceNotes.xml",
+            "OSMD Function Test - Metronome Marks": "OSMD_function_test_metronome_marks.mxl",
+            "OSMD Function Test - Multiple Rest Measures": "OSMD_function_test_multiple_rest_measures.musicxml",
+            "OSMD Function Test - Invisible Notes": "OSMD_function_test_invisible_notes.musicxml",
+            "OSMD Function Test - Notehead Shapes": "OSMD_function_test_noteheadShapes.musicxml",
+            "OSMD Function Test - Ornaments": "OSMD_function_test_Ornaments.xml",
+            "OSMD Function Test - Selecting Measures To Draw": "OSMD_function_test_measuresToDraw_Beethoven_AnDieFerneGeliebte.xml",
+            "OSMD Function Test - System and Page Breaks": "OSMD_Function_Test_System_and_Page_Breaks_4_pages.mxl",
+            "OSMD Function Test - Tabulature": "OSMD_Function_Test_Tabulature_hayden_study_1.mxl",
+            "OSMD Function Test - Tabulature MultiBends": "OSMD_Function_Test_Tablature_Multibends.musicxml",
+            "OSMD Function Test - Tabulature All Effects": "OSMD_Function_Test_Tablature_Alleffects.musicxml",
+            "OSMD Function Test - Tremolo": "OSMD_Function_Test_Tremolo_2bars.musicxml",
+            "OSMD Function Test - Labels": "OSMD_Function_Test_Labels.musicxml",
+            "OSMD Function Test - High Slur Test": "test_slurs_highNotes.musicxml",
+            "OSMD Function Test - Auto Multirest Measures Single Staff": "Test_Auto_Multirest_1.musicxml",
+            "OSMD Function Test - Auto Multirest Measures Multiple Staves": "Test_Auto_Multirest_2.musicxml",
+            "OSMD Function Test - String number collisions": "test_string_number_collisions.musicxml",
+            "Schubert, F. - An Die Musik": "Schubert_An_die_Musik.xml",
+            "Actor, L. - Prelude (Large Sample, loading time)": "ActorPreludeSample.xml",
+            "Actor, L. - Prelude (Large, No Print Part Names)": "ActorPreludeSample_PartName.xml",
+            "Anonymous - Saltarello": "Saltarello.mxl",
+            "Debussy, C. - Mandoline": "Debussy_Mandoline.xml",
+            "Levasseur, F. - Parlez Mois": "Parlez-moi.mxl",
+            "Schumann, R. - Dichterliebe": "Dichterliebe01.xml",
+            "Telemann, G.P. - Sonate-Nr.1.1-Dolce": "TelemannWV40.102_Sonate-Nr.1.1-Dolce.xml",
+            "Telemann, G.P. - Sonate-Nr.1.2-Allegro": "TelemannWV40.102_Sonate-Nr.1.2-Allegro-F-Dur.xml",
+        },
+        comments = {
+            "Beethoven_AnDieFerneGeliebte.xml": ["Beethoven_AnDieFerneGeliebte_comments.xml", "Beethoven_AnDieFerneGeliebte_comments_2.xml"]
+        },
+        zoom = 1.0,
+        // HTML Elements in the page
+        divControls,
+        zoomControls,
+        header,
+        err,
+        error_tr,
+        canvas,
+        selectSample,
+        selectBounding,
+        skylineDebug,
+        bottomlineDebug,
+        zoomIns,
+        zoomOuts,
+        zoomDivs,
+        custom,
+        nextCursorBtn,
+        resetCursorBtn,
+        followCursorCheckbox,
+        showCursorBtn,
+        hideCursorBtn,
+        backendSelect,
+        backendSelectDiv,
+        debugReRenderBtn,
+        debugClearBtn,
+        selectPageSizes,
+        printPdfBtns,
+        transpose,
+        transposeBtn,
+        playbackControlsButton,
+        playbackControl;
+    
+    // manage option setting and resetting for specific samples, e.g. in the autobeam sample autobeam is set to true, otherwise reset to previous state
+    // TODO design a more elegant option state saving & restoring system, though that requires saving the options state in OSMD
+    var minMeasureToDrawStashed = 1;
+    var maxMeasureToDrawStashed = Number.MAX_SAFE_INTEGER;
+    var measureToDrawRangeNeedsReset = false;
+    var drawingParametersStashed = "default";
+    var drawingParametersNeedsReset = false;
+    var autobeamOptionNeedsReset = false;
+    var autobeamOptionStashedValue = false;
+    var autoCustomColoringOptionNeedsReset = false;
+    var autoCustomColoringOptionStashedValue = false;
+    var drawPartNamesOptionStashedValue = true;
+    var drawPartAbbreviationsStashedValue = true;
+    var drawPartNamesOptionNeedsReset = false;
+    var pageBreaksOptionStashedValue = false;
+    var pageBreaksOptionNeedsReset = false;
+    var systemBreaksOptionStashedValue = false; // reset handled by pageBreaksOptionNeedsReset
+
+    var showControls = true;
+    var showExportPdfControl = false;
+    var showPageFormatControl = false;
+    var showZoomControl = true;
+    var showHeader = true;
+    var showDebugControls = false;
+
+    if (process.env.OSMD_DEMO_TITLE) {
+        document.title = process.env.OSMD_DEMO_TITLE;
+    }
+
+    // Initialization code
+    function init() {
+        var name, option;
+
+        // Handle window parameter
+        var paramEmbedded = findGetParameter('embedded');
+        var paramShowControls = findGetParameter('showControls');
+        var paramShowPageFormatControl = findGetParameter('showPageFormatControl');
+        var paramShowExportPdfControl = findGetParameter('showExportPdfControl');
+        var paramShowZoomControl = findGetParameter('showZoomControl');
+        var paramShowHeader = findGetParameter('showHeader');
+        var paramZoom = findGetParameter('zoom');
+        var paramOverflow = findGetParameter('overflow');
+        var paramOpenUrl = findGetParameter('openUrl');
+        var paramDebugControls = findGetParameter('debugControls');
+
+        var paramCompactMode = findGetParameter('compactMode');
+        var paramMeasureRangeStart = findGetParameter('measureRangeStart');
+        var paramMeasureRangeEnd = findGetParameter('measureRangeEnd');
+        var paramPageFormat = findGetParameter('pageFormat');
+        var paramPageBackgroundColor = findGetParameter('pageBackgroundColor');
+        var paramBackendType = findGetParameter('backendType');
+        var paramPageWidth = findGetParameter('pageWidth');
+        var paramPageHeight = findGetParameter('pageHeight');
+
+        var paramHorizontalScrolling = findGetParameter('horizontalScrolling');
+        var paramSingleHorizontalStaffline = findGetParameter('singleHorizontalStaffline');
+
+        showHeader = (paramShowHeader !== '0');
+        showControls = false;
+        if (paramEmbedded) {
+            showControls = paramShowControls !== '0';
+            showZoomControl = paramShowZoomControl !== '0';
+            showPageFormatControl = paramShowPageFormatControl !== '0';
+            showExportPdfControl = paramShowExportPdfControl !== '0';
+        }
+
+        if (paramZoom) {
+            if (paramZoom > 0.1 && paramZoom < 5.0) {
+                zoom = paramZoom;
+            }
+        }
+        if (paramOverflow && typeof paramOverflow === 'string') {
+            if (paramOverflow === 'hidden' || paramOverflow === 'auto' || paramOverflow === 'scroll' || paramOverflow === 'visible') {
+                document.body.style.overflow = paramOverflow;
+            }
+        }
+        
+        var compactMode = paramCompactMode && paramCompactMode !== '0';
+        var measureRangeStart = paramMeasureRangeStart ? Number.parseInt(paramMeasureRangeStart) : 0;
+        var measureRangeEnd = paramMeasureRangeEnd ? Number.parseInt(paramMeasureRangeEnd) : Number.MAX_SAFE_INTEGER;
+        if (measureRangeStart && measureRangeEnd && measureRangeEnd < measureRangeStart) {
+            console.log("[OSMD] warning: measure range end parameter should not be smaller than measure range start. We've set start measure = end measure now.")
+            measureRangeStart = measureRangeEnd;
+        }
+        let pageFormat = paramPageFormat ? paramPageFormat : "Endless";
+        if (paramPageHeight && paramPageWidth) {
+            pageFormat = `${paramPageWidth}x${paramPageHeight}`
+        }
+        var pageBackgroundColor = paramPageBackgroundColor ? "#" + paramPageBackgroundColor : undefined; // vexflow format, see OSMDOptions. can't use # in parameters.
+        //console.log("demo: osmd pagebgcolor: " + pageBackgroundColor);
+        var backendType = (paramBackendType && paramBackendType.toLowerCase) ? paramBackendType : "svg";
+
+        var horizontalScrolling = paramHorizontalScrolling === '1';
+        var singleHorizontalStaffline = paramSingleHorizontalStaffline === '1';
+        
+        // set the backendSelect debug controls dropdown menu selected item
+        //console.log("true: " + backendSelect && backendType.toLowerCase && backendType.toLowerCase() === "canvas");
+        // TODO somehow backendSelect becomes undefined here:
+        /*if (backendSelect && backendType.toLowerCase && backendType.toLowerCase() === "canvas") {
+            console.log("here1");
+            for (var i=0; i<backendSelect.options.length; i++) {
+                if (backendSelect.options[i].value.toLowerCase() === "canvas") {
+                    backendSelect.selectedIndex = i;
+                }
+            }
+            backendSelect.value = "Canvas";
+        }*/
+
+        divControls = document.getElementById('divControls');
+        zoomControls = document.getElementById('zoomControls');
+        header = document.getElementById('header');
+        err = document.getElementById("error-td");
+        error_tr = document.getElementById("error-tr");
+        zoomDivs = [];
+        zoomDivs.push(document.getElementById("zoom-str"));
+        zoomDivs.push(document.getElementById("zoom-str-optional"));
+        custom = document.createElement("option");
+        selectSample = document.getElementById("selectSample");
+        selectBounding = document.getElementById("selectBounding");
+        skylineDebug = document.getElementById("skylineDebug");
+        bottomlineDebug = document.getElementById("bottomlineDebug");
+        zoomIns = [];
+        zoomIns.push(document.getElementById("zoom-in-btn"));
+        zoomIns.push(document.getElementById("zoom-in-btn-optional"));
+        zoomOuts = [];
+        zoomOuts.push(document.getElementById("zoom-out-btn"));
+        zoomOuts.push(document.getElementById("zoom-out-btn-optional"));
+        canvas = document.createElement("div");
+        if (horizontalScrolling) {
+            canvas.style.overflowX = 'auto'; // enable horizontal scrolling
+        }
+        //canvas.id = 'osmdCanvasDiv';
+        //canvas.style.overflowX = 'auto'; // enable horizontal scrolling
+        nextCursorBtn = document.getElementById("next-cursor-btn");
+        resetCursorBtn = document.getElementById("reset-cursor-btn");
+        followCursorCheckbox = document.getElementById("follow-cursor-checkbox");
+        showCursorBtn = document.getElementById("show-cursor-btn");
+        hideCursorBtn = document.getElementById("hide-cursor-btn");
+        backendSelect = document.getElementById("backend-select");
+        backendSelectDiv = document.getElementById("backend-select-div");
+        debugReRenderBtn = document.getElementById("debug-re-render-btn");
+        debugClearBtn = document.getElementById("debug-clear-btn");
+        selectPageSizes = [];
+        selectPageSizes.push(document.getElementById("selectPageSize"));
+        selectPageSizes.push(document.getElementById("selectPageSize-optional"));
+        printPdfBtns = [];
+        printPdfBtns.push(document.getElementById("print-pdf-btn"));
+        printPdfBtns.push(document.getElementById("print-pdf-btn-optional"));
+        transpose = document.getElementById('transpose');
+        transposeBtn = document.getElementById('transpose-btn');
+        playbackControlsButton = document.getElementById("playback-settings-button")
+
+        //var defaultDisplayVisibleValue = "block"; // TODO in some browsers flow could be the better/default value
+        var defaultVisibilityValue = "visible";
+        var devDemoRunning = process.env.OSMD_DEBUG_CONTROLS;
+        showDebugControls = paramDebugControls === '1' || (devDemoRunning && paramDebugControls !== '0')
+        if (showDebugControls) {
+            var elementsToEnable = [
+                selectSample, selectBounding, selectPageSize, backendSelect, backendSelectDiv, divControls
+            ];
+            for (var i=0; i<elementsToEnable.length; i++) {
+                if (elementsToEnable[i]) { // make sure this element is not null/exists in the index.html, e.g. github.io demo has different index.html
+                    if (elementsToEnable[i].style) {
+                        elementsToEnable[i].style.visibility = defaultVisibilityValue;
+                        elementsToEnable[i].style.opacity = 1.0;
+                    }
+                }
+            }
+        } else {
+            if (divControls) {
+                divControls.style.display = "none";
+            }
+        }
+
+        const optionalControls = document.getElementById('optionalControls');
+        if (optionalControls) {
+            if (showControls) {
+                optionalControls.style.visibility = defaultVisibilityValue;
+                optionalControls.style.opacity = 0.8;
+            } else {
+                optionalControls.style.display = 'none';
+            }
+        }
+
+        if (!showHeader) {
+            if (header) {
+                header.style.display = 'none';
+            }
+        } else {
+            if (header) {
+                header.style.opacity = 1.0;
+            }
+        }
+        // Hide error
+        error();
+
+        if (showControls) {
+            const optionalControls = document.getElementById('optionalControls');
+            if (optionalControls) {
+                optionalControls.style.opacity = 1.0;
+                // optionalControls.appendChild(zoomControlsButtons);
+                // optionalControls.appendChild(zoomControlsString);
+                optionalControls.style.position = 'absolute';
+                optionalControls.style.zIndex = '10';
+                optionalControls.style.right = '10px';
+                // optionalControls.style.padding = '10px';
+            }
+
+            if (showZoomControl) {
+                const zoomControlsButtonsColumn = document.getElementById('zoomControlsButtons-optional-column');
+                zoomControlsButtonsColumn.style.opacity = 1.0;
+                // const zoomControlsButtons = document.getElementById('zoomControlsButtons-optional');
+                // zoomControlsButtons.style.opacity = 1.0;
+                const zoomControlsString = document.getElementById('zoom-str-optional'); // actually === zoomDivs[1] above
+
+                if (zoomControlsString) {
+                    zoomControlsString.innerHTML = Math.floor(zoom * 100.0) + "%";
+                    zoomControlsString.style.display = 'inline';
+                    // zoomControlsString.style.padding = '10px';
+                }
+            }
+
+            if (showExportPdfControl) {
+                const exportPdfButtonColumn = document.getElementById('print-pdf-btn-optional-column');
+                if (exportPdfButtonColumn) {
+                    exportPdfButtonColumn.style.opacity = 1.0;
+                }
+            }
+
+            const pageFormatControlColumn = document.getElementById("selectPageSize-optional-column");
+            if (pageFormatControlColumn) {
+                if (showPageFormatControl) {
+                    pageFormatControlColumn.style.opacity = 1.0;
+                } else {
+                    // showPageFormatControlColumn.innerHTML = "";
+                    // pageFormatControlColumn.style.minWidth = 0;
+                    // pageFormatControlColumn.style.width = 0;
+                    pageFormatControlColumn.style.display = 'none'; // squeezes buttons/columns
+                    // pageFormatControlColumn.style.visibility = 'hidden';
+
+                    // const optionalControlsColumnContainer = document.getElementById("optionalControlsColumnContainer");
+                    // optionalControlsColumnContainer.removeChild(pageFormatControlColumn);
+                    // optionalControlsColumnContainer.width *= 0.66;
+                    // optionalControls.witdh *= 0.66;
+                    // optionalControls.focus();
+                }
+            }
+        }
+
+        // Create select
+        for (name in samples) {
+            if (samples.hasOwnProperty(name)) {
+                option = document.createElement("option");
+                option.value = samples[name];
+                option.textContent = name;
+            }
+            if (selectSample) {
+                selectSample.appendChild(option);
+            }
+        }
+        if (selectSample) {
+            selectSample.onchange = selectSampleOnChange;
+        }
+        if (selectBounding) {
+            selectBounding.onchange = selectBoundingOnChange;
+        }
+
+        for (const selectPageSize of selectPageSizes) {
+            if (selectPageSize) {
+                selectPageSize.onchange = function (evt) {
+                    var value = evt.target.value;
+                    openSheetMusicDisplay.setPageFormat(value);
+                    openSheetMusicDisplay.render();
+                };
+            }
+        }
+
+        for (const printPdfBtn of printPdfBtns) {
+            if (printPdfBtn) {
+                printPdfBtn.onclick = function () {
+                    createPdf();
+                }
+            }
+        }
+        // Pre-select default music piece
+
+        custom.appendChild(document.createTextNode("Custom"));
+
+        // Create zoom controls
+        for (const zoomIn of zoomIns) {
+            if (zoomIn) {
+                zoomIn.onclick = function () {
+                    zoom *= 1.2;
+                    scale();
+                };
+            }
+        }
+        for (const zoomOut of zoomOuts) {
+            if (zoomOut) {
+                zoomOut.onclick = function () {
+                    zoom /= 1.2;
+                    scale();
+                };
+            }
+        }
+
+        if (skylineDebug) {
+            skylineDebug.onclick = function () {
+                openSheetMusicDisplay.DrawSkyLine = !openSheetMusicDisplay.DrawSkyLine;
+                openSheetMusicDisplay.render();
+            }
+        }
+
+        if (bottomlineDebug) {
+            bottomlineDebug.onclick = function () {
+                openSheetMusicDisplay.DrawBottomLine = !openSheetMusicDisplay.DrawBottomLine;
+                openSheetMusicDisplay.render();
+            }
+        }
+
+        if (debugReRenderBtn) {
+            debugReRenderBtn.onclick = function () {
+                rerender();
+            }
+        }
+
+        if (debugClearBtn) {
+            debugClearBtn.onclick = function () {
+                openSheetMusicDisplay.clear();
+            }
+        }
+
+        // Create OSMD object and canvas
+        openSheetMusicDisplay = new OpenSheetMusicDisplay(canvas, {
+            autoResize: true,
+            backend: backendType,
+            //backend: "canvas",
+            disableCursor: false,
+            drawingParameters: compactMode ? "compact" : "default", // try compact (instead of default)
+            drawPartNames: true, // try false
+            // drawTitle: false,
+            // drawSubtitle: false,
+            drawFingerings: true,
+            fingeringPosition: "left", // left is default. try right. experimental: auto, above, below.
+            // fingeringInsideStafflines: "true", // default: false. true draws fingerings directly above/below notes
+            setWantedStemDirectionByXml: true, // try false, which was previously the default behavior
+            // drawUpToMeasureNumber: 3, // draws only up to measure 3, meaning it draws measure 1 to 3 of the piece.
+            drawFromMeasureNumber : measureRangeStart,
+            drawUpToMeasureNumber : measureRangeEnd,
+
+            //drawMeasureNumbers: false, // disable drawing measure numbers
+            //measureNumberInterval: 4, // draw measure numbers only every 4 bars (and at the beginning of a new system)
+            useXMLMeasureNumbers: true, // read measure numbers from xml
+
+            // coloring options
+            coloringEnabled: true,
+            // defaultColorNotehead: "#CC0055", // try setting a default color. default is black (undefined)
+            // defaultColorStem: "#BB0099",
+
+            autoBeam: false, // try true, OSMD Function Test AutoBeam sample
+            autoBeamOptions: {
+                beam_rests: false,
+                beam_middle_rests_only: false,
+                //groups: [[3,4], [1,1]],
+                maintain_stem_directions: false
+            },
+            pageFormat: pageFormat,
+            pageBackgroundColor: pageBackgroundColor,
+            renderSingleHorizontalStaffline: singleHorizontalStaffline
+
+            // tupletsBracketed: true, // creates brackets for all tuplets except triplets, even when not set by xml
+            // tripletsBracketed: true,
+            // tupletsRatioed: true, // unconventional; renders ratios for tuplets (3:2 instead of 3 for triplets)
+        });
+        openSheetMusicDisplay.setLogLevel('info'); // set this to 'debug' if you want to see more detailed control flow information in console
+        document.body.appendChild(canvas);
+
+        window.addEventListener("keydown", function (e) {
+            var event = window.event ? window.event : e;
+            if (event.keyCode === 39) {
+                openSheetMusicDisplay.cursor.next();
+            }
+        });
+        nextCursorBtn.addEventListener("click", function () {
+            openSheetMusicDisplay.cursor.next();
+        });
+        resetCursorBtn.addEventListener("click", function () {
+            openSheetMusicDisplay.cursor.reset();
+        });
+        if (followCursorCheckbox) {
+            followCursorCheckbox.onchange = function () {
+                openSheetMusicDisplay.FollowCursor = !openSheetMusicDisplay.FollowCursor;
+            }
+        }
+        window.addEventListener("wheel", function(e){
+            if(followCursorCheckbox) {
+                followCursorCheckbox.checked = false;
+                openSheetMusicDisplay.FollowCursor = false;
+            }
+        });
+        hideCursorBtn.addEventListener("click", function () {
+            if (openSheetMusicDisplay.cursor) {
+                openSheetMusicDisplay.cursor.hide();
+            } else {
+                console.info("Can't hide cursor, as it was disabled (e.g. by drawingParameters).");
+            }
+        });
+        showCursorBtn.addEventListener("click", function () {
+            if (openSheetMusicDisplay.cursor) {
+                openSheetMusicDisplay.cursor.show();
+            } else {
+                console.info("Can't show cursor, as it was disabled (e.g. by drawingParameters).");
+            }
+        });
+
+        backendSelect.addEventListener("change", function (e) {
+            var value = e.target.value;
+            var createNewOsmd = true;
+
+            if (createNewOsmd) {
+                // clears the canvas element
+                canvas.innerHTML = "";
+                openSheetMusicDisplay = new OpenSheetMusicDisplay(canvas, { backend: value });
+                openSheetMusicDisplay.setLogLevel('info'); // set this to 'debug' if you want to get more detailed control flow information
+            } else {
+                // alternative, doesn't work yet, see setOptions():
+                openSheetMusicDisplay.setOptions({ backend: value });
+            }
+            console.log("[OSMD] selectSampleOnChange addEventListener change");
+            // selectSampleOnChange();
+        });
+        if(transposeBtn && transpose){
+            openSheetMusicDisplay.TransposeCalculator = new TransposeCalculator();
+
+            transposeBtn.onclick = function(){
+                var transposeValue = parseInt(transpose.value);
+                openSheetMusicDisplay.Sheet.Transpose = transposeValue;
+                openSheetMusicDisplay.updateGraphic();
+                rerender();
+            }
+        }
+        playbackControl = demoPlaybackControl(openSheetMusicDisplay);
+        playbackControlsButton.addEventListener("click", function(){
+            if(!playbackControl.IsClosed()){
+                playbackControl.hideControls();
+            } else {
+                playbackControl.showControls();
+            }
+        });
+        // TODO after selectSampleOnChange, the resize handler triggers immediately,
+        //   so we render twice at the start of the demo.
+        //   maybe delay the first osmd render, e.g. when window ready?
+        if (paramOpenUrl) {
+            if (openSheetMusicDisplay.getLogLevel() < 2) { // debug or trace
+                console.log("[OSMD] selectSampleOnChange with " + paramOpenUrl);
+            }
+            // DEBUG: cause an error for a certain sample, for testing
+            // if (paramOpenUrl.startsWith("Beethoven")) {
+            //     paramOpenUrl.causeError();
+            // }
+            selectSampleOnChange(paramOpenUrl);
+        } else {
+            if (openSheetMusicDisplay.getLogLevel() < 2) { // debug or trace
+                console.log("[OSMD] selectSampleOnChange without param");
+            }
+            selectSampleOnChange();
+        }
+    }
+
+    function findGetParameter(parameterName) {
+        // special treatment for the openUrl parameter, because different systems attach different arguments to an URL.
+        // because of CORS (cross-origin safety restrictions), you can only load an xml file from the same origin (server).
+
+        // test parameter: ?openUrl=https://opensheetmusiceducation.org/index.php?gf-download=2020%2F01%2FJohannSebastianBach_PraeludiumInCDur_BWV846_1.xml&endUrl&form-id=1&field-id=4&hash=c4ba271ef08204a26cbd4cd2d751c53b78f238c25ddbb1f343e1172f2ce2aa53
+        //   (enable the console.log at the end of this method for testing)
+        // working test parameter in local demo: ?openUrl=OSMD_function_test_all.xml&endUrl
+    
+        if (parameterName === 'openUrl') {
+            let startParameterName = 'openUrl=';
+            let endParameterName = '&endUrl';
+            let openUrlIndex = location.search.indexOf(startParameterName);
+            if (openUrlIndex < 0) {
+                return undefined;
+            }
+            let endIndex = location.search.indexOf(endParameterName) + endParameterName.length;
+            if (endIndex < 0) {
+                console.log("[OSMD] If using openUrl as a parameter, you have to end it with '&endUrl'. openUrl parameter omitted.");
+                return undefined;
+            }
+            let urlString = location.search.substring(openUrlIndex + startParameterName.length, endIndex - endParameterName.length);
+            //console.log("openUrl: " + urlString);
+            return urlString;
+        }
+
+        let result = undefined;
+        let tmp = [];
+        location.search
+            .substr(1)
+            .split('&')
+            .forEach(function (item) {
+                tmp = item.split('=');
+                if (tmp[0] === parameterName) {
+                    result = decodeURIComponent(tmp[1]);
+                    //console.log('Found param:' + parameterName + ' = ' + result);
+                }
+            });
+        return result;
+    }
+
+    function selectBoundingOnChange(evt) {
+        var value = evt.target.value;
+        openSheetMusicDisplay.DrawBoundingBox = value;
+    }
+
+    function selectSampleOnChange(str) {
+        var comment = undefined;
+        var sampleStr = undefined;
+        error();
+        disable();
+        var isCustom = typeof str === "string";
+        if (!isCustom) {
+            if (selectSample) {
+                sampleStr = selectSample.value;
+                str = sampleFolder + sampleStr;
+            } else {
+                if (samples && samples.length > 0) {
+                    sampleStr = samples[0];
+                    str = sampleFolder + sampleStr;
+                } else {
+                    return; // no sample to load right now
+                }
+            }
+            if(comments.hasOwnProperty(sampleStr)){
+                comment = comments[sampleStr];
+            }
+        }
+        // zoom = 1.0;
+
+        setSampleSpecificOptions(str, isCustom);
+
+        openSheetMusicDisplay.load(str, comment).then(
+            function () {
+                // This gives you access to the osmd object in the console. Do not use in production code
+                window.osmd = openSheetMusicDisplay;
+                openSheetMusicDisplay.zoom = zoom;
+                return openSheetMusicDisplay.render();
+            },
+            function (e) {
+                errorLoadingOrRenderingSheet(e, "rendering");
+            }
+        ).then(
+            function () {
+                return onLoadingEnd(isCustom);
+            }, function (e) {
+                errorLoadingOrRenderingSheet(e, "loading");
+                onLoadingEnd(isCustom);
+            }
+        );
+    }
+
+    function setSampleSpecificOptions(str, isCustom) {
+        if (!isCustom && str.includes("measuresToDraw")) { // set options for measuresToDraw sample
+            // stash previously set range of measures to draw
+            if (!measureToDrawRangeNeedsReset) { // only stash once, when measuresToDraw called multiple times in a row
+                minMeasureToDrawStashed = openSheetMusicDisplay.EngravingRules.MinMeasureToDrawIndex + 1;
+                maxMeasureToDrawStashed = openSheetMusicDisplay.EngravingRules.MaxMeasureToDrawIndex + 1;
+            }
+            measureToDrawRangeNeedsReset = true;
+
+            // for debugging: draw from a random range of measures
+            let minMeasureToDraw = Math.ceil(Math.random() * 15); // measures start at 1 (measureIndex = measure number - 1 elsewhere)
+            let maxMeasureToDraw = Math.ceil(Math.random() * 15);
+            if (minMeasureToDraw > maxMeasureToDraw) {
+                minMeasureToDraw = maxMeasureToDraw;
+                let a = minMeasureToDraw;
+                maxMeasureToDraw = a;
+            }
+            //minMeasureToDraw = 1; // set your custom indexes here. Drawing only one measure can be a special case
+            //maxMeasureToDraw = 1;
+            console.log("drawing measures in the range: [" + minMeasureToDraw + "," + maxMeasureToDraw + "]");
+            openSheetMusicDisplay.setOptions({
+                drawFromMeasureNumber: minMeasureToDraw,
+                drawUpToMeasureNumber: maxMeasureToDraw
+            });
+        } else if (measureToDrawRangeNeedsReset) { // reset for other samples
+            openSheetMusicDisplay.setOptions({
+                drawFromMeasureNumber: minMeasureToDrawStashed,
+                drawUpToMeasureNumber: maxMeasureToDrawStashed
+            });
+            measureToDrawRangeNeedsReset = false;
+        }
+
+        if (!isCustom && str.includes("Test_Container_height")) {
+            drawingParametersStashed = openSheetMusicDisplay.drawingParameters.drawingParametersEnum;
+            openSheetMusicDisplay.setOptions({
+                drawingParameters: "compacttight"
+            });
+            drawingParametersNeedsReset = true;
+        } else if (drawingParametersNeedsReset) {
+            openSheetMusicDisplay.setOptions({
+                drawingParameters: drawingParametersStashed
+            });
+            drawingParametersNeedsReset = false;
+        }
+
+        // Enable Boomwhacker-like coloring for OSMD Function Test - Auto-Coloring (Boomwhacker-like, custom color set)
+        if (!isCustom && str.includes("auto-custom-coloring")) { // set options for auto coloring sample
+            autoCustomColoringOptionNeedsReset = true;
+            //openSheetMusicDisplay.setOptions({coloringMode: 1}); // Auto-Coloring with pre-defined colors
+            openSheetMusicDisplay.setOptions({
+                coloringMode: 2, // custom coloring set. 0 would be XML, 1 autocoloring
+                coloringSetCustom: ["#d82c6b", "#F89D15", "#FFE21A", "#4dbd5c", "#009D96", "#43469d", "#76429c", "#ff0000"],
+                // last color value of coloringSetCustom is for rest notes
+                colorStemsLikeNoteheads: true
+            });
+        } else if (autoCustomColoringOptionNeedsReset) {
+            openSheetMusicDisplay.setOptions({ // set default values. better would be to restore to stashed values, but unnecessarily complex for demo
+                coloringMode: 0,
+                colorStemsLikeNoteheads: false,
+                coloringSetCustom: null
+            });
+            autoCustomColoringOptionNeedsReset = false;
+        }
+        if (!isCustom && str.includes("autobeam")) {
+            autobeamOptionStashedValue = openSheetMusicDisplay.EngravingRules.AutoBeamNotes; // stash previously set value, to restore later
+            autobeamOptionNeedsReset = true;
+            openSheetMusicDisplay.setOptions({ autoBeam: true });
+        } else if (autobeamOptionNeedsReset) {
+            openSheetMusicDisplay.setOptions({ autoBeam: autobeamOptionStashedValue });
+            autobeamOptionNeedsReset = false;
+        }
+        if (!isCustom && str.includes("OSMD_Function_Test_System_and_Page_Breaks")) {
+            pageBreaksOptionStashedValue = openSheetMusicDisplay.EngravingRules.NewPageAtXMLNewPageAttribute;
+            systemBreaksOptionStashedValue = openSheetMusicDisplay.EngravingRules.NewSystemAtXMLNewSystemAttribute;
+            pageBreaksOptionNeedsReset = true;
+            openSheetMusicDisplay.setOptions({ newPageFromXML: true, newSystemFromXML: true });
+        }
+        else if (pageBreaksOptionNeedsReset) {
+            openSheetMusicDisplay.setOptions({ newPageFromXML: pageBreaksOptionStashedValue, newSystemFromXML: systemBreaksOptionStashedValue });
+            pageBreaksOptionNeedsReset = false;
+        }
+        if (!isCustom && str.includes("Schubert_An_die_Musik")) { // TODO weird layout bug here with part names. but shouldn't be in score anyways
+            drawPartNamesOptionStashedValue = openSheetMusicDisplay.EngravingRules.RenderPartNames;
+            drawPartAbbreviationsStashedValue = openSheetMusicDisplay.EngravingRules.RenderPartAbbreviations;
+            openSheetMusicDisplay.setOptions({ drawPartNames: false, drawPartAbbreviations: false }); // TODO sets osmd.drawingParameters.DrawPartNames! also check EngravingRules.RenderPartAbbreviations, was false
+            drawPartNamesOptionNeedsReset = true;
+        } else if (drawPartNamesOptionNeedsReset) {
+            openSheetMusicDisplay.setOptions({ drawPartNames: drawPartNamesOptionStashedValue, drawPartAbbreviations: drawPartAbbreviationsStashedValue });
+            drawPartNamesOptionNeedsReset = false;
+        }
+    }
+
+    function errorLoadingOrRenderingSheet(e, loadingOrRenderingString) {
+        var errorString = "Error " + loadingOrRenderingString + " sheet: " + e;
+        // if (process.env.DEBUG) { // people may not set a debug environment variable for the demo.
+        // Always giving a StackTrace might give us more and better error reports.
+        // TODO for a release, StackTrace control could be reenabled
+        errorString += "\n" + "StackTrace: \n" + e.stack;
+        // }
+        console.warn(errorString);
+    }
+
+    function onLoadingEnd(isCustom) {
+        // Remove option from select
+        if (!isCustom && custom.parentElement === selectSample) {
+            selectSample.removeChild(custom);
+        }
+
+        playbackControl.initialize();
+
+        // Enable controls again
+        enable();
+    }
+
+    function logCanvasSize() {
+        for (const zoomDiv of zoomDivs) {
+            if (zoomDiv) {
+                zoomDiv.innerHTML = Math.floor(zoom * 100.0) + "%";
+            }
+        }
+    }
+
+    function scale() {
+        disable();
+        window.setTimeout(function () {
+            openSheetMusicDisplay.Zoom = zoom;
+            openSheetMusicDisplay.render();
+            enable();
+        }, 0);
+    }
+
+    function rerender() {
+        disable();
+        window.setTimeout(function () {
+            if (openSheetMusicDisplay.IsReadyToRender()) {
+                openSheetMusicDisplay.render();
+            } else {
+                console.log("[OSMD demo] Loses context!"); // TODO not sure that this message is reasonable, renders fine anyways. maybe vexflow context lost?
+                selectSampleOnChange(); // reload sample e.g. after osmd.clear()
+            }
+            enable();
+        }, 0);
+    }
+
+    function error(errString) {
+        if (!errString) {
+            error_tr.style.display = "none";
+        } else {
+            console.log("[OSMD demo] error: " + errString)
+            err.textContent = errString;
+            error_tr.style.display = "";
+            canvas.width = canvas.height = 0;
+            enable();
+        }
+    }
+
+    // Enable/Disable Controls
+    function disable() {
+        document.body.style.opacity = 0.3;
+        setDisabledForControls("disabled");
+    }
+
+    function enable() {
+        document.body.style.opacity = 1;
+        setDisabledForControls("");
+        logCanvasSize();
+    }
+
+    function setDisabledForControls(disabledValue) {
+        if (selectSample) {
+            selectSample.disabled = disabledValue;
+        }
+        for (const zoomIn of zoomIns) {
+            if (zoomIn) {
+                zoomIn.disabled = disabledValue;
+            }
+        }
+        for (const zoomOut of zoomOuts) {
+            if (zoomOut) {
+                zoomOut.disabled = disabledValue;
+            }
+        }
+    }
+
+    /**
+     * Creates a Pdf of the currently rendered MusicXML
+     * @param pdfName if no name is given, the composer and title of the piece will be used
+     */
+    function createPdf(pdfName) {
+        if (openSheetMusicDisplay.backendType !== BackendType.SVG) {
+            console.log("[OSMD] createPdf(): Warning: createPDF is only supported for SVG background for now, not for Canvas." +
+                " Please use osmd.setOptions({backendType: SVG}).");
+            return;
+        }
+
+        if (pdfName === undefined) {
+            pdfName = openSheetMusicDisplay.sheet.FullNameString + ".pdf";
+        }
+
+        const backends = openSheetMusicDisplay.drawer.Backends;
+        let svgElement = backends[0].getSvgElement();
+
+        let pageWidth = 210;
+        let pageHeight = 297;
+        const engravingRulesPageFormat = openSheetMusicDisplay.rules.PageFormat;
+        if (engravingRulesPageFormat && !engravingRulesPageFormat.IsUndefined) {
+            pageWidth = engravingRulesPageFormat.width;
+            pageHeight = engravingRulesPageFormat.height;
+        } else {
+            pageHeight = pageWidth * svgElement.clientHeight / svgElement.clientWidth;
+        }
+
+        const orientation = pageHeight > pageWidth ? "p" : "l";
+        // create a new jsPDF instance
+        const pdf = new jsPDF(orientation, "mm", [pageWidth, pageHeight]);
+        const scale = pageWidth / svgElement.clientWidth;
+        for (let idx = 0, len = backends.length; idx < len; ++idx) {
+            if (idx > 0) {
+                pdf.addPage();
+            }
+            svgElement = backends[idx].getSvgElement();
+
+            // render the svg element
+            svg2pdf(svgElement, pdf, {
+                scale: scale,
+                xOffset: 0,
+                yOffset: 0
+            });
+        }
+
+        // simply save the created pdf
+        pdf.save(pdfName);
+
+        // note that using jspdf with svg2pdf creates unnecessary console warnings "AcroForm-Classes are not populated into global-namespace..."
+        // this will hopefully be fixed with a new jspdf release, see https://github.com/yWorks/jsPDF/pull/32
+    }
+
+    var demoPlaybackControl = function(osmd) {
+
+        var playbackListener = {
+            play() {
+                followCursorCheckbox.checked = true;
+                openSheetMusicDisplay.FollowCursor = true;
+            },
+            pause() {},
+            reset() {},
+            bpmChanged() {},
+            volumeChanged() {},
+            volumeMute() {},
+            volumeUnmute() {}
+        }
+
+        var timingSource = new LinearTimingSource();
+        var playbackManager = new PlaybackManager(timingSource, undefined, new BasicAudioPlayer(), undefined);
+        playbackManager.DoPlayback = true;
+        playbackManager.DoPreCount = false;
+        var playbackControlPanel = new ControlPanel();
+        playbackControlPanel.addListener(playbackManager);
+        playbackControlPanel.addListener(playbackListener);
+
+        function initialize() {
+            timingSource.reset();
+            timingSource.pause();
+            timingSource.Settings = osmd.sheet.playbackSettings;
+            playbackManager.initialize(osmd.sheet.musicPartManager);
+            playbackManager.addListener(osmd.cursor);
+            playbackManager.reset();
+            osmd.PlaybackManager = playbackManager;
+            playbackControlPanel.clearVolumeTracks();
+            playbackControlPanel.addVolumeTrack(playbackManager.Metronome.Name, playbackManager.Metronome.Id, playbackManager.Metronome.Volume*100);
+            for(const instrId of playbackManager.InstrumentIdMapping.keys()) {
+                const instr = playbackManager.InstrumentIdMapping.getValue(instrId);
+                playbackControlPanel.addVolumeTrack(instr.Name, instrId, instr.Volume * 100);
+            }
+            playbackControlPanel.bpmChanged(osmd.sheet.DefaultStartTempoInBpm);
+        }
+
+        function showControls() {
+            playbackControlPanel.show();
+        }
+
+        function hideControls() {
+            playbackControlPanel.hideAndClear();
+        }
+
+        function IsClosed() {
+            return playbackControlPanel.IsClosed;
+        }
+
+        return { 
+            initialize: initialize,
+            showControls: showControls,
+            hideControls: hideControls,
+            IsClosed: IsClosed
+        }
+    };
+
+    // Register events: load, drag&drop
+    window.addEventListener("load", function () {
+        init();
+    });
+    window.addEventListener("dragenter", function (event) {
+        event.preventDefault();
+        disable();
+    });
+    window.addEventListener("dragover", function (event) {
+        event.preventDefault();
+    });
+    window.addEventListener("dragleave", function (event) {
+        enable();
+    });
+    window.addEventListener("drop", function (event) {
+        event.preventDefault();
+        if (!event.dataTransfer || !event.dataTransfer.files || event.dataTransfer.files.length === 0) {
+            return;
+        }
+        // Add "Custom..." score
+        selectSample.appendChild(custom);
+        custom.selected = "selected";
+        // Read dragged file
+        var reader = new FileReader();
+        reader.onload = function (res) {
+            selectSampleOnChange(res.target.result);
+        };
+        var filename = event.dataTransfer.files[0].name;
+        if (filename.toLowerCase().indexOf(".xml") > 0
+            || filename.toLowerCase().indexOf(".musicxml") > 0) {
+            reader.readAsText(event.dataTransfer.files[0]);
+        } else if (event.dataTransfer.files[0].name.toLowerCase().indexOf(".mxl") > 0) {
+            reader.readAsBinaryString(event.dataTransfer.files[0]);
+        }
+        else {
+            alert("No vaild .xml/.mxl/.musicxml file!");
+        }
+    });
+}());

+ 121 - 0
karma.conf.js

@@ -0,0 +1,121 @@
+var common = require('./webpack.common.js')
+
+module.exports = function (config) {
+    'use strict'
+    config.set({
+        // base path that will be used to resolve all patterns (eg. files, exclude)
+        basePath: '',
+
+        // frameworks to use
+        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+        frameworks: ['mocha', 'chai'],
+
+        // list of files to exclude
+        exclude: [],
+
+        files: [
+            {
+                pattern: 'test/Util/*.ts',
+                included: false
+            },
+            {
+                pattern: 'test/**/*.ts',
+                included: true
+            }, {
+                pattern: 'test/data/*.xml',
+                included: true
+            }, {
+                pattern: 'test/data/*.mxl.base64',
+                included: true
+            }, {
+                pattern: 'test/data/*.mxl',
+                included: false,
+                watched: false,
+                served: true
+            }
+        ],
+
+        // preprocess matching files before serving them to the browser
+        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+        preprocessors: {
+            'test/data/*.xml': ['xml2js'],
+            'test/data/*.mxl.base64': ['base64-to-js'],
+            // add webpack as preprocessor
+            'test/**/*.ts': ['webpack']
+        },
+
+        webpack: {
+            // karma watches the test entry points
+            // (you don't need to specify the entry option)
+            // webpack watches dependencies
+
+            // copy parts of webpack configuration to use minimal effort here
+            devtool: process.env.CI ? false : 'inline-source-map',
+            mode: process.env.CI ? 'production' : 'development',
+            module: {
+                rules: common.module.rules
+            },
+            resolve: common.resolve
+        },
+
+        // Required for Firefox and Chrome to work
+        // see https://github.com/webpack-contrib/karma-webpack/issues/188
+        mime: {
+            'text/x-typescript': ['ts']
+        },
+
+        // test results reporter to use
+        // possible values: 'dots', 'progress'
+        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+        reporters: ['mocha'],
+
+        // web server port
+        port: 9876,
+        // timeout in ms:
+        browserNoActivityTimeout: 100000, // default 10000
+        browserDisconnectTimeout: 10000, // default 2000
+        browserDisconnectTolerance: 1, // default 0
+        captureTimeout: 60000,
+        // enable / disable colors in the output (reporters and logs)
+        colors: true,
+
+        // level of logging
+        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+        logLevel: config.LOG_INFO,
+
+        client: {
+            captureConsole: true,
+            mocha: {
+                timeout: process.env.timeout || 6000
+            }
+        },
+
+        // enable / disable watching file and executing tests whenever any file changes
+        autoWatch: false,
+
+        // start these browsers
+        browsers: ['ChromeHeadlessNoSandbox'],
+
+        // For security reasons, Google Chrome is unable to provide sandboxing
+        // when it is running in container-based environments (e.g. CI).
+        customLaunchers: {
+            ChromeHeadlessNoSandbox: {
+                base: 'ChromeHeadless',
+                flags: ['--no-sandbox',
+                    '--disable-web-security']
+            },
+            ChromeNoSecurity: {
+                base: 'Chrome',
+                flags: ['--disable-web-security']
+            }
+        },
+
+        // Continuous Integration mode
+        // if true, Karma captures browsers, runs the tests and exits
+        singleRun: true,
+
+        // Concurrency level
+        // how many browser should be started simultaneous
+        concurrency: Infinity
+    })
+}

+ 140 - 0
package.json

@@ -0,0 +1,140 @@
+{
+  "name": "opensheetmusicdisplay-private",
+  "version": "0.9.3",
+  "description": "Private OSMD mirror/audio player.",
+  "main": "build/opensheetmusicdisplay.min.js",
+  "typings": "build/dist/src/",
+  "scripts": {
+    "docs": "typedoc --out ./build/docs --name OpenSheetMusicDisplay --module commonjs --target ES2017 --ignoreCompilerErrors --mode file ./src",
+    "eslint": "eslint -c .eslintrc.js --ext .ts .",
+    "lint": "npm run eslint",
+    "test": "karma start --single-run --no-auto-watch",
+    "test:watch": "karma start --no-single-run --auto-watch --browsers ChromeNoSecurity",
+    "prebuild": "ncp src/VexFlowPatch/src/ node_modules/vexflow/src/",
+    "prepare": "npm run build",
+    "build": "npm-run-all lint build:webpack",
+    "build:doc": "cross-env STATIC_FILES_SUBFOLDER=sheets npm run build",
+    "build:webpack": "webpack --progress --colors --config webpack.prod.js",
+    "build:webpack-dev": "webpack --progress --colors --config webpack.dev.js",
+    "build:webpack-sourcemap": "webpack --progress --colors --config webpack.sourcemap.js",
+    "start": "webpack-dev-server --progress --colors --config webpack.dev.js",
+    "start:local": "webpack-dev-server --progress --colors --config webpack.local.js",
+    "generatePNG": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./export png 0 0 allSmall --osmdtesting",
+    "generateSVG": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./export/svg svg 0 0 allSmall --osmdtesting",
+    "generatePNG:debug": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./export png 0 0 allSmall --debugosmdtesting",
+    "generatePNG:single": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./export png 0 0 ^Beethoven",
+    "generatePNG:legacyslow": "node ./test/Util/generateDiffImagesPuppeteerLocalhost.js ./test/data ./export png 0 0 all",
+    "generatePNG:paged": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./export png 210 297 allSmall",
+    "generatePNG:paged:debug": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./export png 210 297 all --debug 5000",
+    "generatePNG:paged:single": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./export png 0 0 ^Beethoven",
+    "generate:current": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./visual_regression/current png 0 0 allSmall --osmdtesting",
+    "generate:current:debug": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./visual_regression/current png 0 0 allSmall --debugosmdtesting",
+    "generate:current:singletest": "node test/Util/generateImages_browserless.js ../../build ./test/data ./visual_regression/current png 0 0 ^Beethoven --osmdtestingsingle",
+    "generate:blessed": "node ./test/Util/generateImages_browserless.js ../../build ./test/data ./visual_regression/blessed png 0 0 allSmall --osmdtesting",
+    "test:visual": "bash ./test/Util/visual_regression.sh ./visual_regression",
+    "test:visual:singletest": "sh ./test/Util/visual_regression.sh ./visual_regression Beethoven",
+    "fix-memory-limit": "cross-env NODE_OPTIONS=--max_old_space_size=4096"
+  },
+  "pre-commit": [
+    "lint"
+  ],
+  "files": [
+    "build/dist/src",
+    "build/opensheetmusicdisplay.min.js",
+    "AUTHORS",
+    "CHANGELOG.md",
+    "README.md",
+    "external"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/opensheetmusicdisplay/opensheetmusicdisplay"
+  },
+  "keywords": [
+    "sheet",
+    "music",
+    "vexflow",
+    "musicxml"
+  ],
+  "author": "PhonicScore",
+  "license": "UNLICENSED",
+  "bugs": {
+    "url": "https://github.com/opensheetmusicdisplay/opensheetmusicdisplay/issues"
+  },
+  "homepage": "http://opensheetmusicdisplay.org",
+  "dependencies": {
+    "@types/vexflow": "^3.0.0",
+    "jszip": "3.4.0",
+    "loglevel": "^1.6.8",
+    "soundfont-player": "^0.12.0",
+    "standardized-audio-context": "^25.1.5",
+    "typescript-collections": "^1.3.3",
+    "vexflow": "^1.2.93"
+  },
+  "devDependencies": {
+    "@types/chai": "^4.2.11",
+    "@types/mocha": "^7.0.2",
+    "@types/node": "^14.0.9",
+    "@typescript-eslint/eslint-plugin": "^4.14.0",
+    "@typescript-eslint/parser": "^4.14.0",
+    "canvas": "^2.6.1",
+    "chai": "^4.1.0",
+    "clean-webpack-plugin": "^3.0.0",
+    "cross-blob": "^1.2.0",
+    "cross-env": "^7.0.2",
+    "cz-conventional-changelog": "^3.0.0",
+    "eslint": "^6.8.0",
+    "eslint-config-standard": "14.1.1",
+    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-jsdoc": "^31.0.8",
+    "eslint-plugin-no-null": "^1.0.2",
+    "eslint-plugin-node": "^11.0.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.0",
+    "html-webpack-plugin": "^4.3.0",
+    "jquery": "^3.5.1",
+    "jsdom": "^16.2.2",
+    "jspdf-yworks": "^2.1.1",
+    "karma": "^5.0.8",
+    "karma-base64-to-js-preprocessor": "^0.0.1",
+    "karma-chai": "^0.1.0",
+    "karma-chrome-launcher": "^3.1.0",
+    "karma-firefox-launcher": "^1.0.0",
+    "karma-mocha": "^2.0.1",
+    "karma-mocha-reporter": "^2.0.4",
+    "karma-webpack": "^4.0.2",
+    "karma-xml2js-preprocessor": "^0.0.3",
+    "mocha": "^7.0.1",
+    "ncp": "^2.0.0",
+    "npm-run-all": "^4.1.2",
+    "pre-commit": "^1.2.2",
+    "svg2pdf.js": "^1.5.0",
+    "ts-loader": "^4.1.0",
+    "typedoc": "^0.17.3",
+    "typescript": "^3.9.5",
+    "webpack": "^4.43.0",
+    "webpack-cli": "^3.3.11",
+    "webpack-dev-server": "^3.11.2",
+    "webpack-merge": "^4.1.2",
+    "webpack-visualizer-plugin": "^0.1.11",
+    "html-loader": "^1.3.0",
+    "json5-loader": "^4.0.0",
+    "@material/layout-grid": "^7.0.0",
+    "@material/button": "^7.0.0",
+    "@material/icon-button": "^7.0.0",
+    "@material/ripple": "^7.0.0",
+    "@material/textfield": "^7.0.0",
+    "@material/tab-bar": "^7.0.0",
+    "@material/slider": "^7.0.0",
+    "handlebars": "^4.7.6",
+    "@splidejs/splide": "^2.4.14",
+    "@splidejs/splide-extension-grid": "^0.2.0",
+    "uuid": "^8.3.0",
+    "@types/uuid": "^3.4.3"
+  },
+  "config": {
+    "commitizen": {
+      "path": "./node_modules/cz-conventional-changelog"
+    }
+  }
+}

+ 11 - 0
src/Common/Algorithms/Controller/AbstractNumberController.ts

@@ -0,0 +1,11 @@
+
+
+export interface AbstractNumberController {
+    CurrentValue(): number;
+
+    setDirectly(newValue: number): void;
+    setExpectedValue(newValue: number): void;
+
+    startControlling(): void;
+    stopControlling(): void;
+}

+ 37 - 0
src/Common/Algorithms/Controller/BrowserScrollController.ts

@@ -0,0 +1,37 @@
+import { IControllerOutputListener } from "../../Interfaces/IControllerOutputListener";
+import { AbstractNumberController } from "./AbstractNumberController";
+
+export class BrowserScrollController implements AbstractNumberController {
+    private listener: IControllerOutputListener;
+
+    constructor(listener: IControllerOutputListener) {
+        this.listener = listener;
+    }
+
+    private currentValue: number;
+    public setDirectly(newValue: number): void {
+        this.currentValue = newValue;
+        this.listener.outputChanged(true, this.currentValue, newValue); // TODO just filled out for now
+        // TODO do browser smooth scroll
+        // scroll-behavior: smooth;
+    }
+
+    public setExpectedValue(newValue: number): void {
+        this.currentValue = newValue;
+        this.listener.outputChanged(false, this.currentValue, newValue); // TODO just filled out for now
+        // TODO do browser smooth scroll
+        // scroll-behavior: smooth;
+    }
+
+    public CurrentValue(): number {
+        return this.currentValue;
+    }
+
+    public startControlling(): void {
+        // TODO
+    }
+
+    public stopControlling(): void {
+        // TODO
+    }
+}

+ 20 - 0
src/Common/DataObjects/CursorPosChangedData.ts

@@ -0,0 +1,20 @@
+import { Fraction } from "./Fraction";
+import { IRepetition } from "../Interfaces/IRepetition";
+
+export class CursorPosChangedData {
+    constructor(currentMeasureIndex: number = 0, currentRepetition: IRepetition = undefined, currentRepetitionIteration: number = 0,
+                predictedPosition: Fraction = undefined, beatsPerMinute: number = 0) {
+        this.CurrentMeasureIndex = currentMeasureIndex;
+        this.CurrentRepetition = currentRepetition;
+        this.CurrentRepetitionIteration = currentRepetitionIteration;
+        this.PredictedPosition = predictedPosition;
+        this.CurrentBpm = beatsPerMinute;
+    }
+
+    public ResetOccurred: boolean = false;
+    public CurrentMeasureIndex: number;
+    public CurrentRepetition: IRepetition;
+    public CurrentRepetitionIteration: number;
+    public PredictedPosition: Fraction;
+    public CurrentBpm: number;
+}

+ 487 - 0
src/Common/DataObjects/Fraction.ts

@@ -0,0 +1,487 @@
+// TODO: Check the operators' names
+// TODO: This class should probably be immutable?
+
+/**
+ * A class representing mathematical fractions, which have a numerator and a denominator.
+ */
+export class Fraction {
+  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.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;
+  }
+
+    public static multiply (f1: Fraction, f2: Fraction): Fraction {
+        return new Fraction ( (f1.wholeValue * f1.denominator + f1.numerator) * (f2.wholeValue * f2.denominator + f2.numerator),
+                              f1.denominator * f2.denominator);
+    }
+
+  private static greatestCommonDenominator(a: number, b: number): number {
+    if (a === 0) {
+      return b;
+    }
+
+    if (b === 1) {
+      return 1;
+    }
+
+    while (Math.abs(b) > 1e-8) { // essentially b > 0, accounts for floating point inaccuracies (0.000...01)
+      if (a > b) {
+        a -= b;
+      } else {
+        b -= a;
+      }
+    }
+
+    return Math.round(a); // prevent returning 4.000001 or something, though it doesn't happen for our samples
+  }
+
+  /**
+   *
+   * @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();
+  }
+
+  public toString(): string {
+    let result: string = this.numerator + "/" + this.denominator;
+    if (this.wholeValue !== 0) {
+      result = this.wholeValue + " " + result;
+    }
+
+    return result;
+  }
+
+  public clone(): Fraction {
+    return new Fraction(this.numerator, this.denominator, this.wholeValue, false);
+  }
+
+  public get Numerator(): number {
+    return this.numerator;
+  }
+
+  public set Numerator(value: number) {
+    if (this.numerator !== value) {
+      this.numerator = value;
+      this.simplify();
+      this.setRealValue();
+    }
+  }
+
+  public get Denominator(): number {
+    return this.denominator;
+  }
+
+  public set Denominator(value: number) {
+    if (this.denominator !== value) {
+      this.denominator = value;
+      // don't simplify in case of a GraceNote (need it in order to set the right symbol)
+      if (this.numerator !== 0) {
+        this.simplify();
+      }
+      this.setRealValue();
+    }
+  }
+
+  public get WholeValue(): number {
+    return this.wholeValue;
+  }
+
+  public set WholeValue(value: number) {
+    if (this.wholeValue !== value) {
+      this.wholeValue = value;
+      this.setRealValue();
+    }
+  }
+
+  /**
+   * Returns the unified numerator where the whole value will be expanded
+   * with the denominator and added to the existing numerator.
+   */
+  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();
+  // }
+
+  /**
+   * Adds a Fraction to this Fraction.
+   * Attention: This changes the already existing Fraction, which might be referenced elsewhere!
+   * Use Fraction.plus() for creating a new Fraction object being the sum of two Fractions.
+   * @param fraction the Fraction to add.
+   */
+  public Add(fraction: Fraction): Fraction {
+    // normally should check if denominator or fraction.denominator is 0 but in our case
+    // a zero denominator doesn't make sense
+    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();
+    return this;
+  }
+
+  /**
+   * Subtracts a Fraction from this Fraction.
+   * Attention: This changes the already existing Fraction, which might be referenced elsewhere!
+   * Use Fraction.minus() for creating a new Fraction object being the difference of two Fractions.
+   * @param fraction the Fraction to subtract.
+   */
+  public Sub(fraction: Fraction): Fraction {
+    // normally should check if denominator or fraction.denominator is 0 but in our case
+    // a zero denominator doesn't make sense
+    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();
+    return this;
+  }
+
+  /**
+   * Creates a new Fraction which is half as long as this Fraction
+   */
+  public getHalfLength(): Fraction {
+    return new Fraction(this.WholeValue, 2).Add(new Fraction(this.Numerator, this.Denominator * 2));
+  }
+
+  /**
+   * Brute Force quanization by searching incremental with the numerator until the denominator is
+   * smaller/equal than the desired one.
+   * @param maxAllowedDenominator
+   */
+  public Quantize(maxAllowedDenominator: number): Fraction {
+    if (this.denominator <= maxAllowedDenominator) {
+      return this;
+    }
+
+    const upTestFraction: Fraction = new Fraction(this.numerator + 1, this.denominator, this.wholeValue);
+
+    while (upTestFraction.Denominator > maxAllowedDenominator) {
+      upTestFraction.Numerator++;
+    }
+
+    if (this.numerator > this.denominator) {
+      const downTestFraction: Fraction = new Fraction(this.numerator - 1, this.denominator, this.wholeValue);
+
+      while (downTestFraction.Denominator > maxAllowedDenominator) {
+        downTestFraction.Numerator--;
+      }
+
+      if (downTestFraction.Denominator < upTestFraction.Denominator) {
+        return downTestFraction;
+      }
+    }
+    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 gt(frac: Fraction): boolean {
+    return !this.lte(frac);
+  }
+
+  public gte(frac: Fraction): boolean {
+    return !this.lt(frac);
+  }
+
+  //public Equals(f: Fraction): boolean {
+  //    if (ReferenceEquals(this, f))
+  //        return true;
+  //    if (ReferenceEquals(f, undefined))
+  //        return false;
+  //    return this.numerator * f.denominator === f.numerator * this.denominator;
+  //}
+
+  private setRealValue(): void {
+    this.realValue = this.wholeValue + this.numerator / this.denominator;
+  }
+
+  private simplify(): void {
+    // don't simplify in case of a GraceNote (need it in order to set the right symbol)
+    if (this.numerator === 0) {
+      this.denominator = 1;
+      return;
+    }
+
+    // normally should check if denominator or fraction.denominator is 0 but in our case a zero denominator
+    // doesn't make sense. Could probably be optimized
+    const i: number = Fraction.greatestCommonDenominator(Math.abs(this.numerator), Math.abs(this.denominator));
+
+    this.numerator /= i;
+    this.denominator /= i;
+
+    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;
+      }
+    }
+    if (this.denominator > Fraction.maximumAllowedNumber) {
+      const 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) {
+      const factor: number = this.numerator / Fraction.maximumAllowedNumber;
+      this.numerator = Math.round(this.numerator / factor);
+      this.denominator = Math.round(this.denominator / factor);
+    }
+  }
+
+  public static FloatInaccuracyTolerance: number = 0.0001; // inaccuracy allowed when comparing Fraction.RealValues, because of floating point inaccuracy
+
+  public isOnBeat(timeSignature: Fraction): boolean { // use sourceMeasure.ActiveTimeSignature as timeSignature
+      const beatDistance: number = this.distanceFromBeat(timeSignature);
+      return Math.abs(beatDistance) < Fraction.FloatInaccuracyTolerance;
+  }
+
+  public distanceFromBeat(timeSignature: Fraction): number {
+      const beatStep: Fraction = new Fraction(1, timeSignature.Denominator);
+      const distanceFromBeat: number = this.RealValue % beatStep.RealValue; // take modulo the beat value, e.g. 1/8 in a 3/8 time signature
+      return distanceFromBeat;
+  }
+
+
+  //private static equals(f1: Fraction, f2: Fraction): boolean {
+  //    return f1.numerator * f2.denominator === 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 = Math.round(value * d);
+  //        }
+  //        fraction = n / 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 = 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)
+  //    // 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
+}

+ 58 - 0
src/Common/DataObjects/Matrix2D.ts

@@ -0,0 +1,58 @@
+import { PointF2D } from "./PointF2D";
+
+export class Matrix2D {
+    private matrix: number[][];
+
+    constructor() {
+        this.matrix = [];
+        for (let i: number = 0; i < 2; i++) {
+            this.matrix[i] = [];
+            for (let j: number = 0; j < 2; j++) {
+                this.matrix[i][j] = 0;
+            }
+        }
+    }
+
+    public static getRotationMatrix(angle: number): Matrix2D {
+        const rotation: Matrix2D = new Matrix2D();
+        const cos: number = Math.cos(angle);
+        const sin: number = Math.sin(angle);
+        rotation.matrix[0][0] = cos;
+        rotation.matrix[0][1] = -sin;
+        rotation.matrix[1][0] = sin;
+        rotation.matrix[1][1] = cos;
+        return rotation;
+    }
+
+    public scalarMultiplication(scalar: number): void {
+        for (let i: number = 0; i < 2; i++) {
+            for (let j: number = 0; j < 2; j++) {
+                this.matrix[i][j] *= scalar;
+            }
+        }
+    }
+
+    public getTransposeMatrix(): Matrix2D {
+        const transpose: Matrix2D = new Matrix2D();
+        for (let i: number = 0; i < 2; i++) {
+            for (let j: number = 0; j < 2; j++) {
+                transpose.matrix[i][j] = this.matrix[j][i];
+            }
+        }
+        return transpose;
+    }
+
+    public vectorMultiplication(point: PointF2D): PointF2D {
+        const result: PointF2D = new PointF2D();
+        result.x = point.x * this.matrix[0][0] + point.y * this.matrix[0][1];
+        result.y = point.x * this.matrix[1][0] + point.y * this.matrix[1][1];
+        return result;
+    }
+
+    // public get Matrix(index: number): number[] {
+    //     return this.matrix[index];
+    // }
+    // public set Matrix(index: number, value: number[]): void {
+    //     this.matrix[index] = value;
+    // }
+}

+ 25 - 0
src/Common/DataObjects/MusicSheetErrors.ts

@@ -0,0 +1,25 @@
+// skeleton by Andrea
+
+export class MusicSheetErrors {
+    public measureErrors: { [n: number]: string[] } = {};
+
+    private errors: string[] = [];
+    private tempErrors: string[] = [];
+
+    public finalizeMeasure(measureNumber: number): void {
+        let list: string[] = this.measureErrors[measureNumber];
+        if (!list) {
+            list = [];
+        }
+        this.measureErrors[measureNumber] = list.concat(this.tempErrors);
+        this.tempErrors = [];
+    }
+
+    public pushMeasureError(errorMsg: string): void {
+        this.tempErrors.push(errorMsg);
+    }
+
+    public push(errorMsg: string): void {
+        this.errors.push(errorMsg);
+    }
+}

+ 76 - 0
src/Common/DataObjects/OSMDColor.ts

@@ -0,0 +1,76 @@
+/**
+ * Represents a color in RGBA
+ */
+export class OSMDColor {
+    public alpha: number;
+    public red: number;
+    public green: number;
+    public blue: number;
+
+    /*constructor(alpha: number, red: number, green: number, blue: number) {
+        this.alpha = alpha;
+        this.red = red;
+        this.green = green;
+        this.blue = blue;
+    }*/
+
+    /*
+     * Color names are based on the definitions at https://msdn.microsoft.com/de-de/library/aa358802(vs.85).aspx
+     * ...but changed a bit by the famous Mc Overacre
+     */
+    constructor(red: number, green: number, blue: number) {
+        this.alpha = 255;
+        this.red = red;
+        this.green = green;
+        this.blue = blue;
+    }
+    public static get Black(): OSMDColor {
+        return new OSMDColor(0, 0, 0);
+    }
+    public static get DeepSkyBlue(): OSMDColor {
+        return new OSMDColor(0, 191, 255);
+    }
+    public static get Green(): OSMDColor {
+        return new OSMDColor(20, 160, 20);
+    }
+    public static get Magenta(): OSMDColor {
+        return new OSMDColor(255, 0, 255);
+    }
+    public static get Orange(): OSMDColor {
+        return new OSMDColor(255, 128, 0);
+    }
+    public static get Red(): OSMDColor {
+        return new OSMDColor(240, 20, 20);
+    }
+    public static get Disabled(): OSMDColor {
+        return new OSMDColor(225, 225, 225);
+    }
+    public static get DarkBlue(): OSMDColor {
+        return new OSMDColor(0, 0, 140);
+    }
+
+    // For debugging:
+    public static get Debug1(): OSMDColor {
+        return new OSMDColor(200, 0, 140);
+    }
+    public static get Debug2(): OSMDColor {
+        return new OSMDColor(100, 100, 200);
+    }
+    public static get Debug3(): OSMDColor {
+        return new OSMDColor(0, 50, 140);
+    }
+
+    public toHexString(): string {
+        /* eslint-disable no-bitwise */
+        let hex: string = (this.red | 1 << 8).toString(16).slice(1) +
+                          (this.green | 1 << 8).toString(16).slice(1) +
+                          (this.blue | 1 << 8).toString(16).slice(1);
+        const a: string = (this.alpha | 1 << 8).toString(16).slice(1);
+        hex = hex + a;
+        return "#" + hex;
+      }
+
+    public toString(): string {
+        return "rgba(" + this.red + "," + this.green + "," + this.blue + "," + this.alpha + ")";
+    }
+}

+ 444 - 0
src/Common/DataObjects/Pitch.ts

@@ -0,0 +1,444 @@
+// The value of the enum indicates the number of halftoneSteps from one note to the next
+export enum NoteEnum {
+    C = 0,
+    D = 2,
+    E = 4,
+    F = 5,
+    G = 7,
+    A = 9,
+    B = 11
+}
+
+/** Describes Accidental types.
+ * Do not use the number values of these enum members directly for calculation anymore.
+ * To use these for pitch calculation, use pitch.AccidentalHalfTones()
+ * or Pitch.HalfTonesFromAccidental(accidentalEnum).
+ */
+export enum AccidentalEnum {
+    SHARP,
+    FLAT,
+    NONE,
+    NATURAL,
+    DOUBLESHARP,
+    DOUBLEFLAT,
+    TRIPLESHARP,
+    TRIPLEFLAT,
+    QUARTERTONESHARP,
+    QUARTERTONEFLAT,
+}
+
+// This class represents a musical note. The middle A (440 Hz) lies in the octave with the value 1.
+export class Pitch {
+    public static pitchEnumValues: NoteEnum[] = [
+        NoteEnum.C, NoteEnum.D, NoteEnum.E, NoteEnum.F, NoteEnum.G, NoteEnum.A, NoteEnum.B,
+    ];
+
+    private static halftoneFactor: number = 12 / (Math.LN2 / Math.LN10);
+    private static octXmlDiff: number = 3;
+
+    // private _sourceOctave: number;
+    // private _sourceFundamentalNote: NoteEnum;
+    // private _sourceAccidental: AccidentalEnum = AccidentalEnum.NONE;
+    private octave: number;
+    private fundamentalNote: NoteEnum;
+    private accidental: AccidentalEnum = AccidentalEnum.NONE;
+    private frequency: number;
+    private halfTone: number;
+
+    public static getNoteEnumString(note: NoteEnum): string {
+        switch (note) {
+            case NoteEnum.C:
+                return "C";
+            case NoteEnum.D:
+                return "D";
+            case NoteEnum.E:
+                return "E";
+            case NoteEnum.F:
+                return "F";
+            case NoteEnum.G:
+                return "G";
+            case NoteEnum.A:
+                return "A";
+            case NoteEnum.B:
+                return "B";
+            default:
+                return "";
+        }
+    }
+
+    /** This method goes x steps from a NoteEnum on a keyboard.
+     * E.g. Two steps to the left (-2) from a D is a B.
+     * Two steps to the right from an A is a C. */
+    public static stepFromNoteEnum(noteEnum: NoteEnum, step: number): [NoteEnum, number] {
+        const enums: NoteEnum[] = Pitch.pitchEnumValues;
+        const originalIndex: number = enums.indexOf(noteEnum);
+        let octaveShift: number = 0;
+        let newIndex: number = originalIndex + step % enums.length; // modulo only handles positive overflow
+        if (originalIndex + step > enums.length - 1) {
+            octaveShift = 1;
+        }
+        if (newIndex < 0) {
+            newIndex = enums.length + newIndex; // handle underflow, e.g. - 1: enums.length + (-1) = last element
+            octaveShift = -1;
+        }
+        return [enums[newIndex], octaveShift];
+    }
+
+    /**
+     * @param the input pitch
+     * @param the number of halftones to transpose with
+     * @returns ret[0] = the transposed fundamental.
+     * ret[1] = the octave shift (not the new octave!)
+     * @constructor
+     */
+    public static CalculateTransposedHalfTone(pitch: Pitch, transpose: number): { halftone: number, overflow: number } {
+        const newHalfTone: number = <number>pitch.fundamentalNote + pitch.AccidentalHalfTones + transpose;
+        return Pitch.WrapAroundCheck(newHalfTone, 12);
+    }
+
+    public static WrapAroundCheck(value: number, limit: number): { halftone: number, overflow: number } {
+        let overflow: number = 0;
+
+        while (value < 0) {
+            value += limit;
+            overflow--; // the octave change
+        }
+        while (value >= limit) {
+            value -= limit;
+            overflow++; // the octave change
+        }
+        return {overflow: overflow, halftone: value};
+    }
+
+    //public static calcFrequency(pitch: Pitch): number;
+
+    //public static calcFrequency(fractionalKey: number): number;
+
+    public static calcFrequency(obj: Pitch|number): number {
+        let octaveSteps: number = 0;
+        let halfToneSteps: number;
+        if (obj instanceof Pitch) {
+            // obj is a pitch
+            const pitch: Pitch = obj;
+            octaveSteps = pitch.octave - 1;
+            halfToneSteps = <number>pitch.fundamentalNote - <number>NoteEnum.A + pitch.AccidentalHalfTones;
+        } else if (typeof obj === "number") {
+            // obj is a fractional key
+            const fractionalKey: number = obj;
+            halfToneSteps = fractionalKey - 57.0;
+        }
+        // Return frequency:
+        return 440.0 * Math.pow(2, octaveSteps) * Math.pow(2, halfToneSteps / 12.0);
+    }
+
+    public static calcFractionalKey(frequency: number): number {
+        // Return half-tone frequency:
+        return Math.log(frequency / 440.0) / Math.LN10 * Pitch.halftoneFactor + 57.0;
+    }
+
+    public static fromFrequency(frequency: number): Pitch {
+        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) {
+            fundamentalNote = <NoteEnum>(halftone - 1);
+            accidental = AccidentalEnum.SHARP;
+        }
+        return new Pitch(fundamentalNote, octave, accidental);
+    }
+
+    public static fromHalftone(halftone: number): Pitch {
+        const octave: number = Math.floor(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) {
+            fundamentalNote = <NoteEnum>(halftoneInOctave - 1);
+            accidental = AccidentalEnum.SHARP;
+        }
+        return new Pitch(fundamentalNote, octave, accidental);
+    }
+
+    public static ceiling(halftone: number): NoteEnum {
+        halftone = (halftone) % 12;
+        let fundamentalNote: NoteEnum = <NoteEnum>halftone;
+        if (this.pitchEnumValues.indexOf(fundamentalNote) === -1) {
+            fundamentalNote = <NoteEnum>(halftone + 1);
+        }
+        return fundamentalNote;
+    }
+
+    public static floor(halftone: number): NoteEnum {
+        halftone = halftone % 12;
+        let fundamentalNote: NoteEnum = <NoteEnum>halftone;
+        if (this.pitchEnumValues.indexOf(fundamentalNote) === -1) {
+            fundamentalNote = <NoteEnum>(halftone - 1);
+        }
+        return fundamentalNote;
+    }
+
+    constructor(fundamentalNote: NoteEnum, octave: number, accidental: AccidentalEnum) {
+        this.fundamentalNote = fundamentalNote;
+        this.octave = octave;
+        this.accidental = accidental;
+        this.halfTone = <number>(fundamentalNote) + (octave + Pitch.octXmlDiff) * 12 +
+            Pitch.HalfTonesFromAccidental(accidental);
+        this.frequency = Pitch.calcFrequency(this);
+    }
+
+    /** Turns an AccidentalEnum into half tone steps for pitch calculation.
+     *
+     */
+    public static HalfTonesFromAccidental(accidental: AccidentalEnum): number {
+        // about equal performance to hashmap/dictionary. could be turned into hashmap for convenience
+        // switch is very slightly faster, but both are negligibly short anyways.
+        switch (accidental) {
+            // ordered from most to least common to improve average runtime
+            case AccidentalEnum.NONE:
+                return 0;
+            case AccidentalEnum.SHARP:
+                return 1;
+            case AccidentalEnum.FLAT:
+                return -1;
+            case AccidentalEnum.NATURAL:
+                return 0;
+            case AccidentalEnum.DOUBLESHARP:
+                return 2;
+            case AccidentalEnum.DOUBLEFLAT:
+                return -2;
+            case AccidentalEnum.QUARTERTONESHARP:
+                return 0.5;
+            case AccidentalEnum.QUARTERTONEFLAT:
+                return -0.5;
+            case AccidentalEnum.TRIPLESHARP: // very rare, in some classical pieces
+                return 3;
+            case AccidentalEnum.TRIPLEFLAT:
+                return -3;
+            default:
+                throw new Error("Unhandled AccidentalEnum value");
+                // return 0;
+        }
+    }
+
+    public static AccidentalFromHalfTones(halfTones: number): AccidentalEnum {
+        switch (halfTones) {
+            case 0:
+                // for enharmonic change, we won't get a Natural accidental. Maybe there are edge cases though?
+                return AccidentalEnum.NONE;
+            case 1:
+                return AccidentalEnum.SHARP;
+            case -1:
+                return AccidentalEnum.FLAT;
+            case 2:
+                return AccidentalEnum.DOUBLESHARP;
+            case -2:
+                return AccidentalEnum.DOUBLEFLAT;
+            case 0.5:
+                return AccidentalEnum.QUARTERTONESHARP;
+            case -0.5:
+                return AccidentalEnum.QUARTERTONEFLAT;
+            case 3:
+                return AccidentalEnum.TRIPLESHARP;
+            case -3:
+                return AccidentalEnum.TRIPLEFLAT;
+            default:
+                if (halfTones > 0 && halfTones < 1) {
+                    return AccidentalEnum.QUARTERTONESHARP;
+                } else if (halfTones < 0 && halfTones > -1) {
+                    return AccidentalEnum.QUARTERTONEFLAT;
+                }
+                // potentially unhandled or broken accidental halfTone value
+                return AccidentalEnum.QUARTERTONESHARP; // to signal unhandled value
+        }
+    }
+
+    /**
+     * Converts AccidentalEnum to a string which represents an accidental in VexFlow
+     * Can also be useful in other cases, but has to match Vexflow accidental codes.
+     * @param accidental
+     * @returns {string} Vexflow Accidental code
+     */
+    public static accidentalVexflow(accidental: AccidentalEnum): string {
+        let acc: string;
+        switch (accidental) {
+            case AccidentalEnum.NATURAL:
+                acc = "n";
+                break;
+            case AccidentalEnum.FLAT:
+                acc = "b";
+                break;
+            case AccidentalEnum.SHARP:
+                acc = "#";
+                break;
+            case AccidentalEnum.DOUBLESHARP:
+                acc = "##";
+                break;
+            case AccidentalEnum.TRIPLESHARP:
+                acc = "++";
+                break;
+            case AccidentalEnum.DOUBLEFLAT:
+                acc = "bb";
+                break;
+            case AccidentalEnum.TRIPLEFLAT:
+                acc = "bbs"; // there is no "bbb" in VexFlow yet, unfortunately.
+                break;
+            case AccidentalEnum.QUARTERTONESHARP:
+                acc = "+";
+                break;
+            case AccidentalEnum.QUARTERTONEFLAT:
+                acc = "d";
+                break;
+            default:
+        }
+        return acc;
+    }
+
+    public get AccidentalHalfTones(): number {
+        return Pitch.HalfTonesFromAccidental(this.accidental);
+    }
+
+    public get Octave(): number {
+        return this.octave;
+    }
+
+    public get FundamentalNote(): NoteEnum {
+        return this.fundamentalNote;
+    }
+
+    public get Accidental(): AccidentalEnum {
+        return this.accidental;
+    }
+
+    public get Frequency(): number {
+        return this.frequency;
+    }
+
+    public static get OctaveXmlDifference(): number {
+        return Pitch.octXmlDiff;
+    }
+
+    public getHalfTone(): number {
+        return this.halfTone;
+    }
+
+    // This method returns a new Pitch transposed by the given factor
+    public getTransposedPitch(factor: number): Pitch {
+        if (factor > 12) {
+            throw new Error("rewrite this method to handle bigger octave changes or don't use is with bigger octave changes!");
+        }
+        if (factor > 0) {
+            return this.getHigherPitchByTransposeFactor(factor);
+        }
+        if (factor < 0) {
+            return this.getLowerPitchByTransposeFactor(-factor);
+        }
+        return this;
+    }
+
+    public DoEnharmonicChange(): void {
+        switch (this.accidental) {
+            case AccidentalEnum.FLAT:
+            case AccidentalEnum.DOUBLEFLAT:
+                this.fundamentalNote = this.getPreviousFundamentalNote(this.fundamentalNote);
+                this.accidental = Pitch.AccidentalFromHalfTones(this.halfTone - (<number>(this.fundamentalNote) +
+                (this.octave + Pitch.octXmlDiff) * 12));
+                break;
+            case AccidentalEnum.SHARP:
+            case AccidentalEnum.DOUBLESHARP:
+                this.fundamentalNote = this.getNextFundamentalNote(this.fundamentalNote);
+                this.accidental = Pitch.AccidentalFromHalfTones(this.halfTone - (<number>(this.fundamentalNote) +
+                (this.octave + Pitch.octXmlDiff) * 12));
+                break;
+            default:
+                return;
+        }
+    }
+
+    public ToString(): string {
+        let accidentalString: string = Pitch.accidentalVexflow(this.accidental);
+        if (!accidentalString) {
+            accidentalString = "";
+        }
+        return "Key: " + Pitch.getNoteEnumString(this.fundamentalNote) + accidentalString +
+        ", Note: " + this.fundamentalNote + ", octave: " + this.octave.toString();
+    }
+
+    public OperatorEquals(p2: Pitch): boolean {
+        const p1: Pitch = this;
+        // if (ReferenceEquals(p1, p2)) {
+        //     return true;
+        // }
+        if (!p1 || !p2) {
+            return false;
+        }
+        return (p1.FundamentalNote === p2.FundamentalNote && p1.Octave === p2.Octave && p1.Accidental === p2.Accidental);
+    }
+
+    public OperatorNotEqual(p2: Pitch): boolean {
+        const p1: Pitch = this;
+        return !(p1 === p2);
+    }
+
+    //These don't take into account accidentals! which isn't needed for our current purpose
+    public OperatorFundamentalGreaterThan(p2: Pitch): boolean {
+        const p1: Pitch = this;
+        if (p1.Octave === p2.Octave) {
+            return p1.FundamentalNote > p2.FundamentalNote;
+        } else {
+            return p1.Octave > p2.Octave;
+        }
+    }
+
+    public OperatorFundamentalLessThan(p2: Pitch): boolean {
+        const p1: Pitch = this;
+        if (p1.Octave === p2.Octave) {
+            return p1.FundamentalNote < p2.FundamentalNote;
+        } else {
+            return p1.Octave < p2.Octave;
+        }
+    }
+
+    // This method returns a new Pitch factor-Halftones higher than the current Pitch
+    private getHigherPitchByTransposeFactor(factor: number): Pitch {
+        const noteEnumIndex: number = Pitch.pitchEnumValues.indexOf(this.fundamentalNote);
+        let newOctave: number = this.octave;
+        let newNoteEnum: NoteEnum;
+        if (noteEnumIndex + factor > Pitch.pitchEnumValues.length - 1) {
+            newNoteEnum = Pitch.pitchEnumValues[noteEnumIndex + factor - Pitch.pitchEnumValues.length];
+            newOctave++;
+        } else {
+            newNoteEnum = Pitch.pitchEnumValues[noteEnumIndex + factor];
+        }
+        return new Pitch(newNoteEnum, newOctave, AccidentalEnum.NONE);
+    }
+
+    private getLowerPitchByTransposeFactor(factor: number): Pitch {
+        const noteEnumIndex: number = Pitch.pitchEnumValues.indexOf(this.fundamentalNote);
+        let newOctave: number = this.octave;
+        let newNoteEnum: NoteEnum;
+        if (noteEnumIndex - factor < 0) {
+            newNoteEnum = Pitch.pitchEnumValues[Pitch.pitchEnumValues.length + noteEnumIndex - factor];
+            newOctave--;
+        } else {
+            newNoteEnum = Pitch.pitchEnumValues[noteEnumIndex - factor];
+        }
+        return new Pitch(newNoteEnum, newOctave, AccidentalEnum.NONE);
+    }
+
+    private getNextFundamentalNote(fundamental: NoteEnum): NoteEnum {
+        let i: number = Pitch.pitchEnumValues.indexOf(fundamental);
+        i = (i + 1) % Pitch.pitchEnumValues.length;
+        return Pitch.pitchEnumValues[i];
+    }
+
+    private getPreviousFundamentalNote(fundamental: NoteEnum): NoteEnum {
+        const i: number = Pitch.pitchEnumValues.indexOf(fundamental);
+        if (i > 0) {
+            return Pitch.pitchEnumValues[i - 1];
+        } else {
+            return Pitch.pitchEnumValues[Pitch.pitchEnumValues.length - 1];
+        }
+    }
+}

+ 84 - 0
src/Common/DataObjects/PlaybackSettings.ts

@@ -0,0 +1,84 @@
+import { Fraction } from "./Fraction";
+
+export class PlaybackSettings {
+    private beatsPerMinute: number;
+    private beatLengthInMilliseconds: number;
+    private beatRealValue: number;
+    public rhythm: Fraction;
+
+    /** The denominator of the fraction of the rhythm is 1 beat long
+     * --> By knowing the rhythm and the beatsPerMinute the length of notes can be calculated.
+     */
+    constructor(rhythm: Fraction = new Fraction(), beatsPerMinute: number = 0) {
+        this.rhythm = rhythm;
+        this.beatsPerMinute = beatsPerMinute;
+        // 1 minute in milliseconds/beatsPerMinute
+        this.beatLengthInMilliseconds = 60000.0 / beatsPerMinute;
+        // the denominator in the rhythm is the unit for the beats in a music sheet (it is 1 beat long)
+        this.beatRealValue = 1.0 / 4.0;
+    }
+
+    public static createFrom(from: PlaybackSettings): PlaybackSettings {
+        return new PlaybackSettings(from.Rhythm, from.BeatsPerMinute);
+    }
+
+    public get BeatsPerMinute(): number {
+        return this.beatsPerMinute;
+    }
+    public set BeatsPerMinute(value: number) {
+        this.beatsPerMinute = value;
+        // 1 minute in milliseconds/beatsPerMinute
+        this.beatLengthInMilliseconds = 60000.0 / this.beatsPerMinute;
+    }
+    public get Rhythm(): Fraction {
+        return this.rhythm;
+    }
+    public set Rhythm(value: Fraction) {
+        this.rhythm = value;
+        // TODO: Below is commented out in original C# code, delete here?
+        // the denominator in the rhythm is the unit for the beats in a music sheet (it is 1 beat long)
+        // this.beatRealValue = 1.0 / this.rhythm.Denominator;
+    }
+    public get BeatRealValue(): number {
+        return this.beatRealValue;
+    }
+    public get BeatLengthInMilliseconds(): number {
+        return this.beatLengthInMilliseconds;
+    }
+    // TODO: Following overload is handled below, check if it does what it is supposed to do
+    // public getDurationInMilliseconds(duration: Fraction): number {
+    //     var ret: number = duration.RealValue * this.BeatLengthInMilliseconds / this.beatRealValue;
+    //     return ret;
+    // }
+    // public getDurationInMilliseconds(durationRealValue: number): number {
+    //     var ret: number = durationRealValue * this.BeatLengthInMilliseconds / this.beatRealValue;
+    //     return ret;
+    // }
+    public getDurationInMilliseconds(duration: number | Fraction): number {
+        const value: number = typeof duration === "number" ? duration : duration.RealValue;
+        const ret: number = value * this.BeatLengthInMilliseconds / this.beatRealValue;
+        return ret;
+    }
+    public getDurationAsNoteDuration(milliseconds: number, fractionPrecision: number = 1024): Fraction {
+        // 1 beat can be mapped to 1/denominator of the rhythm.
+        const numBeats: number = milliseconds / (this.BeatLengthInMilliseconds);
+        let numerator: number = <number>Math.floor(numBeats);
+
+        // TODO: Comment in line below from original code, keep it?
+        // here is the problem: this.rhythm.Denominator
+
+        const ret: Fraction = new Fraction(numerator, 4);
+        // TODO: Line below commented out in original code, port to TS?
+        //Console.WriteLine($"milliseconds: {milliseconds}, BeatLengthInMilliseconds: {BeatLengthInMilliseconds}, LINEBREAK for linter
+        //numBeats: {numBeats}, DurationFraction: {ret}");
+        // now approximate as good as possible by using fractionPrecision as smallest fraction
+        const tmp: number = numBeats - numerator;
+        numerator = <number>Math.round(tmp / (1.0 / fractionPrecision) / 4);
+        if (numerator === 0 && milliseconds > 0) {
+            numerator = 1;
+        }
+        // add the 2 fractions
+        ret.Add(new Fraction(numerator, fractionPrecision));
+        return ret;
+    }
+}

+ 20 - 0
src/Common/DataObjects/PointF2D.ts

@@ -0,0 +1,20 @@
+// Represent a point on a plane, with (x,y) coordinates
+export class PointF2D {
+    public x: number = 0;
+    public y: number = 0;
+
+    constructor(x: number = 0, y: number = 0) {
+        this.x = x;
+        this.y = y;
+    }
+
+    public static get Empty(): PointF2D {
+        return new PointF2D();
+    }
+    public static pointsAreEqual(p1: PointF2D, p2: PointF2D): boolean {
+        return (p1.x === p2.x && p1.y === p2.y);
+    }
+    public ToString(): string {
+        return "[" + this.x + ", " + this.y + "]";
+    }
+}

+ 36 - 0
src/Common/DataObjects/RectangleF2D.ts

@@ -0,0 +1,36 @@
+import {SizeF2D} from "./SizeF2D";
+import {PointF2D} from "./PointF2D";
+
+/**
+ * Represent a rectangle on a plane
+ */
+export class RectangleF2D {
+    public x: number = 0;
+    public y: number = 0;
+    public width: number = 0;
+    public height: number = 0;
+
+    /**
+     *
+     * @param x
+     * @param y
+     * @param width
+     * @param height
+     */
+    constructor(x: number, y: number, width: number, height: number) {
+        this.x = x;
+        this.y = y;
+        this.width = width;
+        this.height = height;
+    }
+
+    public static createFromLocationAndSize(location: PointF2D, size: SizeF2D): RectangleF2D {
+        return new RectangleF2D(location.x, location.y, size.width, size.height);
+    }
+    public get Location(): PointF2D {
+        return new PointF2D(this.x, this.y);
+    }
+    public get Size(): SizeF2D {
+        return new SizeF2D(this.width, this.height);
+    }
+}

+ 12 - 0
src/Common/DataObjects/SizeF2D.ts

@@ -0,0 +1,12 @@
+/**
+ * Represent the size of a 2D object, with (width, height)
+ */
+export class SizeF2D {
+    public width: number;
+    public height: number;
+
+    constructor(width: number = 0, height: number = 0) {
+        this.width = width;
+        this.height = height;
+    }
+}

+ 10 - 0
src/Common/DataObjects/index.ts

@@ -0,0 +1,10 @@
+// created from 'create-ts-index'
+
+export * from "./Fraction";
+export * from "./Matrix2D";
+export * from "./MusicSheetErrors";
+export * from "./OSMDColor";
+export * from "./Pitch";
+export * from "./PointF2D";
+export * from "./RectangleF2D";
+export * from "./SizeF2D";

+ 18 - 0
src/Common/Enums/FontStyles.ts

@@ -0,0 +1,18 @@
+/**
+ * The styles available to write text on the music sheet
+ */
+export enum FontStyles {
+    Regular = 0,
+    Bold = 1,
+    Italic = 2,
+    BoldItalic = 3,
+    Underlined = 4
+}
+
+export const FontStyleString: Object = {
+    Bold: 1,
+    BoldItalic: 3,
+    Italic: 2,
+    Regular: 0,
+    Underlined: 4
+};

+ 20 - 0
src/Common/Enums/Fonts.ts

@@ -0,0 +1,20 @@
+/**
+ * The fonts available for writing on the sheet music
+ */
+export enum Fonts {
+    TimesNewRoman,
+    Kokila,
+    Gonville
+}
+
+export const FontString: Object = {
+    Gonville: 2,
+    Kokila: 1,
+    TimesNewRoman: 0
+};
+
+export const FontStringNames: Object = {
+    0: "Times New Roman",
+    1: "Kokila",
+    2: "Gonville"
+};

+ 7 - 0
src/Common/Enums/InteractionType.ts

@@ -0,0 +1,7 @@
+export enum InteractionType {
+    SingleTouch,
+    DoubleTouch,
+    TouchUp,
+    TouchDown,
+    Move
+}

+ 10 - 0
src/Common/Enums/PsEnums.ts

@@ -0,0 +1,10 @@
+export enum PlaybackState {
+    Stopped,
+    Running
+}
+
+export enum MessageBoxType {
+    Info,
+    Warning,
+    Error
+}

+ 43 - 0
src/Common/Enums/TextAlignment.ts

@@ -0,0 +1,43 @@
+/**
+ * The Alignment of a TextLabel.
+ * Specifically the label's position coordinates within the Bounding Box.
+ * For LeftBottom, the label's position is at the left bottom corner of its Bounding Box.
+ * (used for example with title, composer, author, etc.)
+ * (see Show Bounding Box For -> Labels in the local demo)
+ */
+export enum TextAlignmentEnum {
+    LeftTop,
+    LeftCenter,
+    LeftBottom,
+    CenterTop,
+    CenterCenter,
+    CenterBottom,
+    RightTop,
+    RightCenter,
+    RightBottom
+}
+/*
+ * TODO this could be split into two alignments, e.g. <Left, Top> for LeftTop.
+ * A function like IsLeft would be easier with the split.
+ * On the other hand, accessing these values will be more complex
+*/
+
+export class TextAlignment {
+    public static IsLeft(textAlignment: TextAlignmentEnum): boolean {
+        return textAlignment === TextAlignmentEnum.LeftTop
+            || textAlignment === TextAlignmentEnum.LeftCenter
+            || textAlignment === TextAlignmentEnum.LeftBottom;
+    }
+
+    public static IsCenterAligned(textAlignment: TextAlignmentEnum): boolean {
+        return textAlignment === TextAlignmentEnum.CenterTop
+            || textAlignment === TextAlignmentEnum.CenterCenter
+            || textAlignment === TextAlignmentEnum.CenterBottom;
+    }
+
+    public static IsRight(textAlignment: TextAlignmentEnum): boolean {
+        return textAlignment === TextAlignmentEnum.RightTop
+            || textAlignment === TextAlignmentEnum.RightCenter
+            || textAlignment === TextAlignmentEnum.RightBottom;
+    }
+}

+ 10 - 0
src/Common/Enums/TieTypes.ts

@@ -0,0 +1,10 @@
+/**
+ * The types of ties available
+ */
+export enum TieTypes {
+    "SIMPLE" = "",
+    "HAMMERON" = "H",
+    "PULLOFF" = "P",
+    "SLIDE" = "S",
+    "TAPPING" = "T"
+}

+ 6 - 0
src/Common/Enums/index.ts

@@ -0,0 +1,6 @@
+// created from 'create-ts-index'
+
+export * from "./FontStyles";
+export * from "./Fonts";
+export * from "./TextAlignment";
+export * from "./TieTypes";

+ 80 - 0
src/Common/FileIO/Mxl.ts

@@ -0,0 +1,80 @@
+import { IXmlElement } from "./Xml";
+import JSZip from "jszip";
+
+/**
+ * Some helper methods to handle MXL files.
+ */
+export class MXLHelper {
+    /**
+     *
+     * @param data
+     * @returns {Promise<IXmlElement>}
+     * @constructor
+     */
+    public static MXLtoIXmlElement(data: string): Promise<IXmlElement> {
+        // starting with jszip 3.4.0, JSZip.JSZip is not found,
+        //    probably because of new possibly conflicting TypeScript definitions
+        const zip: JSZip = new JSZip();
+        // asynchronously load zip file and process it - with Promises
+        const zipLoadedAsync: Promise<JSZip> = zip.loadAsync(data);
+        const text: Promise<string> = zipLoadedAsync.then(
+            (_: JSZip) => {
+                return zip.file("META-INF/container.xml").async("text");
+            },
+            (err: any) => {
+                throw err;
+            }
+        );
+        return text.then(
+            (content: string) => {
+                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("text");
+            },
+            (err: any) => {
+                throw err;
+            }
+        ).then(
+            (content: string) => {
+                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) => {
+                throw err;
+            }
+        ).then(
+            (content: IXmlElement) => {
+                return content;
+            },
+            (err: any) => {
+                throw new Error("extractSheetFromMxl: " + err.message);
+            }
+        );
+    }
+
+    public static MXLtoXMLstring(data: string): Promise<string> {
+        const zip:  JSZip = new JSZip();
+        // asynchronously load zip file and process it - with Promises
+        return zip.loadAsync(data).then(
+            (_: any) => {
+                return zip.file("META-INF/container.xml").async("text");
+            },
+            (err: any) => {
+                throw err;
+            }
+        ).then(
+            (content: string) => {
+                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("text");
+            },
+            (err: any) => {
+                throw err;
+            }
+        );
+    }
+}

+ 106 - 0
src/Common/FileIO/Xml.ts

@@ -0,0 +1,106 @@
+/**
+ * IXmlAttribute is just the standard Attr
+ */
+export type IXmlAttribute = Attr;
+
+/**
+ * Just a wrapper for an XML Element object.
+ * It facilitates handling of XML elements by OSMD
+ */
+export class IXmlElement {
+    public name: string;
+    public value: string;
+    public hasAttributes: boolean = false;
+    public firstAttribute: IXmlAttribute;
+    public hasElements: boolean;
+
+    private attrs: IXmlAttribute[];
+    private elem: Element;
+
+    /**
+     * Wraps 'elem' Element in a IXmlElement
+     * @param elem
+     */
+    constructor(elem: Element) {
+        if (!elem) {
+            throw new Error("IXmlElement: expected Element, got undefined");
+        }
+        this.elem = elem;
+        this.name = elem.nodeName.toLowerCase();
+
+        if (elem.hasAttributes()) {
+            this.hasAttributes = true;
+            this.firstAttribute = elem.attributes[0];
+        }
+        this.hasElements = elem.hasChildNodes();
+        // Look for a value
+        if (elem.childNodes.length === 1 && elem.childNodes[0].nodeType === Node.TEXT_NODE) {
+            this.value = elem.childNodes[0].nodeValue;
+        } else {
+            this.value = "";
+        }
+    }
+
+    /**
+     * Get the attribute with the given name
+     * @param attributeName
+     * @returns {Attr}
+     */
+    public attribute(attributeName: string): IXmlAttribute {
+        return this.elem.attributes.getNamedItem(attributeName);
+    }
+
+    /**
+     * Get all attributes
+     * @returns {IXmlAttribute[]}
+     */
+    public attributes(): IXmlAttribute[] {
+        if (!this.attrs) {
+            const attributes: NamedNodeMap = this.elem.attributes;
+            const attrs: IXmlAttribute[] = [];
+            for (let i: number = 0; i < attributes.length; i += 1) {
+                attrs.push(attributes[i]);
+            }
+            this.attrs = attrs;
+        }
+        return this.attrs;
+    }
+
+    /**
+     * Get the first child element with the given node name
+     * @param elementName
+     * @returns {IXmlElement}
+     */
+    public element(elementName: string): IXmlElement {
+        const nodes: NodeList = this.elem.childNodes;
+        for (let i: number = 0, length: number = nodes.length; i < length; i += 1) {
+            const node: Node = nodes[i];
+            if (node.nodeType === Node.ELEMENT_NODE && node.nodeName.toLowerCase() === elementName) {
+                return new IXmlElement(node as Element);
+            }
+        }
+    }
+
+    /**
+     * Get the children with the given node name (if given, otherwise all child elements)
+     * @param nodeName
+     * @returns {IXmlElement[]}
+     */
+    public elements(nodeName?: string): IXmlElement[] {
+        const nodes: NodeList = this.elem.childNodes;
+        const ret: IXmlElement[] = [];
+        const nameUnset: boolean = !nodeName;
+        if (!nameUnset) {
+            nodeName = nodeName.toLowerCase();
+        }
+        for (let i: number = 0; i < nodes.length; i += 1) {
+            const node: Node = nodes[i];
+            if (node.nodeType === Node.ELEMENT_NODE &&
+                (nameUnset || node.nodeName.toLowerCase() === nodeName)
+            ) {
+                ret.push(new IXmlElement(node as Element));
+            }
+        }
+        return ret;
+    }
+}

+ 4 - 0
src/Common/FileIO/index.ts

@@ -0,0 +1,4 @@
+// created from 'create-ts-index'
+
+export * from "./Mxl";
+export * from "./Xml";

+ 15 - 0
src/Common/Interfaces/AClassHierarchyTrackable.ts

@@ -0,0 +1,15 @@
+export abstract class AClassHierarchyTrackable {
+    //TODO: This pattern doesn't account for interfaces, only classes.
+    //At present, it seems that interfaces need tested manually when they are needed.
+    //Perhaps there is a better solution, but right now I don't see it. This is fine for our requirements currently
+    public isInstanceOfClass(className: string): boolean {
+        let proto: any = this.constructor.prototype;
+        while (proto) {
+            if (className === proto.constructor.name) {
+                return true;
+            }
+            proto = proto.__proto__;
+        }
+        return false;
+    }
+}

+ 12 - 0
src/Common/Interfaces/IAudioMetronomePlayer.ts

@@ -0,0 +1,12 @@
+export interface IAudioMetronomePlayer {
+    /**
+     * Play the sound for the first beat within the measure
+     * @param volume relative volume ranging from 0.0 - 1.0
+     */
+    playFirstBeatSample(volume: number): void;
+    /**
+     * Play the sound for all but the first beat within the measure
+     * @param volume relative volume ranging from 0.0 - 1.0
+     */
+    playBeatSample(volume: number): void;
+}

+ 36 - 0
src/Common/Interfaces/IAudioPlayer.ts

@@ -0,0 +1,36 @@
+import { MidiInstrument } from "../../MusicalScore/VoiceData/Instructions/ClefInstruction";
+
+export interface IAudioPlayer<TSoundFont> {
+  open(uniqueInstruments: number[], numberOfinstruments: number): void;
+
+  close(): void;
+
+  tuningChanged(tuningInHz: number): void;
+
+  playSound(instrumentChannel: number, key: number, volume: number, lengthInMs: number): void;
+
+  stopSound(instrumentChannel: number, volume: number): void;
+
+  setSound(instrumentChannel: number, soundId: MidiInstrument): Promise<void>;
+
+  setVolume(instrumentChannel: number, volume: number): void;
+
+  /**
+   * Sets the file path from where the sound font can be loaded
+   * @param soundId Sound identifier
+   * @param path File path for loading samples into memory
+   */
+  setSoundFontFilePath(soundId: MidiInstrument, path: string): void;
+
+  playbackHasStopped(): void;
+
+  loadSoundFont(soundId: MidiInstrument): Promise<TSoundFont>;
+
+  getMemoryLoadedSoundFonts(): TSoundFont[];
+
+  /*
+        List<MidiInstrument> AvailableSoundFonts { get; }
+        ISoundFont LoadSoundFont(MidiInstrument soundId);
+        void ReleaseSoundFont(MidiInstrument soundId);
+        */
+}

+ 3 - 0
src/Common/Interfaces/IControllerOutputListener.ts

@@ -0,0 +1,3 @@
+export interface IControllerOutputListener {
+    outputChanged(directlySet: boolean, currentValue: number, expectedValue: number): void;
+}

+ 9 - 0
src/Common/Interfaces/IDisplayInteractionListener.ts

@@ -0,0 +1,9 @@
+export interface IDisplayInteractionListener {
+    displaySizeChanged(width: number, height: number): void;
+    positionTouched(relativePositionX: number, relativePositionY: number): void;
+    positionDoubleTouched(relativePositionX: number, relativePositionY: number): void;
+    mouseDown(relativePositionX: number, relativePositionY: number, activateZoomOnRightMouseButton: boolean): void;
+    mouseUp(relativePositionX: number, relativePositionY: number): void;
+    mouseMove(relativePositionX: number, relativePositionY: number, deltaX: number, deltaY: number): void;
+    zoom(scale: number): void;
+}

+ 17 - 0
src/Common/Interfaces/IInstrument.ts

@@ -0,0 +1,17 @@
+import { MidiInstrument } from "../../MusicalScore/VoiceData/Instructions/ClefInstruction";
+
+export interface IInstrument /* extends IDisposable */ {
+    Id: number;
+    Audible: boolean;
+    Solo: boolean;
+    Mute: boolean;
+    Visible: boolean;
+    Highlight: boolean;
+    Following: boolean;
+    PitchMonitor: boolean;
+    Name: string;
+    Volume: number;
+    MidiInstrumentId: MidiInstrument;
+    InstrumentParameterChanged: any /* InstrumentParameterChangedDelegate */;
+    setInstrumentParameter(parameter: any /* InstrumentParameters */, value: Object): void;
+}

+ 4 - 0
src/Common/Interfaces/IMessageViewer.ts

@@ -0,0 +1,4 @@
+
+export interface IMessageViewer {
+    MessageOccurred: any; // ShowMessageDelegate;
+}

+ 10 - 0
src/Common/Interfaces/IPlaybackListener.ts

@@ -0,0 +1,10 @@
+import { Fraction } from "../DataObjects";
+import { CursorPosChangedData } from "../DataObjects/CursorPosChangedData";
+
+export interface IPlaybackListener {
+    cursorPositionChanged(timestamp: Fraction, data: CursorPosChangedData): void;
+    pauseOccurred(o: object): void;
+    selectionEndReached(o: object): void;
+    resetOccurred(o: object): void;
+    notesPlaybackEventOccurred(o: object): void;
+}

+ 9 - 0
src/Common/Interfaces/IPlaybackParametersListener.ts

@@ -0,0 +1,9 @@
+export interface IPlaybackParametersListener {
+    bpmChanged(newBpm: number): void;
+    volumeChanged(instrumentId: number, newVolume: number): void;
+    volumeMute(instrumentId: number): void;
+    volumeUnmute(instrumentId: number): void;
+    play(): void;
+    pause(): void;
+    reset(): void;
+}

+ 9 - 0
src/Common/Interfaces/IRepetition.ts

@@ -0,0 +1,9 @@
+export interface IRepetition {
+    DefaultNumberOfRepetitions: number;
+    FirstSourceMeasureNumber: number;
+    LastSourceMeasureNumber: number;
+    NumberOfEndings: number;
+    UserNumberOfRepetitions: number;
+    StartIndex: number;
+    EndIndex: number;
+}

+ 20 - 0
src/Common/Interfaces/ISettableInstrument.ts

@@ -0,0 +1,20 @@
+import { MidiInstrument } from "../../MusicalScore/VoiceData/Instructions/ClefInstruction";
+import { IInstrument } from "./IInstrument";
+
+export interface ISettableInstrument extends IInstrument {
+    Audible: boolean;
+    Solo: boolean;
+    Mute: boolean;
+    Visible: boolean;
+    Following: boolean;
+    PitchMonitor: boolean;
+    Highlight: boolean;
+    Volume: number;
+    MidiInstrumentId: MidiInstrument;
+    setVoiceAudible(voiceId: number, audible: boolean): void;
+    setStaffAudible(staffId: number, audible: boolean): void;
+    setVoiceFollowing(voiceId: number, follow: boolean): void;
+    setStaffFollow(staffId: number, follow: boolean): void;
+    setVoicePitchMonitor(voiceId: number, pitchMonitor: boolean): void;
+    setStaffPitchMonitor(staffId: number, pitchMonitor: boolean): void;
+}

+ 20 - 0
src/Common/Interfaces/ITimingSource.ts

@@ -0,0 +1,20 @@
+import { Fraction } from "../DataObjects";
+import { PlaybackSettings } from "../DataObjects/PlaybackSettings";
+
+export interface ITimingSource {
+    Settings: PlaybackSettings;
+    setBpm(bpm: number): void;
+    setTimeAndBpm(timestamp: Fraction, bpm: number): void;
+    /** @returns the time in milliseconds when the given timestamp will be reached. */
+    getWaitingTimeForTimestampInMs(timestamp: Fraction): number;
+    getDurationInMs(duration: Fraction): number;
+    getCurrentTimeInMs(): number;
+    getCurrentTimestamp(): Fraction;
+    /** @returns Returns the current audio timestamp as fraction, but revised by the audio delay of the system (e.g. a constant value is subtracted). */
+    getCurrentAudioDelayRevisedTimestamp(): Fraction;
+    getTimestampForTimeInMs(timesInMs: number): Fraction;
+    getDuration(milliseconds: number): Fraction;
+    start(): void;
+    pause(): void;
+    reset(): void;
+}

+ 6 - 0
src/Common/Interfaces/IUserDisplayInteractionListener.ts

@@ -0,0 +1,6 @@
+import { PointF2D } from "../DataObjects";
+import { InteractionType } from "../Enums/InteractionType";
+
+export interface IUserDisplayInteractionListener {
+    userDisplayInteraction(relativePosition: PointF2D, positionInSheetUnits: PointF2D, type: InteractionType): void;
+}

+ 12 - 0
src/Common/Interfaces/IZoomView.ts

@@ -0,0 +1,12 @@
+export interface IZoomView {
+    /**
+     * @param offsetX x offset in unit coord space
+     * @param rangeX x range in unit coord space
+     */
+    viewportXChanged(offsetX: number, rangeX: number): void;
+    /**
+     * @param offsetY y offset in unit coord space
+     * @param rangeY y range in unit coord space
+     */
+    viewportYChanged(offsetY: number, rangeY: number): void;
+}

+ 14 - 0
src/Common/Interfaces/index.ts

@@ -0,0 +1,14 @@
+export * from "./AClassHierarchyTrackable";
+export * from "./IAudioMetronomePlayer";
+export * from "./IAudioPlayer";
+export * from "./IControllerOutputListener";
+export * from "./IDisplayInteractionListener";
+export * from "./IInstrument";
+export * from "./IMessageViewer";
+export * from "./IPlaybackListener";
+export * from "./IPlaybackParametersListener";
+export * from "./IRepetition";
+export * from "./ISettableInstrument";
+export * from "./ITimingSource";
+export * from "./IUserDisplayInteractionListener";
+export * from "./IZoomView";

+ 6 - 0
src/Common/Strings/StringUtil.ts

@@ -0,0 +1,6 @@
+export class StringUtil {
+  public static StringContainsSeparatedWord(str: string, wordRegExString: string, ignoreCase: boolean = false): boolean {
+    const regExp: RegExp = new RegExp("( |^)" + wordRegExString + "([ .]|$)", ignoreCase ? "i" : undefined);
+    return regExp.test(str);
+  }
+}

+ 12 - 0
src/Common/Strings/TextTranslation.ts

@@ -0,0 +1,12 @@
+export class TextTranslation {
+    public static DefaultTextTranslation: TextTranslation;
+    public static translateText(tag: string, text: string): string {
+        if (TextTranslation.DefaultTextTranslation === undefined) {
+            return text;
+        }
+        return TextTranslation.DefaultTextTranslation.translate(tag, text);
+    }
+    public translate(tag: string, text: string): string {
+        return text;
+    }
+}

+ 3 - 0
src/Common/Strings/index.ts

@@ -0,0 +1,3 @@
+// created from 'create-ts-index'
+
+export * from "./StringUtil";

+ 4 - 0
src/Common/index.ts

@@ -0,0 +1,4 @@
+export * from "./DataObjects";
+export * from "./Enums";
+export * from "./FileIO";
+export * from "./Interfaces";

+ 134 - 0
src/Display/AbstractDisplayInteractionManager.ts

@@ -0,0 +1,134 @@
+import { IDisplayInteractionListener } from "../Common/Interfaces/IDisplayInteractionListener";
+
+export abstract class AbstractDisplayInteractionManager {
+    protected listeners: IDisplayInteractionListener[] = [];
+    private zoomGestureActive: boolean = false;
+    protected touchCount: number = 0;
+    protected touchActive: boolean = false;
+    protected touchMoving: boolean = false;
+    private lastRelPosX: number;
+    private lastRelPosY: number;
+    protected lastPixelX: number;
+    protected lastPixelY: number;
+    protected displayWidth: number = 1;
+    protected displayHeight: number = 1;
+    protected displayDpi: number = 96;
+    protected maxNumerOfFingers: number = 2;
+    protected movementThreshInch: number = 0.075;
+    protected interactionWasZoomGesture: boolean = false;
+    constructor() {
+        // TODO MB: Linter doesn't like empty constructors. Can we just remove this?
+    }
+    public addListener(listener: IDisplayInteractionListener): void {
+        this.listeners.push(listener);
+    }
+    public get ZoomGestureActive(): boolean {
+        return this.zoomGestureActive;
+    }
+    public get WasZoomGestureActive(): boolean {
+        return this.interactionWasZoomGesture;
+    }
+    public displaySizeChanged(displayWidthInPixel: number, displayHeightInPixel: number): void {
+        this.displayWidth = displayWidthInPixel;
+        this.displayHeight = displayHeightInPixel;
+        for (const listener of this.listeners) {
+            listener.displaySizeChanged(this.displayWidth, this.displayHeight);
+        }
+    }
+    public Dispose(): void {
+        this.dispose();
+    }
+    public Initialize(): void {
+        this.initialize();
+    }
+    public get DisplayDpi(): number {
+        return this.displayDpi;
+    }
+    public get TouchActive(): boolean {
+        return this.touchActive;
+    }
+    public get TouchMoving(): boolean {
+        return this.touchMoving;
+    }
+    protected abstract dispose(): void;
+    protected abstract initialize(): void;
+    protected touchDown(positionInPixelX: number, positionInPixelY: number, leftMouseButton: boolean): void {
+        this.interactionWasZoomGesture = false;
+        const relativePositionX: number = positionInPixelX / this.displayWidth;
+        const relativePositionY: number = positionInPixelY / this.displayHeight;
+        this.lastRelPosX = relativePositionX;
+        this.lastRelPosY = relativePositionY;
+        this.lastPixelX = positionInPixelX;
+        this.lastPixelY = positionInPixelY;
+        this.touchActive = true;
+        this.touchMoving = false;
+        this.touchCount = Math.min(this.touchCount + 1, this.maxNumerOfFingers);
+        for (const listener of this.listeners) {
+            //JL: Why is this negating the leftmousebutton? i guess it expects it to be undefined since it is a touch?
+            listener.mouseDown(relativePositionX, relativePositionY, !leftMouseButton);
+        }
+    }
+    protected move(positionInPixelX: number, positionInPixelY: number): void {
+        if (this.touchActive && !this.zoomGestureActive) {
+            const relativePositionX: number = positionInPixelX / this.displayWidth;
+            const relativePositionY: number = positionInPixelY / this.displayHeight;
+            const deltaX: number = (relativePositionX - this.lastRelPosX);
+            const deltaY: number = (relativePositionY - this.lastRelPosY);
+            this.touchMoving = true;
+            for (const listener of this.listeners) {
+                listener.mouseMove(relativePositionX, relativePositionY, deltaX, deltaY);
+            }
+        }
+    }
+    protected zoomGestureStarted(): void {
+        this.zoomGestureActive = true;
+    }
+    protected zoomGestureCompleted(): void {
+        this.zoomGestureActive = false;
+        this.interactionWasZoomGesture = true;
+    }
+    protected zoomGestureMove(scale: number): void {
+        if (this.zoomGestureActive) {
+            this.listeners.forEach(function (dil: IDisplayInteractionListener): void {
+                dil.zoom(scale);
+            });
+        }
+    }
+    protected touchUp(positionInPixelX: number, positionInPixelY: number): void {
+        this.touchActive = false;
+        this.touchMoving = false;
+        this.touchCount = Math.max(0, this.touchCount - 1);
+        const relativePositionX: number = positionInPixelX / this.displayWidth;
+        const relativePositionY: number = positionInPixelY / this.displayHeight;
+        for (const listener of this.listeners) {
+            listener.mouseUp(relativePositionX, relativePositionY);
+        }
+    }
+    protected click(positionInPixelX: number, positionInPixelY: number): void {
+        // don't click, if it was a move:
+        // changed to still fire click even for small movements (needed for ios, as no touches began fires at view border.)
+        if (!this.mouseDidMove(this.lastPixelX, positionInPixelX, this.lastPixelY, positionInPixelY) && !this.ZoomGestureActive) {
+            const relativePositionX: number = positionInPixelX / this.displayWidth;
+            const relativePositionY: number = positionInPixelY / this.displayHeight;
+            for (const listener of this.listeners) {
+                listener.positionTouched(relativePositionX, relativePositionY);
+            }
+        }
+    }
+    protected doubleClick(positionInPixelX: number, positionInPixelY: number): void {
+        // don't click, if it was a move:
+        // changed to still fire click even for small movements (needed for ios, as no touches began fired at view border.)
+        if (!this.mouseDidMove(this.lastPixelX, positionInPixelX, this.lastPixelY, positionInPixelY) && !this.ZoomGestureActive) {
+            const relativePositionX: number = positionInPixelX / this.displayWidth;
+            const relativePositionY: number = positionInPixelY / this.displayHeight;
+            for (const listener of this.listeners) {
+                listener.positionDoubleTouched(relativePositionX, relativePositionY);
+            }
+        }
+    }
+    protected mouseDidMove(oldPosX: number, newPosX: number, oldPosY: number, newPosY: number): boolean {
+        const movementDpiX: number = Math.abs(oldPosX - newPosX) / this.displayDpi;
+        const movementDpiY: number = Math.abs(oldPosY - newPosY) / this.displayDpi;
+        return movementDpiX > this.movementThreshInch || movementDpiY > this.movementThreshInch;
+    }
+}

+ 313 - 0
src/Display/AbstractZoomView.ts

@@ -0,0 +1,313 @@
+import { IControllerOutputListener } from "../Common/Interfaces/IControllerOutputListener";
+import { IDisplayInteractionListener } from "../Common/Interfaces/IDisplayInteractionListener";
+import { IZoomView } from "../Common/Interfaces/IZoomView";
+import { AbstractDisplayInteractionManager } from "./AbstractDisplayInteractionManager";
+// @ts-ignore
+import log from "loglevel";
+import { PointF2D } from "../Common/DataObjects";
+//import { AbstractNumberController } from "../Common/Algorithms/Controller/AbstractNumberController";
+//import { BrowserScrollController } from "../Common/Algorithms/Controller/BrowserScrollController";
+
+export abstract class AbstractZoomView implements IControllerOutputListener, IDisplayInteractionListener {
+    constructor(displayInteractionManager: AbstractDisplayInteractionManager) {
+        this.displayInteractionManager = displayInteractionManager;
+        this.displayInteractionManager.addListener(this);
+        this.offsetXMin = Number.MIN_VALUE;
+        this.offsetYMin = Number.MIN_VALUE;
+        this.rangeXMin = 1;
+        this.rangeYMin = 1;
+        this.offsetXMax = Number.MAX_VALUE;
+        this.offsetYMax = Number.MAX_VALUE;
+        this.rangeXMax = 1000000000;
+        this.rangeYMax = 1000000000;
+        // this.frictionScrollControllerX = new FrictionScrollController(this);
+        // this.scrollControllerX = new ConstantAccelerationController(this);
+        this.XScrollingEnabled = false;
+        //this.frictionScrollControllerY = new FrictionScrollController(this);
+        // this.scrollControllerY = new PTnController(this);
+        //this.scrollControllerY = new BrowserScrollController(this); // TODO don't need scrollController in the browser!? there's scroll-behavior: smooth
+        this.YScrollingEnabled = true;
+    }
+    protected displayInteractionManager: AbstractDisplayInteractionManager;
+    private rangeX: number;
+    private offsetX: number;
+    private rangeY: number;
+    private offsetY: number;
+    private lastRangeX: number;
+    private lastOffsetX: number;
+    private lastRangeY: number;
+    private lastOffsetY: number;
+    private aspectRatio: number = 1;
+    protected zoomViews: IZoomView[] = [];
+    protected mouseZoomMode: boolean = false;
+    protected usesManuallyControlledZoomMode: boolean;
+    //private autoScrollX: boolean = true;
+    private autoScrollY: boolean = true;
+    // private frictionScrollControllerX: FrictionScrollController;
+    // private scrollControllerX: AbstractNumberController; // ignore for now, doesn't exist in OSMD
+    // private frictionScrollControllerY: FrictionScrollController; // dragging screen. ignore for now.
+    //private scrollControllerY: AbstractNumberController; // already basically implemented by jimmy
+    protected convertToUnitsReady(): boolean { throw new Error("not implemented"); }
+    protected getPositionInUnits(relativePositionX: number, relativePositionY: number): PointF2D { throw new Error("not implemented"); }
+    public positionTouched(relativePositionX: number, relativePositionY: number): void {
+        if (!this.convertToUnitsReady()) {
+            return;
+        }
+        const clickPosition: PointF2D = this.getPositionInUnits(relativePositionX, relativePositionY);
+        this.unitPosTouched(clickPosition, relativePositionX, relativePositionY);
+    }
+    protected unitPosTouched(PosInUnits: PointF2D, relPosX: number, relPosY: number): void { throw new Error("not implemented"); }
+    public get TouchActive(): boolean {
+        return this.displayInteractionManager.TouchActive;
+    }
+    public get TouchMoving(): boolean {
+        return this.displayInteractionManager.TouchMoving;
+    }
+    public positionDoubleTouched(relativePositionX: number, relativePositionY: number): void {
+        if (!this.convertToUnitsReady()) {
+            return;
+        }
+        const clickPosition: PointF2D = this.getPositionInUnits(relativePositionX, relativePositionY);
+        this.unitPosDoubleTouched(clickPosition, relativePositionX, relativePositionY);
+    }
+    protected unitPosDoubleTouched(PosInUnits: PointF2D, relPosX: number, relPosY: number): void { throw new Error("not implemented"); }
+    public get UsesManuallyControlledZoomMode(): boolean {
+        return this.usesManuallyControlledZoomMode;
+    }
+    public set UsesManuallyControlledZoomMode(value: boolean) {
+        this.usesManuallyControlledZoomMode = value;
+    }
+    public mouseDown(relativePositionX: number, relativePositionY: number, activateZoomOnRightMouseButton: boolean = false): void {
+        if (!this.convertToUnitsReady()) {
+            return;
+        }
+        this.selectScrollControllerY(false);
+        this.lastRangeX = Math.max(1, this.RangeX);
+        this.lastRangeY = Math.max(1, this.RangeY);
+        this.lastOffsetX = this.OffsetX;
+        this.lastOffsetY = this.OffsetY;
+        //this.frictionScrollControllerX.touchDown(this.OffsetX, this.OffsetY);
+        //this.frictionScrollControllerY.touchDown(this.OffsetX, this.OffsetY);
+        const clickPosition: PointF2D = this.getPositionInUnits(relativePositionX, relativePositionY);
+        this.unitPosTouchDown(clickPosition, relativePositionX, relativePositionY);
+        if (!this.usesManuallyControlledZoomMode) {
+            if (activateZoomOnRightMouseButton) { // zooming
+                this.mouseZoomMode = true;
+            } else { // panning
+                this.mouseZoomMode = false;
+            }
+        }
+    }
+    protected unitPosTouchDown(PosInUnits: PointF2D, relPosX: number, relPosY: number): void { throw new Error("not implemented"); }
+    public mouseUp(relativePositionX: number, relativePositionY: number): void {
+        // if (!this.autoScrollX) {
+        //     this.frictionScrollControllerX.touchUp(this.OffsetX, this.OffsetY);
+        // }
+        // if (!this.autoScrollY) {
+        //     this.frictionScrollControllerY.touchUp(this.OffsetX, this.OffsetY);
+        // }
+        const clickPosition: PointF2D = this.getPositionInUnits(relativePositionX, relativePositionY);
+        this.unitPosTouchUp(clickPosition, relativePositionX, relativePositionY);
+    }
+    protected unitPosTouchUp(PosInUnits: PointF2D, relPosX: number, relPosY: number): void { throw new Error("not implemented"); }
+    public mouseMove(relativeDisplayPositionX: number, relativeDisplayPositionY: number, deltaX: number, deltaY: number): void {
+        if (this.mouseZoomMode) { // zoom
+            // zoom horizontally
+            if (Math.abs(deltaX - 0) > 0.00000001) {
+                this.RangeX = Math.abs(this.lastRangeX / (1 + deltaX));
+            }
+
+            // zoom vertically
+            if (!this.lockRanges && Math.abs(deltaY - 0) > 0.00000001) {
+                this.RangeY = Math.abs(this.lastRangeY / (1 - deltaY));
+            }
+        } else { // shift horizontally and/or vertically
+            if (Math.abs(deltaX - 0) > 0.00000001) {
+                this.OffsetX = this.lastOffsetX - deltaX * this.RangeX;
+            }
+            if (Math.abs(deltaY - 0) > 0.00000001) {
+                this.OffsetY = this.lastOffsetY - deltaY * this.RangeY;
+            }
+        }
+        // if (this.TouchActive) {
+        //     this.frictionScrollControllerX.touchMove(this.OffsetX, this.OffsetY);
+        //     this.frictionScrollControllerY.touchMove(this.OffsetX, this.OffsetY);
+        // }
+        const clickPosition: PointF2D = this.getPositionInUnits(relativeDisplayPositionX, relativeDisplayPositionY);
+        this.unitPosMove(clickPosition, relativeDisplayPositionX, relativeDisplayPositionY);
+    }
+    protected unitPosMove(PosInUnits: PointF2D, relativeDisplayPositionX: number, relativeDisplayPositionY: number): void {
+        throw new Error("not implemented");
+    }
+    public zoom(scale: number): void {
+        // zoom horizontally
+        this.RangeX = Math.abs(this.lastRangeX / scale);
+    }
+    public addZoomView(zoomable: IZoomView): void {
+        this.zoomViews.push(zoomable);
+    }
+    public XScrollingEnabled: boolean;
+    public YScrollingEnabled: boolean;
+    public offsetXMin: number;
+    public offsetYMin: number;
+    public rangeXMin: number;
+    public rangeYMin: number;
+    public offsetXMax: number;
+    public offsetYMax: number;
+    public rangeXMax: number;
+    public rangeYMax: number;
+    public lockRanges: boolean;
+    public get OffsetX(): number {
+        return this.offsetX;
+    }
+    public set OffsetX(value: number) {
+        this.offsetX = Math.min(this.offsetXMax, Math.max(this.offsetXMin, value));
+        for (const zoomable of this.zoomViews) {
+            zoomable.viewportXChanged(this.offsetX, this.RangeX);
+        }
+        // if (this.XScrollingEnabled && !this.autoScrollX) {
+        //     this.scrollControllerX.setOnlyCurrentValueDirectly(this.offsetX);
+        // }
+    }
+    public get OffsetY(): number {
+        return this.offsetY;
+    }
+    public set OffsetY(value: number) {
+        this.offsetY = value;
+        if (this.offsetY > this.offsetYMax) {
+            this.offsetY = this.offsetYMax;
+            //this.frictionScrollControllerY.stopTicking();
+        } else if (this.offsetY < this.offsetYMin) {
+            this.offsetY = this.offsetYMin;
+            //this.frictionScrollControllerY.stopTicking();
+        }
+        for (const zoomable of this.zoomViews) {
+            zoomable.viewportYChanged(this.offsetY, this.RangeY);
+        }
+        if (this.YScrollingEnabled && !this.autoScrollY) {
+            //this.scrollControllerY.setDirectly(this.offsetY);
+        }
+    }
+    public get RangeX(): number {
+        return this.rangeX;
+    }
+    public set RangeX(value: number) {
+        this.rangeX = Math.min(this.rangeXMax, Math.max(this.rangeXMin, value));
+        if (this.lockRanges) {
+            this.RangeY = this.RangeX / this.aspectRatio;
+            for (const zoomable of this.zoomViews) {
+                zoomable.viewportXChanged(this.OffsetX, this.RangeX);
+                zoomable.viewportYChanged(this.OffsetY, this.RangeY);
+            }
+        } else {
+            for (const zoomable of this.zoomViews) {
+                zoomable.viewportXChanged(this.OffsetX, this.RangeX);
+            }
+        }
+    }
+    public get RangeY(): number {
+        return this.rangeY;
+    }
+    public set RangeY(value: number) {
+        this.rangeY = Math.min(this.rangeYMax, Math.max(this.rangeYMin, value));
+        for (const zoomable of this.zoomViews) {
+            zoomable.viewportYChanged(this.OffsetY, this.RangeY);
+        }
+    }
+    protected set AspectRatio(value: number) {
+        this.aspectRatio = value;
+    }
+    public initialize(offsetX: number, rangeX: number, offsetY: number, rangeY: number): void {
+        this.setVerticalViewport(offsetY, rangeY);
+        this.setHorizontalViewport(offsetX, rangeX);
+    }
+    public setHorizontalViewport(offsetX: number, rangeX: number): void {
+        this.RangeX = rangeX;
+        this.OffsetX = offsetX;
+        this.lastRangeX = this.RangeX;
+        this.lastOffsetX = this.OffsetX;
+    }
+    public setVerticalViewport(offsetY: number, rangeY: number): void {
+        this.RangeY = rangeY;
+        this.OffsetY = offsetY;
+        this.lastRangeY = this.RangeY;
+        this.lastOffsetY = this.OffsetY;
+    }
+    public viewSizeChanged(displayWidthInPixel: number, displayHeightInPixel: number): void {
+        if (this.lockRanges) {
+            this.aspectRatio = displayWidthInPixel / displayHeightInPixel;
+            this.RangeY = this.RangeX / this.aspectRatio;
+            this.lastRangeY = this.RangeY;
+        }
+    }
+    public outputChanged(directlySet: boolean, currentValue: number, expectedValue: number): void {
+        this.OffsetY = <number>currentValue;
+    }
+    public setOffsetXValueOnly(offsetX: number): void {
+        this.offsetX = Math.min(this.offsetXMax, Math.max(this.offsetXMin, offsetX));
+    }
+    public setXOffset(offsetX: number, animated: boolean): void {
+        if (this.displayInteractionManager.TouchActive || !this.XScrollingEnabled) {
+            return;
+        }
+        // const offsetXWithinLimits: number = Math.min(this.offsetXMax, Math.max(this.offsetXMin, offsetX));
+        // if (animated) {
+        //     this.selectScrollControllerX(true);
+        //     this.scrollControllerX.setExpectedValue(offsetXWithinLimits);
+        // } else {
+        //     this.scrollControllerX.setDirectly(offsetXWithinLimits);
+        // }
+    }
+    public setOffsetYValueOnly(offsetY: number): void {
+        this.offsetY = Math.min(this.offsetYMax, Math.max(this.offsetYMin, offsetY));
+    }
+    public setYOffset(offsetY: number, animated: boolean): void {
+        if (this.displayInteractionManager.TouchActive || !this.YScrollingEnabled) {
+            return;
+        }
+        //const offsetYWithinLimits: number = Math.min(this.offsetYMax, Math.max(this.offsetYMin, offsetY));
+        if (animated) {
+            this.selectScrollControllerY(true);
+            //this.scrollControllerY.setExpectedValue(offsetYWithinLimits);
+        } else {
+            //this.scrollControllerY.setDirectly(offsetYWithinLimits);
+        }
+    }
+    // public dispose(): void {
+    //     try {
+    //         // this.scrollControllerX.Dispose();
+    //         // this.frictionScrollControllerX.Dispose();
+    //         this.scrollControllerY.Dispose();
+    //         // this.frictionScrollControllerY.Dispose();
+    //     } catch (ex) {
+    //         log.debug("AbstractZoomView.dispose", ex);
+    //     }
+
+    // }
+    // private selectScrollControllerX(autoScroll: boolean): void {
+    //     if (this.autoScrollX !== autoScroll) {
+    //         this.autoScrollX = autoScroll;
+    //         if (this.autoScrollX) {
+    //             this.frictionScrollControllerX.stopTicking();
+    //             this.scrollControllerX.startControlling();
+    //         } else {
+    //             this.scrollControllerX.stopControlling();
+    //         }
+    //     }
+    // }
+    private selectScrollControllerY(autoScroll: boolean): void {
+        if (this.autoScrollY !== autoScroll) {
+            this.autoScrollY = autoScroll;
+            if (this.autoScrollY) {
+                //this.frictionScrollControllerY.stopTicking();
+                //this.scrollControllerY.startControlling();
+            } else {
+                //this.scrollControllerY.stopControlling();
+            }
+        }
+    }
+
+    public displaySizeChanged(width: number, height: number): void {
+        throw new Error("Method not implemented.");
+    }
+}

+ 27 - 0
src/Display/PlaybackCursorUserInteractionManager.ts

@@ -0,0 +1,27 @@
+import { PointF2D } from "../Common/DataObjects";
+import { InteractionType } from "../Common/Enums/InteractionType";
+import { IUserDisplayInteractionListener } from "../Common/Interfaces/IUserDisplayInteractionListener";
+import { GraphicalMusicSheet, GraphicalVoiceEntry } from "../MusicalScore";
+import { Cursor } from "../OpenSheetMusicDisplay/Cursor";
+
+export class PlaybackCursorUserInteractionManager implements IUserDisplayInteractionListener {
+    private graphic: GraphicalMusicSheet;
+   // private cursor: Cursor;
+
+    constructor(graphic: GraphicalMusicSheet, cursor: Cursor) {
+        this.graphic = graphic;
+        //this.cursor = cursor;
+    }
+    public userDisplayInteraction(relativePosition: PointF2D, positionInSheetUnits: PointF2D, type: InteractionType): void {
+        switch (type) {
+            case InteractionType.SingleTouch:
+                const nearestVoiceEntry: GraphicalVoiceEntry = this.graphic.GetNearestVoiceEntry(positionInSheetUnits);
+                console.log(nearestVoiceEntry);
+                //TODO: This will change
+                //this.cursor.cursorPositionChanged(nearestVoiceEntry.parentStaffEntry.getAbsoluteTimestamp(), undefined);
+                break;
+            default:
+            break;
+        }
+    }
+}

+ 217 - 0
src/Display/ScreenViewingRegion.ts

@@ -0,0 +1,217 @@
+import { BoundingBox } from "../MusicalScore/Graphical";
+import { SizeF2D, PointF2D } from "../Common/DataObjects";
+
+/* This class is used as a simple 2D graphic pipeline to apply the resizing and positioning of drawing elements due to user interaction.
+ * This is achieved by defining a Screen Viewing Region, which represents the current region of the score that appears on the screen.
+ * Resizing this Viewing Region allows to zoom in and out, and moving it allows panning.
+ * The resizing considers also the modification of the current aspect ratio.
+ **/
+export class ScreenViewingRegion {
+    // TODO MB: Handle constructor overload
+    // Tried handling this with static create...() functions below, check if working.
+    //constructor() {
+    //    this(new SizeF2D(1, 1), new SizeF2D(1, 1), new PointF2D(0, 0), 1);
+
+    //}
+    //constructor(displaySizeInPixel: SizeF2D, regionWidthInUnits: number) {
+    //    this(displaySizeInPixel, new SizeF2D(1, 1), new PointF2D(0, 0), regionWidthInUnits);
+
+    //}
+
+    //Initial region shows the page WIDTH completely. The point 'position' corresponds to the left-upper corner of the viewing region
+    constructor(displaySizeInPixel: SizeF2D, relativeSizeOfRegionInDisplay: SizeF2D, relativePositionOfRegionInDisplay: PointF2D, regionWidthInUnits: number) {
+       this.psi = new BoundingBox(undefined);
+       //Change to internal value since the setters each depend on each other being defined. Which they won't be at this stage
+       this.displaySizeInPixel = displaySizeInPixel;
+       this.RelativeDisplaySize = relativeSizeOfRegionInDisplay;
+       this.RelativeDisplayPosition = relativePositionOfRegionInDisplay;
+       this.WidthInUnits = regionWidthInUnits;
+    }
+
+    // TODO MB: Give this a better name maybe
+    public static createWithRelativeDefaults(displaySizeInPixel: SizeF2D, regionWidthInUnits: number): ScreenViewingRegion {
+        return new ScreenViewingRegion(displaySizeInPixel, new SizeF2D(1, 1), new PointF2D(0, 0), regionWidthInUnits);
+    }
+
+    public static createWithDefaults(): ScreenViewingRegion {
+        return new ScreenViewingRegion(new SizeF2D(1, 1), new SizeF2D(1, 1), new PointF2D(0, 0), 1);
+    }
+
+    public RelativeDisplayPosition: PointF2D;
+    // /**
+    //  * Clip the whole object also if it lies inside the region but intersects this border.
+    //  */
+    // public ClipOnLeftBorderIntersection: boolean;
+    // /**
+    //  * Clip the whole object also if it lies inside the region but intersects this border.
+    //  */
+    // public ClipOnRightBorderIntersection: boolean;
+    // /**
+    //  * Clip the whole object also if it lies inside the region but intersects this border.
+    //  */
+    // public ClipOnTopBorderIntersection: boolean;
+    // /**
+    //  * Clip the whole object also if it lies inside the region but intersects this border.
+    //  */
+    // public ClipOnBottomBorderIntersection: boolean;
+    public get UpperLeftPositionInUnits(): PointF2D {
+        return this.psi.AbsolutePosition;
+    }
+    public set UpperLeftPositionInUnits(value: PointF2D) {
+        this.psi.AbsolutePosition = value;
+    }
+    public get DisplaySizeInPixel(): SizeF2D {
+        return this.displaySizeInPixel;
+    }
+    public set DisplaySizeInPixel(value: SizeF2D) {
+        this.displaySizeInPixel = value;
+        this.regionSizeInPixel = new SizeF2D(
+            this.displaySizeInPixel.width * this.relativeRegionSize.width,
+            this.displaySizeInPixel.height * this.relativeRegionSize.height
+            );
+        this.recalculateDependentVariables();
+    }
+    public get RelativeDisplaySize(): SizeF2D {
+        return this.relativeRegionSize;
+    }
+    public set RelativeDisplaySize(value: SizeF2D) { // TODO: pixelSize, pixelposition and their relative pendants should depend on each other
+        this.relativeRegionSize = value;
+        this.regionSizeInPixel = new SizeF2D(
+            this.displaySizeInPixel.width * this.relativeRegionSize.width,
+            this.displaySizeInPixel.height * this.relativeRegionSize.height
+            );
+        this.recalculateDependentVariables();
+    }
+    public get RegionSizeInPixel(): SizeF2D {
+        return this.regionSizeInPixel;
+    }
+    public get WidthInUnits(): number {
+        return this.psi.BorderRight;
+    }
+    public set WidthInUnits(value: number) {
+        this.psi.BorderRight = value;
+        this.recalculateDependentVariables();
+    }
+    public get ViewRegionInUnits(): SizeF2D {
+        return new SizeF2D(this.psi.BorderRight, this.psi.BorderBottom);
+    }
+    public isVisible(psi: BoundingBox, isCompletelyInside: boolean): boolean {
+        const psiInScreen: boolean = this.psi.collisionDetection(psi);
+        isCompletelyInside = this.psi.liesInsideBorders(psi);
+        return psiInScreen;
+    }
+    /** This visible check takes care of the 4 ClipOnIntersectionWith.... flags
+     * If a flag is set, all objects that reach over the corresponding border will not be "visible" and the method returns false.
+     */
+    // public isVisibleWithIntersectionClipping(psi: BoundingBox, isCompletelyInside: boolean): boolean {
+    //     const psiInScreen: boolean = this.psi.collisionDetection(psi);
+    //     // TODO MB: C# uses out keyword in .liesInsideBorders. Needs to be handled differently here.
+    //     // Original C# for reference:
+    //     // isCompletelyInside = this.psi.liesInsideBorders(psi, out leftBorderInside, out rightBorderInside, out topBorderInside, out bottomBorderInside);
+    //     // Commented to not offend linter. End of where I commented marked below
+
+    //     let leftBorderInside: boolean;
+    //     let rightBorderInside: boolean;
+    //     let topBorderInside: boolean;
+    //     let bottomBorderInside: boolean;
+    //     isCompletelyInside = this.psi.liesInsideBorders(psi, leftBorderInside, rightBorderInside, topBorderInside, bottomBorderInside);
+    //     if ((   (!leftBorderInside && this.ClipOnLeftBorderIntersection) ||
+    //             (!rightBorderInside && this.ClipOnRightBorderIntersection) ||
+    //             (!topBorderInside && this.ClipOnTopBorderIntersection) ||
+    //             (!bottomBorderInside && this.ClipOnBottomBorderIntersection)) ||
+    //             !psiInScreen) {
+    //         return false;
+    //     }
+    //     // *** End of commenting
+    //     return true;
+
+    // }
+    public isInsideDisplayArea(relativeDisplayPosX: number, relativeDisplayPosY: number): boolean {
+        const inside: boolean =
+            (this.RelativeDisplayPosition.x <= relativeDisplayPosX) &&
+            (relativeDisplayPosX <= this.RelativeDisplayPosition.x + this.RelativeDisplaySize.width) &&
+            (this.RelativeDisplayPosition.y <= relativeDisplayPosY) &&
+            (relativeDisplayPosY <= this.RelativeDisplayPosition.y + this.RelativeDisplaySize.height);
+        return inside;
+    }
+    // public transformBoundingBoxToScreenCoordinates(psiInUnits: BoundingBox): BoundingBox {
+    //     const pixelPsi: BoundingBox = new BoundingBox(psiInUnits.DataObject);
+    //     // TODO MB: Linter doesn't like long lines, reformat this to an agreed standard.
+    //     const leftBorderInPixel: number =
+    //         ((psiInUnits.AbsolutePosition.x + psiInUnits.BorderLeft) - this.psi.AbsolutePosition.x) * this.horizontalUnitToPixelRatio +
+    //         this.RelativeDisplayPosition.x * this.DisplaySizeInPixel.width;
+    //     const topBorderInPixel: number =
+    //         ((psiInUnits.AbsolutePosition.y + psiInUnits.BorderTop) - this.psi.AbsolutePosition.y) * this.verticalUnitToPixelRatio +
+    //         this.RelativeDisplayPosition.y * this.DisplaySizeInPixel.height;
+    //     pixelPsi.AbsolutePosition = new PointF2D(leftBorderInPixel, topBorderInPixel);
+    //     pixelPsi.BorderRight = psiInUnits.BorderRight * this.horizontalUnitToPixelRatio;
+    //     pixelPsi.BorderBottom = psiInUnits.BorderBottom * this.verticalUnitToPixelRatio;
+    //     return pixelPsi;
+    // }
+    // public transformRectangleToScreenCoordinates(rectInUnits: RectangleF2D): RectangleF2D {
+    //     const rectInPixels: RectangleF2D = new RectangleF2D(
+    //         this.transformPositionXToScreenCoordinates(rectInUnits.x),
+    //         this.transformPositionYToScreenCoordinates(rectInUnits.y),
+    //         rectInUnits.width * this.horizontalUnitToPixelRatio,
+    //         rectInUnits.height * this.verticalUnitToPixelRatio
+    //     );
+    //     // TODO MB: Moved below 4 lines into Rectangle initialization. Should have same result, check this.
+    //     // rectInPixels.x = this.transformPositionXToScreenCoordinates(rectInUnits.x);
+    //     // rectInPixels.y = this.transformPositionYToScreenCoordinates(rectInUnits.y);
+    //     // rectInPixels.width = rectInUnits.width * this.horizontalUnitToPixelRatio;
+    //     // rectInPixels.height = rectInUnits.height * this.verticalUnitToPixelRatio;
+    //     return rectInPixels;
+    // }
+    // public transformSizeToScreenCoordinates(sizeInUnits: SizeF2D): SizeF2D {
+    //     return new SizeF2D(sizeInUnits.width * this.horizontalUnitToPixelRatio, sizeInUnits.height * this.verticalUnitToPixelRatio);
+    // }
+    // public transformPointsToScreenCoordinates(pointInUnits: PointF2D): PointF2D {
+    //     return new PointF2D(this.transformPositionXToScreenCoordinates(pointInUnits.x), this.transformPositionYToScreenCoordinates(pointInUnits.y));
+    // }
+    // public transformPositionXToScreenCoordinates(posXInUnits: number): number {
+    //     return (posXInUnits - this.psi.AbsolutePosition.x) * this.horizontalUnitToPixelRatio
+    //      + this.RelativeDisplayPosition.x * this.DisplaySizeInPixel.width;
+    // }
+    // public transformPositionYToScreenCoordinates(posYInUnits: number): number {
+    //     return (posYInUnits - this.psi.AbsolutePosition.y) * this.verticalUnitToPixelRatio + this.RelativeDisplayPosition.y * this.DisplaySizeInPixel.height;
+    // }
+    // public transformLengthXToScreenCoordinates(lengthXInUnits: number): number {
+    //     return lengthXInUnits * this.horizontalUnitToPixelRatio;
+    // }
+    // public transformLengthYToScreenCoordinates(lengthYInUnits: number): number {
+    //     return lengthYInUnits * this.verticalUnitToPixelRatio;
+    // }
+
+    /**
+     * @param relativeScreenPosition The relative position on the whole screen,
+     * not on the ScreenViewingRegion (only if the region stretches over the whole screen).
+     */
+    public transformToUnitCoordinates(relativeScreenPosition: PointF2D): PointF2D {
+        const position: PointF2D = new PointF2D(this.UpperLeftPositionInUnits.x + this.ViewRegionInUnits.width *
+                                                ((relativeScreenPosition.x - this.RelativeDisplayPosition.x) / this.RelativeDisplaySize.width),
+                                                this.UpperLeftPositionInUnits.y + this.ViewRegionInUnits.height *
+                                                ((relativeScreenPosition.y - this.RelativeDisplayPosition.y) / this.RelativeDisplaySize.height));
+        return position;
+    }
+    // public transformToUnitCoordinates(sizeInPixels: SizeF2D): SizeF2D {
+    //     return new SizeF2D(sizeInPixels.width / this.horizontalUnitToPixelRatio, sizeInPixels.height / this.verticalUnitToPixelRatio);
+    // }
+    public transformLengthXToUnitCoordinates(lengthXInPixels: number): number {
+        return lengthXInPixels / this.horizontalUnitToPixelRatio;
+    }
+    public transformLengthYToUnitCoordinates(lengthYInPixels: number): number {
+        return lengthYInPixels / this.verticalUnitToPixelRatio;
+    }
+    private recalculateDependentVariables(): void {
+        const aspectRatio: number = this.regionSizeInPixel.width / this.regionSizeInPixel.height;
+        this.psi.BorderBottom = this.psi.BorderRight / aspectRatio;
+        this.horizontalUnitToPixelRatio = this.regionSizeInPixel.width / this.ViewRegionInUnits.width;
+        this.verticalUnitToPixelRatio = this.regionSizeInPixel.height / this.ViewRegionInUnits.height;
+    }
+    private displaySizeInPixel: SizeF2D; // Size of the display
+    private regionSizeInPixel: SizeF2D; // Size of the Region on the display
+    private relativeRegionSize: SizeF2D;
+    private horizontalUnitToPixelRatio: number;
+    private verticalUnitToPixelRatio: number;
+    private psi: BoundingBox;
+}

+ 562 - 0
src/Display/SheetRenderingManager.ts

@@ -0,0 +1,562 @@
+import { IZoomView } from "../Common/Interfaces/IZoomView";
+import {    MusicSheetDrawer, GraphicalMusicSheet, BoundingBox, DrawingParameters,
+            MusicSystem, GraphicalVoiceEntry } from "../MusicalScore/Graphical";
+import { ScreenViewingRegion } from "./ScreenViewingRegion";
+import { PointF2D, Fraction, SizeF2D } from "../Common/DataObjects";
+import { AbstractZoomView } from "./AbstractZoomView";
+import { InteractionType } from "../Common/Enums/InteractionType";
+import { AbstractDisplayInteractionManager } from "./AbstractDisplayInteractionManager";
+import { IUserDisplayInteractionListener } from "../Common/Interfaces/IUserDisplayInteractionListener";
+import { PlaybackManager } from "../Playback";
+
+export class SheetRenderingManager extends AbstractZoomView implements IZoomView {
+    // protected phonicScoreInterface: IPhonicScoreInterface; // TODO MB: remove this
+    protected musicSheetDrawer: MusicSheetDrawer;
+    protected graphicalMusicSheet: GraphicalMusicSheet;
+    protected mainViewingRegion: ScreenViewingRegion = ScreenViewingRegion.createWithDefaults();
+    // protected display: IMusicSheetDisplay;
+    // protected renderingFinished: EventWaitHandle = new EventWaitHandle(true, EventResetMode.ManualReset);
+    // protected newRedrawWanted: EventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
+    protected tryAgainToRenderCount: number = 0;
+    //private toImageMusicSheetDrawer: MusicSheetDrawer;
+    private yOffsetMouseDown: number = Number.MIN_VALUE;
+    private unlockCursorDistancePixel: number = 50.0;
+    private relativeTopPosition: number = 0.06;
+    /* The preview images are supersampled (because of our drawing mechanism with more than 1 rasterization stage,
+     * this increases the output image quality significantly)
+     **/
+    protected internalPreviewImageScale: number = 3.0;
+    protected listeners: IUserDisplayInteractionListener[] = [];
+    public PlaybackManager: PlaybackManager;
+
+    constructor(displayInteractionManager: AbstractDisplayInteractionManager, playbackManager?: PlaybackManager) {
+        super(displayInteractionManager);
+        this.addZoomView(this);
+        this.lockRanges = true;
+        this.TopBarHeightInPixel = 70;
+        this.BottomBarHeightInPixel = 0;
+        // this.phonicScoreInterface = phonicScoreInterface;
+        // this.display = display;
+        // this.musicSheetDrawer =
+        //     new PsMusicSheetDrawer(phonicScoreInterface, display.Renderer, display.Renderer, FontInfo.Info, false, phonicScoreInterface.HasSoundOutput);
+        // this.toImageMusicSheetDrawer =
+        //     new PsMusicSheetDrawer(phonicScoreInterface, display.PreviewImageRenderer, display.PreviewImageRenderer, FontInfo.Info, true, false);
+        //this.toImageMusicSheetDrawer.splitScreenLineColor = -1;
+        // TODO MB: Commented following 2 lines because paintingThreadLoop is to be removed. Do we need to convert this somehow?
+        // const redrawPreparationThread: Task = new Task(this.paintingThreadLoop);
+        // redrawPreparationThread.Start();
+    }
+
+    public addListener(listener: IUserDisplayInteractionListener): void {
+        this.listeners.push(listener);
+    }
+    public SingleTouchDisabled: boolean;
+    public DoubleTouchDisabled: boolean;
+    public LockDisplayToCursor: boolean = true;
+    public ZoomActive: boolean = false;
+    protected convertToUnitsReady(): boolean {
+        return this.graphicalMusicSheet !== undefined;
+    }
+    protected unitPosTouched(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
+        // lock(this.mainViewingRegion)
+        // {
+        // Pass mouse click to click listener
+        if (!this.SingleTouchDisabled) {
+            const relPos: PointF2D = new PointF2D(relPosX, relPosY);
+            this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.SingleTouch);
+            for (const listener of this.listeners) {
+                listener.userDisplayInteraction(relPos, PosInUnits, InteractionType.SingleTouch);
+            }
+        }
+        // }
+    }
+    protected unitPosDoubleTouched(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
+        // lock(this.mainViewingRegion)
+        // {
+        if (!this.DoubleTouchDisabled) {
+            const relPos: PointF2D = new PointF2D(relPosX, relPosY);
+            this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.DoubleTouch);
+            for (const listener of this.listeners) {
+                listener.userDisplayInteraction(relPos, PosInUnits, InteractionType.DoubleTouch);
+            }
+        }
+        // }
+    }
+    protected unitPosTouchDown(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
+        // lock(this.mainViewingRegion)
+        // {
+        const relPos: PointF2D = new PointF2D(relPosX, relPosY);
+        this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.TouchDown);
+        for (const listener of this.listeners) {
+            listener.userDisplayInteraction(new PointF2D(relPosX, relPosY), PosInUnits, InteractionType.TouchDown);
+        }
+        this.yOffsetMouseDown = PosInUnits.y;
+        // }
+    }
+    protected unitPosTouchUp(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
+        // lock(this.mainViewingRegion)
+        // {
+        const relPos: PointF2D = new PointF2D(relPosX, relPosY);
+        this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.TouchUp);
+        for (const listener of this.listeners) {
+            listener.userDisplayInteraction(new PointF2D(relPosX, relPosY), PosInUnits, InteractionType.TouchUp);
+        }
+        if (this.displayInteractionManager.WasZoomGestureActive === false) {
+            this.unlockFromCursorIfNecessary(PosInUnits);
+        }
+        this.yOffsetMouseDown = Number.MIN_VALUE;
+        // }
+    }
+    protected unitPosMove(PosInUnits: PointF2D, relPosX: number, relPosY: number): void {
+        // lock(this.mainViewingRegion)
+        // {
+        const relPos: PointF2D = new PointF2D(relPosX, relPosY);
+        this.handleUserDisplayInteraction(relPos, PosInUnits, InteractionType.Move);
+        for (const listener of this.listeners) {
+            listener.userDisplayInteraction(new PointF2D(relPosX, relPosY), PosInUnits, InteractionType.Move);
+        }
+        this.unlockFromCursorIfNecessary(PosInUnits);
+        // }
+    }
+
+    public get MainViewingRegion(): ScreenViewingRegion {
+        return this.mainViewingRegion;
+    }
+    public TopBarHeightInPixel: number;
+    public BottomBarHeightInPixel: number;
+    // public setRenderers(windowRenderer: IMusicSheetRenderer, previewRenderer: IImageRenderer): void {
+    //     this.musicSheetDrawer.setRenderer(windowRenderer);
+    //     this.toImageMusicSheetDrawer.setRenderer(previewRenderer);
+    // }
+    public setMusicSheet(musicSheet: GraphicalMusicSheet): void {
+        // this.musicSheetDrawer.disposeAllBackbuffers();
+        this.graphicalMusicSheet = musicSheet;
+        this.adaptDisplayLimitsToSheet();
+        // this.setYOffset(
+        //     EngravingRules.Rules.TitleTopDistance - this.topBarHeightInUnits() - this.relativeTopPosition * this.heightWithoutTopBottomBarsInUnits(),
+        //     true);
+        this.setYOffset(0, true);
+        // this.redraw();
+    }
+    public viewportXChanged(offsetX: number, rangeX: number): void {
+        if (this.graphicalMusicSheet === undefined) {
+            return;
+        }
+        // lock(this.mainViewingRegion)
+        // {
+        this.horizontalViewportChanged(offsetX, rangeX);
+        // }
+    }
+    /**
+     * Sets the vertical position and viewing height of the displayed area on the music score.
+     */
+    public viewportYChanged(offsetY: number, rangeY: number): void {
+        if (this.graphicalMusicSheet === undefined) {
+            return;
+        }
+        if (this.yOffsetMouseDown <= Number.MIN_VALUE + 0.5) {
+            this.yOffsetMouseDown = offsetY;
+        }
+        // lock(this.mainViewingRegion)
+        // {
+        this.verticalViewportChanged(offsetY, rangeY);
+        // }
+    }
+    public displaySizeChanged(width: number, height: number): void {
+        super.viewSizeChanged(width, height);
+        //TODO: Don't think we need these for web?
+        //this.TopBarHeightInPixel = topBarHeightInPixel;
+        //this.BottomBarHeightInPixel = bottomBarHeightInPixel;
+        // this.musicSheetDrawer.disposeAllBackbuffers();
+        if (Math.abs(width - 0) < 0.0000001 || Math.abs(height - 0) < 0.0000001) {
+            return;
+        }
+        // lock(this.mainViewingRegion)
+        // {
+        if (this.graphicalMusicSheet !== undefined) {
+            this.graphicalMusicSheet.EnforceRedrawOfMusicSystems(); // probably not necessary, already handled by OSMD
+        }
+        this.mainViewingRegion.DisplaySizeInPixel = new SizeF2D (width, height);
+        this.adaptDisplayLimitsToSheet();
+        // }
+    }
+    public calcDisplayYPosition(system: MusicSystem): number {
+        return  system.PositionAndShape.AbsolutePosition.y + system.PositionAndShape.BorderMarginTop -
+                this.topBarHeightInUnits() - this.relativeTopPosition * this.heightWithoutTopBottomBarsInUnits();
+    }
+    /**
+     * The display scroll y-position to show the given system completely on the bottom of the screen
+     */
+    public yPositionForLastSystem(lastSystem: MusicSystem): number {
+        return  lastSystem.PositionAndShape.AbsolutePosition.y + lastSystem.PositionAndShape.BorderMarginBottom -
+                this.topBarHeightInUnits() - (1 - this.relativeTopPosition) * this.heightWithoutTopBottomBarsInUnits();
+    }
+    // TODO MB: What is up with the unused variables here? Also: formatting of parameters.
+    public scorePositionChanged(upperCursorPoint: PointF2D, enrolledTimeStamp: Fraction, sheetTimeStamp: Fraction,
+                                system: MusicSystem, resetOccurred: boolean, smoothAnimation: boolean): void {
+        const positionY: number = this.calcDisplayYPosition(system);
+        this.setYPosition(positionY, smoothAnimation);
+        // this.redraw();
+    }
+    public setXPosition(positionXInUnits: number, animated: boolean): void {
+        // lock(this.mainViewingRegion)
+        // {
+        if (this.LockDisplayToCursor) {
+            this.setXOffset(positionXInUnits, animated);
+        }
+        // }
+    }
+    public setYPosition(positionYInUnits: number, animated: boolean): void {
+        // lock(this.mainViewingRegion)
+        // {
+        if (this.LockDisplayToCursor) {
+            this.setYOffset(positionYInUnits, animated);
+        }
+        // }
+    }
+    public clearBackbuffers(): void {
+        // this.musicSheetDrawer.disposeAllBackbuffers();
+    }
+    // public redraw(): void {
+    //     this.newRedrawWanted.Set();
+    // }
+    // public render(): void {
+    //     // lock(this.display.Renderer)
+    //     // {
+    //     try {
+    //         this.display.Renderer.prepareDrawing();
+    //         this.display.Renderer.draw();
+    //     } catch (ex) {
+    //         log.error("SheetRenderingManager.render", "Renderer PrepareDrawing or draw", ex);
+    //         throw ex;
+    //     } finally {
+    //         try {
+    //             this.display.Renderer.finalizeDrawing();
+    //         } catch (ex) {
+    //             log.error("SheetRenderingManager.render", "Renderer FinalizeDrawing", ex);
+    //             throw ex;
+    //         } finally {
+    //             this.renderingFinished.Set();
+    //         }
+    //     }
+    //     // }
+    // }
+    public get DrawingParameters(): DrawingParameters {
+        return this.musicSheetDrawer.drawingParameters;
+    }
+    public topBarHeightInUnits(): number {
+        return this.mainViewingRegion.transformLengthYToUnitCoordinates(this.TopBarHeightInPixel);
+    }
+    public bottomBarHeightInUnits(): number {
+        return this.mainViewingRegion.transformLengthYToUnitCoordinates(this.BottomBarHeightInPixel);
+    }
+    public heightWithoutTopBottomBarsInUnits(): number {
+        return this.mainViewingRegion.ViewRegionInUnits.height - this.topBarHeightInUnits() - this.bottomBarHeightInUnits();
+    }
+    public activePositionToBottomBarHeight(): number {
+        return  (this.mainViewingRegion.ViewRegionInUnits.height - this.topBarHeightInUnits() - this.bottomBarHeightInUnits()) *
+                (1 - 2 * this.relativeTopPosition);
+    }
+    // public freeMemory(): void {
+    //     this.display.Renderer.freeMemory();
+    // }
+    // public Dispose(): void {
+    //     super.dispose();
+    // }
+    public getClickPosition(relativePositionX: number, relativePositionY: number): PointF2D {
+        return this.mainViewingRegion.transformToUnitCoordinates(new PointF2D(relativePositionX, relativePositionY));
+    }
+    public graphicalObjectIsVisible(boundingBox: BoundingBox): boolean {
+        const isCompletelyInside: boolean = false;
+        // lock(this.mainViewingRegion)
+        // {
+        return this.mainViewingRegion.isVisible(boundingBox, isCompletelyInside);
+        // }
+    }
+    /**
+     * sets the size of the maximal musicpage seen including the extensions on top resp. bottom
+     * !Caution!: settings/offsets have been changed for ScrollIndicator.. won't work anymore if changed again
+     */
+    public adaptDisplayLimitsToSheet(): void {
+        if (   this.graphicalMusicSheet === undefined
+            || this.graphicalMusicSheet.MusicPages.length === 0
+            || this.graphicalMusicSheet.MusicPages[0].MusicSystems.length === 0) {
+            return;
+        }
+
+        // set the new limits for viewing:
+        this.offsetXMin = 0;
+        this.rangeXMin = this.graphicalMusicSheet.MinAllowedSystemWidth;
+        this.rangeXMax = 300;
+        this.offsetYMin = -0.3 * this.RangeY;
+        const lastPagePsi: BoundingBox = this.graphicalMusicSheet.MusicPages.last().PositionAndShape;
+        this.offsetYMax = Math.max(0, lastPagePsi.BorderMarginBottom - 0.7 * this.RangeY);
+        if (this.OffsetY > this.offsetYMax) {
+            this.setYOffset(this.offsetYMax, true);
+        }
+    }
+    protected horizontalViewportChanged(offsetX: number, rangeX: number): void {
+        if (this.mainViewingRegion.WidthInUnits !== rangeX) {
+            this.mainViewingRegion.WidthInUnits = rangeX;
+            // this.redraw();
+        }
+    }
+
+    protected verticalViewportChanged(offsetY: number, rangeY: number): void {
+        this.mainViewingRegion.UpperLeftPositionInUnits = new PointF2D(this.mainViewingRegion.UpperLeftPositionInUnits.x, offsetY);
+    }
+
+    private unlockFromCursorIfNecessary(PosInUnits: PointF2D): void {
+        if (this.LockDisplayToCursor === false || this.ZoomActive) {
+            return;
+        }
+
+        if (this.displayInteractionManager.ZoomGestureActive || this.displayInteractionManager.WasZoomGestureActive) {
+            return;
+        }
+        // finally check for the movement distance, to not unlock already at little finger pressure changes...
+        // TODO MB: Fix formatting.
+        const ydiff: number = Math.abs((PosInUnits.y - this.yOffsetMouseDown) *
+                                this.mainViewingRegion.RegionSizeInPixel.height /
+                                this.mainViewingRegion.ViewRegionInUnits.height);
+        if (ydiff > this.unlockCursorDistancePixel) {
+            // this.phonicScoreInterface.requestLockDisplayToCursor(false);
+            this.LockDisplayToCursor = false;
+        }
+    }
+
+    protected getPositionInUnits(relativePositionX: number, relativePositionY: number): PointF2D {
+        return this.mainViewingRegion.transformToUnitCoordinates(new PointF2D(relativePositionX, relativePositionY));
+    }
+
+    protected handleUserDisplayInteraction( relativePositionOnDisplay: PointF2D, positionOnMusicSheet: PointF2D,
+                                            type: InteractionType): void {
+        switch (type) {
+            case InteractionType.SingleTouch:
+            case InteractionType.DoubleTouch: {
+                // switch (this.Tool) {
+        //             case PsTool.None: {
+        //                 if (this.graphicalMusicSheet === undefined || this.renderingManager.TouchMoving) {
+        //                     break;
+        //                 }
+
+        //                 // check for activity symbol clicked
+        //                 if (positionOnMusicSheet.x < 10) {
+                            // const activitySymbol: StaffLineActivitySymbol =
+                            //     this.graphicalMusicSheet.getClickedObject<StaffLineActivitySymbol>(positionOnMusicSheet);
+        //                     if (activitySymbol !== undefined) {
+        //                         const instrument: Instrument = activitySymbol.parentStaffLine.ParentStaff.ParentInstrument;
+        //                         switch (this.Mode) {
+        //                             case PsMode.Following: {
+        //                              // KeyValuePair<int, bool> parameters = new KeyValuePair<int, bool>(
+        //                              //     activitySymbol.ParentStaffLine.ParentStaff.Id,
+        //                              //     !activitySymbol.ParentStaffLine.ParentStaff.Following
+        //                              //     );
+                                        // instrument.setInstrumentParameter(
+                                        //     InstrumentParameters.Follow,
+                                        //     !activitySymbol.parentStaffLine.ParentStaff.following
+                                        //     );
+        //                                 break;
+        //                             }
+        //                             case PsMode.Midi: {
+        //                                 if (this.PitchMonitorEnabled) {
+        //                                     const pitchMonitorEnabled: boolean = !activitySymbol.parentStaffLine.ParentStaff.PitchMonitor;
+        //                                     //KeyValuePair<int, bool> parameters = new KeyValuePair<int, bool>(
+        //                                          // activitySymbol.ParentStaffLine.ParentStaff.Id,
+        //                                          // !activitySymbol.ParentStaffLine.ParentStaff.PitchMonitor);
+        //                                     instrument.setInstrumentParameter(InstrumentParameters.PitchMonitor, pitchMonitorEnabled);
+
+        //                                     //if (pitchMonitorEnabled) {
+        //                                     //        // switch off all other instruments so that only one will be active
+        //                                     //    foreach (var instr in this.graphicalMusicSheet.ParentMusicSheet.Instruments) {
+        //                                     //        if (instr != instrument) {
+        //                                     //            instr.setInstrumentParameter(InstrumentParameters.PitchMonitor, false);
+        //                                     //            }
+        //                                     //        }
+        //                                     //    }
+        //                                 }
+        //                                 else {
+        //                                  KeyValuePair < int, bool > parameters = new KeyValuePair<int, bool>(
+        //                                      activitySymbol.ParentStaffLine.ParentStaff.Id,
+        //                                      !activitySymbol.ParentStaffLine.ParentStaff.Audible
+        //                                  );
+        //                                     instrument.setInstrumentParameter(InstrumentParameters.StaffAudible, parameters);
+        //                                 }
+        //                                 break;
+        //                             }
+        //                             default:
+        //                                 break;
+        //                         }
+
+        //                         break;
+        //                     }
+        //                 }
+
+                const clickVe: GraphicalVoiceEntry = this.graphicalMusicSheet.GetNearestVoiceEntry(positionOnMusicSheet);
+
+        //                 // check for clef clicked
+
+        //                 if (clickedObject is GraphicalClefInstruction) {
+        //                     if (this.QueryRequested !== undefined) {
+        //                         GraphicalClefInstruction clef = clickedObject as GraphicalClefInstruction;
+        //                         this.QueryRequested(QueryType.ClefChange, clef);
+        //                     }
+        //                     break;
+        //                 }
+
+                        /*
+                        // *** MARKED AREA and COMMENT Editing ***
+                        //check for Marked Area/Comment clicked
+                        GraphicalLabel clickableLabel = this.graphicalMusicSheet.getNearestGraphicalObject<GraphicalLabel>(positionOnMusicSheet);
+                        if (clickableLabel is Clickable)
+                        {
+                            Clickable clickable = (Clickable)clickableLabel;
+                            if (clickable.DataObject is MarkedArea)
+                            {
+                                this.annotationManager.editMarkedAreaLabel((MarkedArea)clickable.DataObject);
+                                break;
+                            }
+                            else if (clickable.DataObject is Comment)
+                            {
+                                this.annotationManager.editCommentLabel((Comment)clickable.DataObject);
+                                break;
+                            }
+                        }
+                        */
+
+                        // if (this.Mode != PsMode.Manual) {
+                            // lock(this.graphicalMusicSheet) {
+                // set cursor and/or start/end marker position
+
+                if (clickVe) {
+                    if (clickVe.parentStaffEntry.parentVerticalContainer !== undefined) {
+                        const clickedTimeStamp: Fraction = clickVe.parentStaffEntry.parentVerticalContainer.AbsoluteTimestamp;
+                        // if (this.Loop === false) {
+                        this.setStartPosition(clickedTimeStamp);
+                        // } else { //greater than startSymbol
+                        //     if (this.loop_setEndMarker) {
+                        //         this.setEndPosition(clickedTimeStamp);
+                        //         // this.MessageOccurred(MessageBoxType.Info, "", MessageBoxTopic.LoopMarkerChanged, LoopTagType.EndTag);
+                        //     } else {
+                        //         this.setEndPosition(this.graphicalMusicSheet.ParentMusicSheet.SheetEndTimestamp);
+                        //         this.setStartPosition(clickedTimeStamp);
+                        //         // this.MessageOccurred(MessageBoxType.Info, "", MessageBoxTopic.LoopMarkerChanged, LoopTagType.StartTag);
+                        //     }
+
+                            // toggle marker:
+                            // this.loop_setEndMarker = !this.loop_setEndMarker;
+                        // }
+
+                        // playback clicked note
+                        if (clickVe.notes[0]?.sourceNote.Pitch !== undefined) {
+                            this.PlaybackManager?.playVoiceEntry(clickVe.parentVoiceEntry);
+                        }
+                    }
+                }
+                            // }
+                        // }
+    //                     else // manual mode:
+    //                     {
+                        //     if (relativePositionOnDisplay.y < 0.3) {
+                        //         this.scrollPageUp_();
+                        //         break;
+                        //     }
+
+                        //     if (relativePositionOnDisplay.y > 0.7) {
+                        //         this.scrollPageDown_();
+                        //         break;
+                        //     }
+                        // }
+
+    //                     break;
+    //                 }
+
+    //                 case PsTool.Zoom:
+    //                     break;
+                    // case PsTool.Comment: {
+                        // const clickedGse: GraphicalStaffEntry =
+                        //     this.graphicalMusicSheet.getNearestGraphicalObject<GraphicalStaffEntry>(
+                        //         positionOnMusicSheet);
+                        // if (clickedGse === undefined || clickedGse.relInMeasureTimestamp === undefined
+                        // ) // second would mean grace note
+                        // {
+                        //     break;
+                        // }
+
+                        // const staff: Staff = clickedGse.parentMeasure.ParentStaffLine.ParentStaff;
+                        // const staffLineIndex: number = MusicSheet.getIndexFromStaff(staff);
+                        // this.annotationManager.createComment(clickedGse.parentVerticalContainer.AbsoluteTimestamp,
+                        //     staffLineIndex);
+    //                     break;
+    //                 }
+
+    //                 case PsTool.Mark: {
+                        // const clickedGse: GraphicalStaffEntry =
+                        //     this.graphicalMusicSheet.getNearestGraphicalObject<GraphicalStaffEntry>(
+                        //         positionOnMusicSheet);
+                        // if (clickedGse === undefined || clickedGse.relInMeasureTimestamp === undefined
+                        // ) // second would mean grace note
+                        // {
+                        //     break;
+                        // }
+
+                        // this.annotationManager.createMarkedArea(
+                        //     clickedGse.parentVerticalContainer.AbsoluteTimestamp);
+                        // break;
+    //                 }
+
+    //                 default:
+    //                     throw new ArgumentOutOfRangeException();
+    //             }
+
+                break;
+            }
+
+            case InteractionType.TouchUp: {
+                // switch (this.Tool) {
+                //     case PsTool.None:
+                //         break;
+                //     case PsTool.Zoom:
+                //         this.adaptSystemBreaksToPageWidth_();
+                //         break;
+                //     case PsTool.Comment:
+                //         break;
+                //     case PsTool.Mark:
+                //         break;
+                //     default:
+                //         throw new ArgumentOutOfRangeException();
+                // }
+
+                break;
+            }
+
+            case InteractionType.TouchDown: {
+                break;
+            }
+
+            case InteractionType.Move: {
+                break;
+            }
+
+            default:
+                throw new Error("type");
+        }
+    }
+
+    protected setStartPosition(newStartPosition: Fraction): void {
+        if (this.graphicalMusicSheet === undefined) {
+            return;
+        }
+
+        // if (this.Loop && newStartPosition >= this.graphicalMusicSheet.ParentMusicSheet.SelectionEnd) {
+        //     const currentMeasureNumber: number = this.graphicalMusicSheet.ParentMusicSheet
+        //         .getSourceMeasureFromTimeStamp(newStartPosition).MeasureNumber;
+        //     this.setEndPosition(currentMeasureNumber);
+        // }
+
+        // this.graphicalMusicSheet.setSelectionStartSymbol(newStartPosition);
+        this.graphicalMusicSheet.ParentMusicSheet.SelectionStart = newStartPosition;
+        this.PlaybackManager?.reset();
+    }
+
+}

+ 134 - 0
src/Display/WebDisplayInteractionManager.ts

@@ -0,0 +1,134 @@
+import { AbstractDisplayInteractionManager } from "./AbstractDisplayInteractionManager";
+import { PointF2D } from "../Common/DataObjects/PointF2D";
+
+export class WebDisplayInteractionManager extends AbstractDisplayInteractionManager {
+    protected isTouchDevice: boolean = false;
+    protected osmdSheetMusicContainer: HTMLElement;
+    protected fullOffsetLeft: number = 0;
+    protected fullOffsetTop: number = 0;
+
+    constructor(osmdContainer: HTMLElement) {
+        super();
+        this.isTouchDevice = this.isTouch();
+        this.osmdSheetMusicContainer = osmdContainer;
+        this.listenForInteractions();
+    }
+
+    protected initialize(): void {
+        this.fullOffsetLeft = 0;
+        this.fullOffsetTop = 0;
+        let nextParent: HTMLElement = this.osmdSheetMusicContainer;
+        while (nextParent) {
+            this.fullOffsetLeft += nextParent.offsetLeft;
+            this.fullOffsetTop += nextParent.offsetTop;
+            nextParent = nextParent.offsetParent as HTMLElement;
+        }
+    }
+
+    protected dispose(): void {
+        this.osmdSheetMusicContainer.removeEventListener(this.downEventName, this.downEventListener);
+        this.osmdSheetMusicContainer.removeEventListener("touchend", this.touchEndEventListener.bind(this));
+        this.osmdSheetMusicContainer.removeEventListener(this.moveEventName, this.moveEventListener);
+        window.removeEventListener("resize", this.resizeEventListener.bind(this));
+    }
+
+    //TODO: Much of this pulled from annotations code. Once we get the two branches together, combine common code
+    private isTouch(): boolean {
+        if (("ontouchstart" in window) || (window as any).DocumentTouch) {
+            return true;
+        }
+        // include the 'heartz' as a way to have a non matching MQ to help terminate the join
+        // https://git.io/vznFH
+        const prefixes: string[] = ["-webkit-", "-moz-", "-o-", "-ms-"];
+        const query: string = ["(", prefixes.join("touch-enabled),("), "heartz", ")"].join("");
+        return window.matchMedia(query).matches;
+    }
+
+    protected get downEventName(): string {
+        return this.isTouchDevice ? "touchstart" : "mousedown";
+    }
+
+    protected get moveEventName(): string {
+        return this.isTouchDevice ? "touchmove" : "mousemove";
+    }
+
+    private listenForInteractions(): void {
+        const self: WebDisplayInteractionManager = this;
+        //this.osmdSheetMusicContainer[this.downEventName] = this.downEventListener.bind(this);
+        this.osmdSheetMusicContainer.addEventListener(this.downEventName, this.downEventListener.bind(this));
+
+        this.osmdSheetMusicContainer.addEventListener("touchend", this.touchEndEventListener.bind(this));
+
+        document.addEventListener(self.moveEventName, this.moveEventListener.bind(this));
+
+        window.addEventListener("resize", this.resizeEventListener.bind(this));
+    }
+
+    //Millis of how long is valid for the next click of a double click
+    private readonly DOUBLE_CLICK_WINDOW: number = 200;
+    private clickTimeout: NodeJS.Timeout;
+    private lastClick: number = 0;
+    private downEventListener(clickEvent: MouseEvent | TouchEvent): void {
+        //clickEvent.preventDefault();
+        const currentTime: number = new Date().getTime();
+        const clickLength: number = currentTime - this.lastClick;
+        clearTimeout(this.clickTimeout);
+        let x: number = 0;
+        let y: number = 0;
+        if (this.isTouchDevice && clickEvent instanceof TouchEvent) {
+            x = clickEvent.touches[0].pageX;
+            y = clickEvent.touches[0].pageY;
+        } else if (clickEvent instanceof MouseEvent) {
+            x = clickEvent.pageX;
+            y = clickEvent.pageY;
+        }
+        const clickMinusOffset: PointF2D = this.getOffsetCoordinates(x, y);
+
+        if (clickLength < this.DOUBLE_CLICK_WINDOW && clickLength > 0) {
+            //double click
+            this.doubleClick(clickMinusOffset.x, clickMinusOffset.y);
+        } else {
+            const self: WebDisplayInteractionManager = this;
+            this.clickTimeout = setTimeout(function(): void {
+                clearTimeout(this.clickTimeout);
+                if (self.isTouchDevice) {
+                    self.touchDown(clickMinusOffset.x, clickMinusOffset.y, undefined);
+                } else {
+                    self.click(clickMinusOffset.x, clickMinusOffset.y);
+                }
+            },                             this.DOUBLE_CLICK_WINDOW);
+        }
+        this.lastClick = currentTime;
+    }
+
+    private moveEventListener(mouseMoveEvent: MouseEvent | TouchEvent): void {
+        //mouseMoveEvent.preventDefault();
+        let x: number = 0;
+        let y: number = 0;
+        if (this.isTouchDevice && mouseMoveEvent instanceof TouchEvent) {
+            x = mouseMoveEvent.touches[0].clientX;
+            y = mouseMoveEvent.touches[0].clientY;
+        } else if (mouseMoveEvent instanceof MouseEvent) {
+            x = mouseMoveEvent.clientX;
+            y = mouseMoveEvent.clientY;
+        }
+        const clickMinusOffset: PointF2D = this.getOffsetCoordinates(x, y);
+        this.move(clickMinusOffset.x, clickMinusOffset.y);
+    }
+
+    private touchEndEventListener(clickEvent: TouchEvent): void {
+        const touchMinusOffset: PointF2D = this.getOffsetCoordinates(clickEvent.touches[0].pageX, clickEvent.touches[0].pageY);
+        this.touchUp(touchMinusOffset.x, touchMinusOffset.y);
+    }
+
+
+    private resizeEventListener(): void {
+        this.displaySizeChanged(this.osmdSheetMusicContainer.clientWidth, this.osmdSheetMusicContainer.clientHeight);
+    }
+
+    private getOffsetCoordinates(clickX: number, clickY: number): PointF2D {
+        const sheetX: number = clickX - this.fullOffsetLeft;
+        const sheetY: number = clickY - this.fullOffsetTop;
+        return new PointF2D(sheetX, sheetY);
+    }
+}

+ 6 - 0
src/Display/index.ts

@@ -0,0 +1,6 @@
+export * from "./AbstractDisplayInteractionManager";
+export * from "./AbstractZoomView";
+export * from "./PlaybackCursorUserInteractionManager";
+export * from "./ScreenViewingRegion";
+export * from "./SheetRenderingManager";
+export * from "./WebDisplayInteractionManager";

+ 30 - 0
src/MusicalScore/Exceptions.ts

@@ -0,0 +1,30 @@
+
+export class MusicSheetReadingException implements Error {
+    public name: string;
+    public message: string;
+    constructor(message: string, e?: Error) {
+        //super(message);
+        this.message = message;
+        if (e) {
+            this.message += " " + e.toString();
+        }
+    }
+}
+
+
+export class ArgumentOutOfRangeException implements Error {
+    public name: string;
+    public message: string;
+    constructor(message: string) {
+        //super(message);
+        this.message = message;
+    }
+}
+
+export class InvalidEnumArgumentException implements Error {
+    public name: string;
+    public message: string;
+    constructor(message: string) {
+        this.message = message;
+    }
+}

+ 38 - 0
src/MusicalScore/Graphical/AbstractGraphicalExpression.ts

@@ -0,0 +1,38 @@
+import { GraphicalObject } from "./GraphicalObject";
+import { GraphicalLabel } from "./GraphicalLabel";
+import { StaffLine } from "./StaffLine";
+import { BoundingBox } from "./BoundingBox";
+import { AbstractExpression, PlacementEnum } from "../VoiceData/Expressions/AbstractExpression";
+import { EngravingRules } from "./EngravingRules";
+import { SourceMeasure } from "../VoiceData/SourceMeasure";
+
+export abstract class AbstractGraphicalExpression extends GraphicalObject {
+    protected label: GraphicalLabel;
+    protected parentStaffLine: StaffLine;
+    /** Internal cache of read expression */
+    protected expression: AbstractExpression;
+    /** EngravingRules for positioning */
+    protected rules: EngravingRules;
+    protected parentMeasure: SourceMeasure;
+
+    constructor(parentStaffline: StaffLine, expression: AbstractExpression, measure: SourceMeasure) {
+        super();
+        this.expression = expression;
+        this.parentMeasure = measure; // could be undefined!
+        this.boundingBox = new BoundingBox(this, parentStaffline.PositionAndShape);
+        this.parentStaffLine = parentStaffline;
+        this.parentStaffLine.AbstractExpressions.push(this);
+        this.rules = parentStaffline.ParentMusicSystem.rules;
+    }
+
+    /** Graphical label of the expression if available */
+    get Label(): GraphicalLabel { return this.label; }
+    /** Staffline where the expression is attached to */
+    public get ParentStaffLine(): StaffLine { return this.parentStaffLine; }
+    public get SourceExpression(): AbstractExpression { return this.expression; }
+    public get Placement(): PlacementEnum { return this.expression.Placement; }
+
+    //#region abstract methods
+    public abstract updateSkyBottomLine(): void;
+    //#endregion
+}

+ 16 - 0
src/MusicalScore/Graphical/AbstractGraphicalInstruction.ts

@@ -0,0 +1,16 @@
+import {GraphicalStaffEntry} from "./GraphicalStaffEntry";
+import {GraphicalObject} from "./GraphicalObject";
+
+export abstract class AbstractGraphicalInstruction extends GraphicalObject {
+    protected parent: GraphicalStaffEntry;
+    constructor(parent: GraphicalStaffEntry) {
+        super();
+        this.parent = parent;
+    }
+    public get Parent(): GraphicalStaffEntry {
+        return this.parent;
+    }
+    public set Parent(value: GraphicalStaffEntry) {
+        this.parent = value;
+    }
+}

+ 128 - 0
src/MusicalScore/Graphical/AccidentalCalculator.ts

@@ -0,0 +1,128 @@
+import {AccidentalEnum} from "../../Common/DataObjects/Pitch";
+import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction";
+import {GraphicalNote} from "./GraphicalNote";
+import {Pitch} from "../../Common/DataObjects/Pitch";
+import {NoteEnum} from "../../Common/DataObjects/Pitch";
+import { Dictionary } from "typescript-collections";
+// import { Dictionary } from "typescript-collections/dist/lib";
+import { MusicSheetCalculator } from "./MusicSheetCalculator";
+
+/**
+ * Compute the accidentals for notes according to the current key instruction
+ */
+export class AccidentalCalculator {
+    private keySignatureNoteAlterationsDict: Dictionary<number, AccidentalEnum> = new Dictionary<number, AccidentalEnum>();
+    private currentAlterationsComparedToKeyInstructionList: number[] = [];
+    private currentInMeasureNoteAlterationsDict: Dictionary<number, AccidentalEnum> = new Dictionary<number, AccidentalEnum>();
+    private activeKeyInstruction: KeyInstruction;
+
+    public get ActiveKeyInstruction(): KeyInstruction {
+        return this.activeKeyInstruction;
+    }
+
+    public set ActiveKeyInstruction(value: KeyInstruction) {
+        this.activeKeyInstruction = value;
+        this.reactOnKeyInstructionChange();
+    }
+
+    /**
+     * This method is called after each Measure
+     * It clears the in-measure alterations dict for the next measure
+     * and pre-loads with the alterations of the key signature
+     */
+    public doCalculationsAtEndOfMeasure(): void {
+        this.currentInMeasureNoteAlterationsDict.clear();
+        this.currentAlterationsComparedToKeyInstructionList.clear();
+        for (const key of this.keySignatureNoteAlterationsDict.keys()) {
+            this.currentInMeasureNoteAlterationsDict.setValue(key, this.keySignatureNoteAlterationsDict.getValue(key));
+        }
+    }
+
+    public checkAccidental(graphicalNote: GraphicalNote, pitch: Pitch): void {
+        if (!pitch) {
+            return;
+        }
+        const pitchKey: number = <number>pitch.FundamentalNote + pitch.Octave * 12;
+        /*let pitchKeyGivenInMeasureDict: boolean = this.currentInMeasureNoteAlterationsDict.containsKey(pitchKey);
+        if (
+            (pitchKeyGivenInMeasureDict && this.currentInMeasureNoteAlterationsDict.getValue(pitchKey) !== pitch.Accidental)
+            || (!pitchKeyGivenInMeasureDict && pitch.Accidental !== AccidentalEnum.NONE)
+        ) {
+            if (this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey) === -1) {
+                this.currentAlterationsComparedToKeyInstructionList.push(pitchKey);
+            }
+            this.currentInMeasureNoteAlterationsDict.setValue(pitchKey, pitch.Accidental);
+            this.symbolFactory.addGraphicalAccidental(graphicalNote, pitch);
+        } else if (
+            this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey) !== -1
+            && ((pitchKeyGivenInMeasureDict && this.currentInMeasureNoteAlterationsDict.getValue(pitchKey) !== pitch.Accidental)
+            || (!pitchKeyGivenInMeasureDict && pitch.Accidental === AccidentalEnum.NONE))
+        ) {
+            this.currentAlterationsComparedToKeyInstructionList.splice(this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey), 1);
+            this.currentInMeasureNoteAlterationsDict.setValue(pitchKey, pitch.Accidental);
+            this.symbolFactory.addGraphicalAccidental(graphicalNote, pitch);
+        }*/
+
+        const isInCurrentAlterationsToKeyList: boolean = this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey) >= 0;
+        if (this.currentInMeasureNoteAlterationsDict.containsKey(pitchKey)) {
+            if (isInCurrentAlterationsToKeyList) {
+                this.currentAlterationsComparedToKeyInstructionList.splice(this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey), 1);
+            }
+            if (this.currentInMeasureNoteAlterationsDict.getValue(pitchKey) !== pitch.AccidentalHalfTones) {
+                if (this.keySignatureNoteAlterationsDict.containsKey(pitchKey) &&
+                    this.keySignatureNoteAlterationsDict.getValue(pitchKey) !== pitch.AccidentalHalfTones) {
+                    this.currentAlterationsComparedToKeyInstructionList.push(pitchKey);
+                    this.currentInMeasureNoteAlterationsDict.setValue(pitchKey, pitch.AccidentalHalfTones);
+                } else if (pitch.Accidental !== AccidentalEnum.NONE) {
+                    this.currentInMeasureNoteAlterationsDict.remove(pitchKey);
+                }
+
+                const inMeasureAlterationAccidental: AccidentalEnum = this.currentInMeasureNoteAlterationsDict.getValue(pitchKey);
+                if (pitch.Accidental === AccidentalEnum.NONE) {
+                    if (Math.abs(inMeasureAlterationAccidental) === 0.5) {
+                        // fix to remember quartersharp and quarterflat and not make them natural on following notes
+                        pitch = new Pitch(pitch.FundamentalNote, pitch.Octave, AccidentalEnum.NONE);
+                    } else {
+                        // If an AccidentalEnum.NONE is given, it would not be rendered.
+                        // We need here to convert to a AccidentalEnum.NATURAL:
+                        pitch = new Pitch(pitch.FundamentalNote, pitch.Octave, AccidentalEnum.NATURAL);
+                    }
+                }
+                MusicSheetCalculator.symbolFactory.addGraphicalAccidental(graphicalNote, pitch);
+            }
+        } else { // pitchkey not in measure dict:
+            if (pitch.Accidental !== AccidentalEnum.NONE) {
+                if (!isInCurrentAlterationsToKeyList) {
+                    this.currentAlterationsComparedToKeyInstructionList.push(pitchKey);
+                }
+                this.currentInMeasureNoteAlterationsDict.setValue(pitchKey, pitch.AccidentalHalfTones);
+                MusicSheetCalculator.symbolFactory.addGraphicalAccidental(graphicalNote, pitch);
+            } else {
+                if (isInCurrentAlterationsToKeyList) {
+                    // we need here a AccidentalEnum.NATURAL now to get it rendered - AccidentalEnum.NONE would not be rendered
+                    pitch = new Pitch(pitch.FundamentalNote, pitch.Octave, AccidentalEnum.NATURAL);
+                    this.currentAlterationsComparedToKeyInstructionList.splice(this.currentAlterationsComparedToKeyInstructionList.indexOf(pitchKey), 1);
+                    MusicSheetCalculator.symbolFactory.addGraphicalAccidental(graphicalNote, pitch);
+                }
+            }
+        }
+    }
+
+    private reactOnKeyInstructionChange(): void {
+        const noteEnums: NoteEnum[] = this.activeKeyInstruction.AlteratedNotes;
+        let keyAccidentalType: AccidentalEnum;
+        if (this.activeKeyInstruction.Key > 0) {
+            keyAccidentalType = AccidentalEnum.SHARP;
+        } else {
+            keyAccidentalType = AccidentalEnum.FLAT;
+        }
+        this.keySignatureNoteAlterationsDict.clear();
+        this.currentAlterationsComparedToKeyInstructionList.length = 0;
+        for (let octave: number = -9; octave < 9; octave++) {
+            for (let i: number = 0; i < noteEnums.length; i++) {
+                this.keySignatureNoteAlterationsDict.setValue(<number>noteEnums[i] + octave * 12, Pitch.HalfTonesFromAccidental(keyAccidentalType));
+            }
+        }
+        this.doCalculationsAtEndOfMeasure();
+    }
+}

+ 743 - 0
src/MusicalScore/Graphical/BoundingBox.ts

@@ -0,0 +1,743 @@
+import log from "loglevel";
+import {ArgumentOutOfRangeException} from "../Exceptions";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {SizeF2D} from "../../Common/DataObjects/SizeF2D";
+import {RectangleF2D} from "../../Common/DataObjects/RectangleF2D";
+import { StaffLineActivitySymbol } from "./StaffLineActivitySymbol";
+import { EngravingRules } from "./EngravingRules";
+import { Clickable } from "./Clickable";
+import { GraphicalObject } from "./GraphicalObject";
+
+/**
+ * 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;
+    protected relativePositionHasBeenSet: boolean = false;
+    protected xBordersHaveBeenSet: boolean = false;
+    protected yBordersHaveBeenSet: boolean = false;
+    protected absolutePosition: PointF2D = new PointF2D();
+    protected relativePosition: PointF2D = new PointF2D();
+    protected size: SizeF2D = new SizeF2D();
+    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;
+    protected borderBottom: number = 0;
+    protected borderMarginLeft: number = 0;
+    protected borderMarginRight: number = 0;
+    protected borderMarginTop: number = 0;
+    protected borderMarginBottom: number = 0;
+    protected boundingRectangle: RectangleF2D;
+    protected boundingMarginRectangle: RectangleF2D;
+    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 isSymbol Defines the bounding box to be symbol thus not calculating its boundaries by itself. NOTE: Borders need to be set!
+     */
+    constructor(dataObject: Object = undefined, parent: BoundingBox = undefined, isSymbol: boolean = false) {
+        this.parent = parent;
+        this.dataObject = dataObject;
+        this.isSymbol = isSymbol;
+        this.xBordersHaveBeenSet = false;
+        this.yBordersHaveBeenSet = false;
+        if (parent) {
+            this.Parent = parent;
+        }
+    }
+
+    public get RelativePositionHasBeenSet(): boolean {
+        return this.relativePositionHasBeenSet;
+    }
+
+    public get XBordersHaveBeenSet(): boolean {
+        return this.xBordersHaveBeenSet;
+    }
+
+    public set XBordersHaveBeenSet(value: boolean) {
+        this.xBordersHaveBeenSet = value;
+    }
+
+    public get YBordersHaveBeenSet(): boolean {
+        return this.yBordersHaveBeenSet;
+    }
+
+    public set YBordersHaveBeenSet(value: boolean) {
+        this.yBordersHaveBeenSet = value;
+    }
+
+    public get AbsolutePosition(): PointF2D {
+        return this.absolutePosition;
+    }
+
+    public set AbsolutePosition(value: PointF2D) {
+        this.absolutePosition = value;
+    }
+
+    public get RelativePosition(): PointF2D {
+        return this.relativePosition;
+    }
+
+    public set RelativePosition(value: PointF2D) {
+        this.relativePosition = value;
+        this.relativePositionHasBeenSet = true;
+    }
+
+    public get Size(): SizeF2D {
+        return this.size;
+    }
+
+    public set Size(value: SizeF2D) {
+        this.size = value;
+    }
+
+    public get MarginSize(): SizeF2D {
+        return this.marginSize;
+    }
+
+    public get UpperLeftCorner(): PointF2D {
+        return this.upperLeftCorner;
+    }
+
+    public get UpperLeftMarginCorner(): PointF2D {
+        return this.upperLeftMarginCorner;
+    }
+
+    public get BorderLeft(): number {
+        return this.borderLeft;
+    }
+
+    public set BorderLeft(value: number) {
+        this.borderLeft = value;
+        this.calculateRectangle();
+    }
+
+    public get BorderRight(): number {
+        return this.borderRight;
+    }
+
+    public set BorderRight(value: number) {
+        this.borderRight = value;
+        this.calculateRectangle();
+    }
+
+    public get BorderTop(): number {
+        return this.borderTop;
+    }
+
+    public set BorderTop(value: number) {
+        this.borderTop = value;
+        this.calculateRectangle();
+    }
+
+    public get BorderBottom(): number {
+        return this.borderBottom;
+    }
+
+    public set BorderBottom(value: number) {
+        this.borderBottom = value;
+        this.calculateRectangle();
+    }
+
+    public get BorderMarginLeft(): number {
+        return this.borderMarginLeft > this.borderLeft ? this.borderLeft : this.borderMarginLeft;
+    }
+
+    public set BorderMarginLeft(value: number) {
+        this.borderMarginLeft = value;
+        this.calculateMarginRectangle();
+    }
+
+    public get BorderMarginRight(): number {
+        return this.borderMarginRight < this.borderRight ? this.borderRight : this.borderMarginRight;
+    }
+
+    public set BorderMarginRight(value: number) {
+        this.borderMarginRight = value;
+        this.calculateMarginRectangle();
+    }
+
+    public get BorderMarginTop(): number {
+        return this.borderMarginTop > this.borderTop ? this.borderTop : this.borderMarginTop;
+    }
+
+    public set BorderMarginTop(value: number) {
+        this.borderMarginTop = value;
+        this.calculateMarginRectangle();
+    }
+
+    public get BorderMarginBottom(): number {
+        return this.borderMarginBottom < this.borderBottom ? this.borderBottom : this.borderMarginBottom;
+    }
+
+    public set BorderMarginBottom(value: number) {
+        this.borderMarginBottom = value;
+        this.calculateMarginRectangle();
+    }
+
+    public get BoundingRectangle(): RectangleF2D {
+        return this.boundingRectangle;
+    }
+
+    public get BoundingMarginRectangle(): RectangleF2D {
+        return this.boundingMarginRectangle;
+    }
+
+    public get ChildElements(): BoundingBox[] {
+        return this.childElements;
+    }
+
+    public set ChildElements(value: BoundingBox[]) {
+        this.childElements = value;
+    }
+
+    public get Parent(): BoundingBox {
+        return this.parent;
+    }
+
+    public set Parent(value: BoundingBox) {
+        if (this.parent) {
+            // remove from old parent
+            const index: number = this.parent.ChildElements.indexOf(this, 0);
+            if (index > -1) {
+                this.parent.ChildElements.splice(index, 1);
+            }
+        }
+        this.parent = value;
+        // add to new parent
+        if (this.parent?.ChildElements?.indexOf(this) > -1) {
+            log.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 {
+        return this.dataObject;
+    }
+
+
+    /**
+     * Get the center of a bounding box
+     * @param boundingBox Bounding box to check
+     */
+    public get Center(): PointF2D {
+        return new PointF2D(this.RelativePosition.x + (this.BorderMarginRight + this.BorderMarginLeft),
+                            this.RelativePosition.y + (this.BorderMarginBottom + this.BorderMarginTop));
+    }
+
+    public setAbsolutePositionFromParent(): void {
+        if (this.parent) {
+            this.absolutePosition.x = this.parent.AbsolutePosition.x + this.relativePosition.x;
+            this.absolutePosition.y = this.parent.AbsolutePosition.y + this.relativePosition.y;
+        } else {
+            this.absolutePosition = this.relativePosition;
+        }
+    }
+
+    /**
+     * 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) {
+        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) {
+            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
+     */
+    public calculateAbsolutePositionsRecursive(x: number, y: number): void {
+        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) {
+            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 {
+        if (this.childElements.length === 0) {
+            return;
+        }
+        for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
+            const childElement: BoundingBox = this.ChildElements[idx];
+            childElement.calculateBoundingBox();
+        }
+
+        // initialize with max/min values
+        let minLeft: number = Number.MAX_VALUE;
+        let maxRight: number = Number.MIN_VALUE;
+        let minTop: number = Number.MAX_VALUE;
+        let maxBottom: number = Number.MIN_VALUE;
+        let minMarginLeft: number = Number.MAX_VALUE;
+        let maxMarginRight: number = Number.MIN_VALUE;
+        let minMarginTop: number = Number.MAX_VALUE;
+        let maxMarginBottom: number = Number.MIN_VALUE;
+
+        // apart from symbol elements, where we initialize with the symbol's borders
+        if (this.isSymbol) {
+            minLeft = this.borderLeft;
+            maxRight = this.borderRight;
+            minTop = this.borderTop;
+            maxBottom = this.borderBottom;
+            minMarginLeft = this.borderMarginLeft;
+            maxMarginRight = this.borderMarginRight;
+            minMarginTop = this.borderMarginTop;
+            maxMarginBottom = this.borderMarginBottom;
+        }
+
+        // ChildElements will have their borders calculated, so calculate current borders
+        for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++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);
+            maxBottom = Math.max(maxBottom, childElement.relativePosition.y + childElement.borderBottom);
+            minMarginLeft = Math.min(minMarginLeft, childElement.relativePosition.x + childElement.borderMarginLeft);
+            maxMarginRight = Math.max(maxMarginRight, childElement.relativePosition.x + childElement.borderMarginRight);
+            minMarginTop = Math.min(minMarginTop, childElement.relativePosition.y + childElement.borderMarginTop);
+            maxMarginBottom = Math.max(maxMarginBottom, childElement.relativePosition.y + childElement.borderMarginBottom);
+        }
+
+        // ChildElements will have their borders calculated, so calculate current borders
+        this.borderLeft = minLeft;
+        this.borderRight = maxRight;
+        this.borderTop = minTop;
+        this.borderBottom = maxBottom;
+        this.borderMarginLeft = minMarginLeft;
+        this.borderMarginRight = maxMarginRight;
+        this.borderMarginTop = minMarginTop;
+        this.borderMarginBottom = maxMarginBottom;
+        this.calculateRectangle();
+        this.calculateMarginRectangle();
+        this.xBordersHaveBeenSet = true;
+        this.yBordersHaveBeenSet = true;
+    }
+
+    public calculateTopBottomBorders(): void {
+        if (this.childElements.length === 0) {
+            return;
+        }
+        for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
+            const childElement: BoundingBox = this.ChildElements[idx];
+            childElement.calculateTopBottomBorders();
+        }
+        let minTop: number = Number.MAX_VALUE;
+        let maxBottom: number = Number.MIN_VALUE;
+        let minMarginTop: number = Number.MAX_VALUE;
+        let maxMarginBottom: number = Number.MIN_VALUE;
+        if (this.yBordersHaveBeenSet) {
+            minTop = this.borderTop;
+            maxBottom = this.borderBottom;
+            minMarginTop = this.borderMarginTop;
+            maxMarginBottom = this.borderMarginBottom;
+        }
+        for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
+            const childElement: BoundingBox = this.ChildElements[idx];
+            minTop = Math.min(minTop, childElement.relativePosition.y + childElement.borderTop);
+            if (!EngravingRules.FixStafflineBoundingBox || !(childElement.dataObject instanceof StaffLineActivitySymbol)) {
+                maxBottom = Math.max(maxBottom, childElement.relativePosition.y + childElement.borderBottom);
+                // TODO there's a problem with the bottom bounding box of many stafflines, often caused by StaffLineActivitySymbol,
+                // often leading to the page SVG canvas being unnecessarily long in y-direction. This seems to be remedied by this workaround.
+                // see #643
+            }
+            minMarginTop = Math.min(minMarginTop, childElement.relativePosition.y + childElement.borderMarginTop);
+            maxMarginBottom = Math.max(maxMarginBottom, childElement.relativePosition.y + childElement.borderMarginBottom);
+        }
+        this.borderTop = minTop;
+        this.borderBottom = maxBottom;
+        this.borderMarginTop = minMarginTop;
+        this.borderMarginBottom = maxMarginBottom;
+        this.calculateRectangle();
+        this.calculateMarginRectangle();
+    }
+
+    /**
+     * This method computes the first non-overlapping position in the placementPsi Element for the current (this) positionAndShapeInfo
+     * @param placementPsi
+     * @param direction
+     * @param position
+     */
+    public computeNonOverlappingPositionWithMargin(placementPsi: BoundingBox, direction: ColDirEnum, position: PointF2D): void {
+        this.RelativePosition = new PointF2D(position.x, position.y);
+        this.setAbsolutePositionFromParent();
+        let currentPosition: number = 0.0;
+        let hasBeenMoved: boolean = false;
+        do {
+            switch (direction) {
+                case ColDirEnum.Left:
+                case ColDirEnum.Right:
+                    currentPosition = this.relativePosition.x;
+                    placementPsi.calculateMarginPositionAlongDirection(this, direction);
+                    hasBeenMoved = Math.abs(currentPosition - this.relativePosition.x) > 0.001;
+                    break;
+                case ColDirEnum.Up:
+                case ColDirEnum.Down:
+                    currentPosition = this.relativePosition.y;
+                    placementPsi.calculateMarginPositionAlongDirection(this, direction);
+                    hasBeenMoved = Math.abs(currentPosition - this.relativePosition.y) > 0.001;
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException("direction");
+            }
+        }
+        while (hasBeenMoved);
+    }
+
+    /**
+     * This method detects a collision (without margins)
+     * @param psi
+     * @returns {boolean}
+     */
+    public collisionDetection(psi: BoundingBox): boolean {
+        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);
+        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;
+        }
+        return false;
+    }
+
+    /**
+     * This method checks if the given Psi's Margins lie inside the current Psi's Margins.
+     * @param psi
+     * @returns {boolean}
+     */
+    public liesInsideBorders(psi: BoundingBox): boolean {
+        const leftBorderInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= (psi.absolutePosition.x + psi.borderLeft)
+            && (psi.absolutePosition.x + psi.borderLeft) <= (this.AbsolutePosition.x + this.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) {
+            const topBorderInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= (psi.absolutePosition.y + psi.borderTop)
+                && (psi.absolutePosition.y + psi.borderTop) <= (this.AbsolutePosition.y + this.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;
+            }
+        }
+        return false;
+    }
+
+    public pointLiesInsideBorders(position: PointF2D): boolean {
+        const xInside: boolean = (this.AbsolutePosition.x + this.borderLeft) <= position.x && position.x <= (this.AbsolutePosition.x + this.borderRight);
+        if (xInside) {
+            const yInside: boolean = (this.AbsolutePosition.y + this.borderTop) <= position.y && position.y <= (this.AbsolutePosition.y + this.borderBottom);
+            if (yInside) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method detects a collision (margin-wide)
+     * @param psi
+     * @returns {boolean}
+     */
+    public marginCollisionDetection(psi: BoundingBox): boolean {
+        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);
+        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;
+        }
+        return false;
+    }
+
+    /**
+     * This method checks if the given Psi's Margins lie inside the current Psi's Margins
+     * @param psi
+     * @returns {boolean}
+     */
+    public liesInsideMargins(psi: BoundingBox): boolean {
+        const leftMarginInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= (psi.absolutePosition.x + psi.borderMarginLeft)
+            && (psi.absolutePosition.x + psi.borderMarginLeft) <= (this.AbsolutePosition.x + this.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) {
+            const topMarginInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= (psi.absolutePosition.y + psi.borderMarginTop)
+                && (psi.absolutePosition.y + psi.borderMarginTop) <= (this.AbsolutePosition.y + this.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;
+            }
+        }
+        return false;
+    }
+
+    public pointLiesInsideMargins(position: PointF2D): boolean {
+        const xInside: boolean = (this.AbsolutePosition.x + this.borderMarginLeft) <= position.x
+            && position.x <= (this.AbsolutePosition.x + this.borderMarginRight);
+        if (xInside) {
+            const yInside: boolean = (this.AbsolutePosition.y + this.borderMarginTop) <= position.y
+                && position.y <= (this.AbsolutePosition.y + this.borderMarginBottom);
+            if (yInside) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method computes the first non-overlapping position in the placementPsi Element for the current (this) positionAndShapeInfo
+     * @param placementPsi
+     * @param direction
+     * @param position
+     */
+    public computeNonOverlappingPosition(placementPsi: BoundingBox, direction: ColDirEnum, position: PointF2D): void {
+        this.RelativePosition = new PointF2D(position.x, position.y);
+        this.setAbsolutePositionFromParent();
+        let currentPosition: number = 0.0;
+        let hasBeenMoved: boolean = false;
+        do {
+            switch (direction) {
+                case ColDirEnum.Left:
+                case ColDirEnum.Right:
+                    currentPosition = this.relativePosition.x;
+                    placementPsi.calculatePositionAlongDirection(this, direction);
+                    hasBeenMoved = Math.abs(currentPosition - this.relativePosition.x) > 0.0001;
+                    break;
+                case ColDirEnum.Up:
+                case ColDirEnum.Down:
+                    currentPosition = this.relativePosition.y;
+                    placementPsi.calculatePositionAlongDirection(this, direction);
+                    hasBeenMoved = Math.abs(currentPosition - this.relativePosition.y) > 0.0001;
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException("direction");
+            }
+        } while (hasBeenMoved); // as long as the element is moved
+    }
+
+    public getClickedObjectOfType<T>(clickPosition: PointF2D): T {
+        const obj: Object = this.dataObject;
+        if (this.pointLiesInsideBorders(clickPosition) && (<T>obj)) {
+            return (obj as T);
+        }
+        for (let idx: number = 0, len: number = this.childElements.length; idx < len; ++idx) {
+            const psi: BoundingBox = this.childElements[idx];
+            const innerObject: Object = psi.getClickedObjectOfType<T>(clickPosition);
+            if (innerObject) {
+                return (innerObject as T);
+            }
+        }
+        return undefined;
+    }
+
+    //See below method. Have to implement specific due to current Typescript limitations
+    public getClickedClickable(clickPosition: PointF2D): Clickable {
+        const obj: Object = this.dataObject;
+        if (this.pointLiesInsideBorders(clickPosition) && obj && obj instanceof Clickable) {
+            return obj;
+        }
+        for (let idx: number = 0, len: number = this.childElements.length; idx < len; ++idx) {
+            const psi: BoundingBox = this.childElements[idx];
+            const innerObject: Object = psi.getClickedClickable(clickPosition);
+            if (innerObject && innerObject instanceof Clickable) {
+                return innerObject;
+            }
+        }
+        return undefined;
+    }
+
+    //Generics don't work like this in TS. Casting doesn't filter out objects.
+    //instanceof doesn't work either with generic types. Hopefully instanceof becomes available at some point, for now we have to do annoyingly
+    //specific implementations after calling this to filter the objects.
+    public getObjectsInRegion<T extends GraphicalObject>(region: BoundingBox, liesInside: boolean = true,
+                                                         className: string = GraphicalObject.name): T[] {
+        let result: T[] = [];
+        for (const child of this.childElements) {
+            result = result.concat(child.getObjectsInRegion<T>(region, liesInside, className));
+        }
+
+        //if (!result || result.length === 0) {
+        // audioplayer: this.dataObject as T
+        if (this.dataObject && (this.dataObject as T).isInstanceOfClass(className)) {
+            if (liesInside) {
+                if (region.liesInsideBorders(this)) {
+                    result.push(this.dataObject as T);
+                }
+            } else {
+                if (region.collisionDetection(this)) {
+                    result.push(this.dataObject as T);
+                }
+            }
+            // FIXME Andrea: add here "return []"?
+        }
+        //}
+        return result;
+        //return this.childElements.SelectMany(psi => psi.getObjectsInRegion<T>(region, liesInside));
+    }
+
+    protected calculateRectangle(): void {
+        this.upperLeftCorner = new PointF2D(this.BorderLeft, this.BorderTop);
+        this.size = new SizeF2D(this.BorderRight - this.BorderLeft, this.BorderBottom - this.BorderTop);
+        this.boundingRectangle = RectangleF2D.createFromLocationAndSize(this.upperLeftCorner, this.size);
+    }
+
+    protected calculateMarginRectangle(): void {
+        this.upperLeftMarginCorner = new PointF2D(this.BorderMarginLeft, this.BorderMarginTop);
+        this.marginSize = new SizeF2D(this.BorderMarginRight - this.BorderMarginLeft, this.BorderMarginBottom - this.BorderMarginTop);
+        this.boundingMarginRectangle = RectangleF2D.createFromLocationAndSize(this.upperLeftMarginCorner, this.marginSize);
+    }
+
+    /**
+     * This method calculates the margin border along the given direction so that no collision takes place along this direction
+     * @param toBePlaced
+     * @param direction
+     */
+    private calculateMarginPositionAlongDirection(toBePlaced: BoundingBox, direction: ColDirEnum): void {
+        // now this will be the "known" Element, about to get bigger with the toBePlaced
+        // eg toBePlaced will always be in the PositionAndShape hierarchy a Child of this
+        // example: this = StaffEntry, toBePlaced = Accidental
+
+        // logical return
+        if (this === toBePlaced) {
+            return;
+        }
+
+        // check for collision only at symbols and return border
+        if (this.isSymbol && this.marginCollisionDetection(toBePlaced)) {
+            let shiftDistance: number = 0;
+            switch (direction) {
+                case ColDirEnum.Left:
+                    shiftDistance = (this.absolutePosition.x + this.borderMarginLeft) - (toBePlaced.absolutePosition.x + toBePlaced.borderMarginRight);
+                    toBePlaced.relativePosition.x += shiftDistance;
+                    toBePlaced.absolutePosition.x += shiftDistance;
+                    return;
+                case ColDirEnum.Right:
+                    shiftDistance = (this.absolutePosition.x + this.borderMarginRight) - (toBePlaced.absolutePosition.x + toBePlaced.borderMarginLeft);
+                    toBePlaced.relativePosition.x += shiftDistance;
+                    toBePlaced.absolutePosition.x += shiftDistance;
+                    return;
+                case ColDirEnum.Up:
+                    shiftDistance = (this.absolutePosition.y + this.borderMarginTop) - (toBePlaced.absolutePosition.y + toBePlaced.borderMarginBottom);
+                    toBePlaced.relativePosition.y += shiftDistance;
+                    toBePlaced.absolutePosition.y += shiftDistance;
+                    return;
+                case ColDirEnum.Down:
+                    shiftDistance = (this.absolutePosition.y + this.borderMarginBottom) - (toBePlaced.absolutePosition.y + toBePlaced.borderMarginTop);
+                    toBePlaced.relativePosition.y += shiftDistance;
+                    toBePlaced.absolutePosition.y += shiftDistance;
+                    return;
+                default:
+                    throw new ArgumentOutOfRangeException("direction");
+            }
+        }
+
+        // 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) {
+            const childElement: BoundingBox = this.ChildElements[idx];
+            childElement.calculateMarginPositionAlongDirection(toBePlaced, direction);
+        }
+    }
+
+    /**
+     * This method calculates the border along the given direction so that no collision takes place along this direction
+     * @param toBePlaced
+     * @param direction
+     */
+    private calculatePositionAlongDirection(toBePlaced: BoundingBox, direction: ColDirEnum): void {
+        // now this will be the "known" Element, about to get bigger with the toBePlaced
+        // eg toBePlaced will always be in the PositionAndShape hierarchy a Child of this
+        // example: this = StaffEntry, toBePlaced = Accidental
+
+        // logical return
+        if (this === toBePlaced) {
+            return;
+        }
+
+        // check for collision only at symbols and return border
+        if (this.isSymbol && this.collisionDetection(toBePlaced)) {
+            let shiftDistance: number;
+            switch (direction) {
+                case ColDirEnum.Left:
+                    shiftDistance = (this.absolutePosition.x + this.borderLeft) - (toBePlaced.absolutePosition.x + toBePlaced.borderRight);
+                    toBePlaced.relativePosition.x += shiftDistance;
+                    toBePlaced.absolutePosition.x += shiftDistance;
+                    return;
+                case ColDirEnum.Right:
+                    shiftDistance = (this.absolutePosition.x + this.borderRight) - (toBePlaced.absolutePosition.x + toBePlaced.borderLeft);
+                    toBePlaced.relativePosition.x += shiftDistance;
+                    toBePlaced.absolutePosition.x += shiftDistance;
+                    return;
+                case ColDirEnum.Up:
+                    shiftDistance = (this.absolutePosition.y + this.borderTop) - (toBePlaced.absolutePosition.y + toBePlaced.borderBottom);
+                    toBePlaced.relativePosition.y += shiftDistance;
+                    toBePlaced.absolutePosition.y += shiftDistance;
+                    return;
+                case ColDirEnum.Down:
+                    shiftDistance = (this.absolutePosition.y + this.borderBottom) - (toBePlaced.absolutePosition.y + toBePlaced.borderTop);
+                    toBePlaced.relativePosition.y += shiftDistance;
+                    toBePlaced.absolutePosition.y += shiftDistance;
+                    return;
+                default:
+                    throw new ArgumentOutOfRangeException("direction");
+            }
+        }
+
+        // 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) {
+            const childElement: BoundingBox = this.ChildElements[idx];
+            childElement.calculatePositionAlongDirection(toBePlaced, direction);
+        }
+    }
+}
+
+export enum ColDirEnum {
+    Left = 0,
+    Right = 1,
+    Up = 2,
+    Down = 3
+}

+ 5 - 0
src/MusicalScore/Graphical/Clickable.ts

@@ -0,0 +1,5 @@
+import {GraphicalObject} from "./GraphicalObject";
+
+export class Clickable extends GraphicalObject {
+    public dataObject: Object;
+}

+ 131 - 0
src/MusicalScore/Graphical/DrawingEnums.ts

@@ -0,0 +1,131 @@
+// import * as Collections from "typescript-collections";
+// import Collections = require("typescript-collections");
+import { Dictionary } from "typescript-collections";
+
+/**
+ * The supported styles to draw a rectangle on the music sheet
+ */
+export enum OutlineAndFillStyleEnum {
+    BaseWritingColor,
+    FollowingCursor,
+    AlternativeFollowingCursor,
+    PlaybackCursor,
+    Highlighted,
+    ErrorUnderlay,
+    Selected,
+    SelectionSymbol,
+    DebugColor1,
+    DebugColor2,
+    DebugColor3,
+    SplitScreenDivision,
+    GreyTransparentOverlay,
+    MarkedArea1,
+    MarkedArea2,
+    MarkedArea3,
+    MarkedArea4,
+    MarkedArea5,
+    MarkedArea6,
+    MarkedArea7,
+    MarkedArea8,
+    MarkedArea9,
+    MarkedArea10,
+    Comment1,
+    Comment2,
+    Comment3,
+    Comment4,
+    Comment5,
+    Comment6,
+    Comment7,
+    Comment8,
+    Comment9,
+    Comment10
+}
+
+export const OUTLINE_AND_FILL_STYLE_DICT: Dictionary<OutlineAndFillStyleEnum, string> =
+    new 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 supported)
+ */
+export enum GraphicalLayers {
+    Background,
+    Highlight,
+    MeasureError,
+    SelectionSymbol,
+    Cursor,
+    PSI_Debug,
+    Notes,
+    Comment,
+    Debug_above
+}
+
+export enum NoteState {
+    Normal,
+    Selected,
+    Follow_Confirmed,
+    QFeedback_NotFound,
+    QFeedback_OK,
+    QFeedback_Perfect,
+    Debug1,
+    Debug2,
+    Debug3
+}
+
+export enum AutoColorSet {
+    /* different (boomwhacker-like) color set*/
+    C = "#d82c6b",
+    D = "#F89D15",
+    E = "#FFE21A",
+    F = "#4dbd5c",
+    G = "#009D96",
+    A = "#43469d",
+    B = "#76429c",
+    Rest = "#000000"
+
+    // color set from MuseScore Color notehead plugin version 1.1 by Werner Schweer and others
+    /*C = "#eeee00",
+    D = "#9b30ff",
+    E = "#ee9a00",
+    F = "#8b4513",
+    G = "#ff0000",
+    A = "#1e90ff",
+    B = "#00ff00"*/
+}

+ 26 - 0
src/MusicalScore/Graphical/DrawingMode.ts

@@ -0,0 +1,26 @@
+export enum DrawingMode {
+    All,
+    NoOverlays,
+    Leadsheet
+}
+
+export enum MusicSymbolDrawingStyle {
+    Normal,
+    Disabled,
+    Selected,
+    Clickable,
+    PlaybackSymbols,
+    FollowSymbols,
+    QFeedbackNotFound,
+    QFeedbackOk,
+    QFeedbackPerfect,
+    Debug1,
+    Debug2,
+    Debug3
+}
+
+export enum PhonicScoreModes {
+    Following,
+    Midi,
+    Manual
+}

+ 256 - 0
src/MusicalScore/Graphical/DrawingParameters.ts

@@ -0,0 +1,256 @@
+import { EngravingRules } from "./EngravingRules";
+import { PlacementEnum } from "../VoiceData/Expressions/AbstractExpression";
+
+export enum ColoringModes {
+    XML = 0,
+    AutoColoring = 1,
+    CustomColorSet = 2
+}
+
+export enum DrawingParametersEnum {
+    allon = "allon",
+    compact = "compact",
+    compacttight = "compacttight",
+    default = "default",
+    leadsheet = "leadsheet",
+    preview = "preview",
+    thumbnail = "thumbnail",
+}
+
+/** Internal drawing/rendering parameters and broad modes like compact and thumbnail. Overlap with EngravingRules. */
+export class DrawingParameters {
+    /** will set other settings if changed with set method */
+    private drawingParametersEnum: DrawingParametersEnum;
+    private rules: EngravingRules = new EngravingRules();
+    public drawHighlights: boolean;
+    public drawErrors: boolean;
+    public drawSelectionStartSymbol: boolean;
+    public drawSelectionEndSymbol: boolean;
+    public drawCursors: boolean = true;
+    public drawActivitySymbols: boolean;
+    public drawScrollIndicator: boolean;
+    public drawAnnotations: boolean;
+    public drawComments: boolean;
+    public drawMarkedAreas: boolean;
+    public drawTitle: boolean = true;
+    public drawSubtitle: boolean = true;
+    public drawLyricist: boolean = true;
+    public drawComposer: boolean = true;
+    public drawCredits: boolean = true;
+    public drawPartNames: boolean = true;
+    public coloringMode: ColoringModes;
+    public fingeringPosition: PlacementEnum = PlacementEnum.Left;
+    /** Draw notes set to be invisible (print-object="no" in XML). */
+    public drawHiddenNotes: boolean = false;
+
+    constructor(drawingParameters: DrawingParametersEnum = DrawingParametersEnum.default) {
+        this.DrawingParametersEnum = drawingParameters;
+    }
+
+    /** Sets drawing parameters enum and changes settings flags accordingly. */
+    public set DrawingParametersEnum(drawingParametersEnum: DrawingParametersEnum) {
+        this.drawingParametersEnum = drawingParametersEnum;
+        switch (drawingParametersEnum) {
+            case DrawingParametersEnum.allon:
+                this.setForAllOn();
+                break;
+            case DrawingParametersEnum.thumbnail:
+                this.setForThumbnail();
+                break;
+            case DrawingParametersEnum.leadsheet:
+                this.setForLeadsheet();
+                break;
+            case DrawingParametersEnum.compact:
+                this.setForCompactMode();
+                break;
+            case DrawingParametersEnum.compacttight:
+                this.setForCompactTightMode();
+                break;
+            case DrawingParametersEnum.default:
+            default:
+                this.setForDefault();
+        }
+    }
+
+    public get DrawingParametersEnum(): DrawingParametersEnum {
+        return this.drawingParametersEnum;
+    }
+
+    public setForAllOn(): void {
+        this.drawHighlights = true;
+        this.drawErrors = true;
+        this.drawSelectionStartSymbol = true;
+        this.drawSelectionEndSymbol = true;
+        this.drawCursors = true;
+        this.drawActivitySymbols = true;
+        this.drawScrollIndicator = true;
+        this.drawAnnotations = true;
+        this.drawComments = true;
+        this.drawMarkedAreas = true;
+        this.DrawTitle = true;
+        this.DrawSubtitle = true;
+        this.DrawComposer = true;
+        this.DrawLyricist = true;
+        this.drawCredits = true;
+        this.DrawPartNames = true;
+        this.drawHiddenNotes = true;
+        this.rules.CompactMode = false;
+    }
+
+    public setForDefault(): void {
+        this.rules.loadDefaultValues(); // this is not ideal, but it's hard to reset compactTight mode properly
+        this.setForAllOn();
+        this.drawHiddenNotes = false;
+    }
+
+    public setForThumbnail(): void {
+        this.drawHighlights = false;
+        this.drawErrors = false;
+        this.drawSelectionStartSymbol = false;
+        this.drawSelectionStartSymbol = false;
+        this.drawCursors = false;
+        this.drawActivitySymbols = false;
+        this.drawScrollIndicator = false;
+        this.drawAnnotations = true;
+        this.drawComments = true;
+        this.drawMarkedAreas = true;
+        this.drawHiddenNotes = false;
+    }
+
+    public setForCompactMode(): void {
+        // this.setForDefault(); // this would reset all EngravingRules to default values.
+        this.rules.CompactMode = true;
+        this.DrawCredits = false; // sets DrawComposer, DrawTitle, DrawLyricist to false
+        // this.DrawPartNames = true; // unnecessary
+        this.drawHiddenNotes = false;
+    }
+
+    public setForCompactTightMode(): void {
+        this.setForCompactMode(); // also sets CompactMode = true
+        this.DrawPartNames = false;
+
+        this.rules.VoiceSpacingMultiplierVexflow = 0.65;
+        this.rules.VoiceSpacingAddendVexflow = 2.0;
+
+        // tight rendering mode, lower margins and safety distances between systems, staffs etc. may cause overlap.
+        // these options can afterwards be finetuned by setting osmd.rules.BetweenStaffDistance for example
+        this.rules.MinSkyBottomDistBetweenStaves = 1.0; // default 1.0. this can cause collisions with slurs and dynamics sometimes
+        this.rules.MinSkyBottomDistBetweenSystems = 1.0; // default 5.0
+        // note that this.rules === osmd.rules, since it's passed as a reference
+
+        this.rules.BetweenStaffDistance = 2.5;
+        this.rules.StaffDistance = 3.5;
+        this.rules.MinimumDistanceBetweenSystems = 1;
+        // this.rules.PageTopMargin = 0.0; // see this.rules.PageTopMarginNarrow used in compact mode
+        this.rules.PageBottomMargin = 0.0;
+        this.rules.PageLeftMargin = 2.0;
+        this.rules.PageRightMargin = 2.0;
+        // this.BetweenStaffDistance = 2.5 // etc needs to be set in OSMD.rules
+        // this.StaffDistance = 3.5
+        // this.MinimumDistanceBetweenSystems = 1
+    }
+
+    public setForLeadsheet(): void {
+        this.drawHighlights = false;
+        this.drawErrors = false;
+        this.drawSelectionStartSymbol = true;
+        this.drawSelectionEndSymbol = true;
+        this.drawCursors = true;
+        this.drawActivitySymbols = false;
+        this.drawScrollIndicator = true;
+        this.drawAnnotations = true;
+        this.drawComments = true;
+        this.drawMarkedAreas = true;
+    }
+
+    //#region GETTER / SETTER
+    public get DrawCredits(): boolean {
+        return this.drawCredits;
+    }
+
+    public set DrawCredits(value: boolean) {
+        this.drawCredits = value;
+        this.DrawComposer = value;
+        this.DrawTitle = value;
+        this.DrawSubtitle = value;
+        this.DrawLyricist = value;
+    }
+    // TODO these drawCredits settings are duplicate in drawingParameters and EngravingRules. Maybe we only need them in EngravingRules.
+    // this sets the parameter in DrawingParameters, which in turn sets the parameter in EngravingRules.
+    // see settings below that don't call drawingParameters for the immediate approach.
+    // on the other hand, DrawingParameters has the added option of setting broad modes (e.g. compact), though they aren't that useful
+
+    public get DrawTitle(): boolean {
+        return this.drawTitle;
+    }
+
+    /** Enable or disable drawing the Title of the piece. If disabled, will disable drawing Subtitle as well. */
+    public set DrawTitle(value: boolean) {
+        this.drawTitle = value;
+        this.rules.RenderTitle = value;
+        if (!value) { // don't draw subtitle if title isn't drawn
+            this.DrawSubtitle = false;
+        }
+    }
+
+    public get DrawSubtitle(): boolean {
+        return this.drawSubtitle;
+    }
+
+    /** Enable or disable drawing the Subtitle of the piece. If enabled, will enable drawing Title as well. */
+    public set DrawSubtitle(value: boolean) {
+        this.drawSubtitle = value;
+        this.rules.RenderSubtitle = value;
+        if (value) {
+            this.DrawTitle = true; // if subtitle is drawn, title needs to be drawn as well
+        }
+    }
+
+    public get DrawComposer(): boolean {
+        return this.drawComposer;
+    }
+
+    /** Enable or disable drawing a label for the Composer of the piece. */
+    public set DrawComposer(value: boolean) {
+        this.drawComposer = value;
+        this.rules.RenderComposer = value;
+    }
+
+    public get DrawLyricist(): boolean {
+        return this.drawLyricist;
+    }
+
+    public set DrawLyricist(value: boolean) {
+        this.drawLyricist = value;
+        this.rules.RenderLyricist = value;
+    }
+
+    public get DrawPartNames(): boolean {
+        return this.drawPartNames;
+    }
+
+    public set DrawPartNames(value: boolean) {
+        this.drawPartNames = value;
+        this.rules.RenderPartNames = value;
+        if (!this.rules.RenderPartNames) {
+            this.rules.RenderPartAbbreviations = false;
+        }
+    }
+
+    public get FingeringPosition(): PlacementEnum {
+        return this.fingeringPosition;
+    }
+
+    public set FingeringPosition(value: PlacementEnum) {
+        this.fingeringPosition = value;
+        this.rules.FingeringPosition = value;
+    }
+
+    public get Rules(): EngravingRules {
+        return this.rules;
+    }
+
+    public set Rules(value: EngravingRules) {
+        this.rules = value;
+    }
+}

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

@@ -0,0 +1,823 @@
+import { PagePlacementEnum } from "./GraphicalMusicPage";
+//import {MusicSymbol} from "./MusicSymbol";
+import log from "loglevel";
+import { TextAlignmentEnum } from "../../Common/Enums/TextAlignment";
+import { PlacementEnum } from "../VoiceData/Expressions/AbstractExpression";
+import { AutoBeamOptions, AlignRestOption, FillEmptyMeasuresWithWholeRests } from "../../OpenSheetMusicDisplay/OSMDOptions";
+import { ColoringModes as ColoringMode } from "./DrawingParameters";
+import { Dictionary } from "typescript-collections";
+import { FontStyles } from "../../Common/Enums";
+import { NoteEnum } from "../../Common/DataObjects/Pitch";
+import { ChordSymbolEnum, CustomChord, DegreesInfo } from "../../MusicalScore/VoiceData/ChordSymbolContainer";
+import { GraphicalNote } from "./GraphicalNote";
+import { Note } from "../VoiceData/Note";
+
+/** Rendering and Engraving options, more fine-grained than [[IOSMDOptions]].
+ *  Not all of these options are meant to be modified by users of the library,
+ *  full support is only given for [[IOSMDOptions]].
+ *  Nevertheless, there are many useful options here,
+ *  like Render* to (not) render certain elements (e.g. osmd.rules.RenderRehearsalMarks = false)
+ */
+export class EngravingRules {
+    /** A unit of distance. 1.0 is the distance between lines of a stave for OSMD, which is 10 pixels in Vexflow. */
+    public static unit: number = 1.0;
+    public SamplingUnit: number;
+    public StaccatoShorteningFactor: number;
+    /** Height (size) of the sheet title. */
+    public SheetTitleHeight: number;
+    public SheetSubtitleHeight: number;
+    public SheetMinimumDistanceBetweenTitleAndSubtitle: number;
+    public SheetComposerHeight: number;
+    public SheetAuthorHeight: number;
+    public CompactMode: boolean;
+    public PagePlacementEnum: PagePlacementEnum;
+    public PageHeight: number;
+    public PageTopMargin: number;
+    public PageTopMarginNarrow: number;
+    public PageBottomMargin: number;
+    public PageLeftMargin: number;
+    public PageRightMargin: number;
+    public TitleTopDistance: number;
+    public TitleBottomDistance: number;
+    public SystemLeftMargin: number;
+    public SystemRightMargin: number;
+    public SystemLabelsRightMargin: number;
+    public SystemComposerDistance: number;
+    public InstrumentLabelTextHeight: number;
+    public MinimumDistanceBetweenSystems: number;
+    public MinSkyBottomDistBetweenSystems: number;
+    public LastSystemMaxScalingFactor: number;
+    public StaffDistance: number;
+    public BetweenStaffDistance: number;
+    public StaffHeight: number;
+    public TabStaffInterlineHeight: number;
+    public BetweenStaffLinesDistance: number;
+    /** Whether to automatically beam notes that don't already have beams in XML. */
+    public AutoBeamNotes: boolean;
+    /** Options for autoBeaming like whether to beam over rests. See AutoBeamOptions interface. */
+    public AutoBeamOptions: AutoBeamOptions;
+    public BeamWidth: number;
+    public BeamSpaceWidth: number;
+    public BeamForwardLength: number;
+    public FlatBeams: boolean;
+    public FlatBeamOffset: number;
+    public FlatBeamOffsetPerBeam: number;
+    public ClefLeftMargin: number;
+    public ClefRightMargin: number;
+    /** How many unique note positions a percussion score needs to have to not be rendered on one line. */
+    public PercussionOneLineCutoff: number;
+    public PercussionForceVoicesOneLineCutoff: number;
+    public PercussionOneLineUseXMLDisplayStep: boolean;
+    public PercussionOneLineXMLDisplayStepOctaveOffset: number;
+    public BetweenKeySymbolsDistance: number;
+    public KeyRightMargin: number;
+    public RhythmRightMargin: number;
+    public ShowRhythmAgainAfterPartEndOrFinalBarline: boolean;
+    public NewPartAndSystemAfterFinalBarline: boolean;
+    public InStaffClefScalingFactor: number;
+    public DistanceBetweenNaturalAndSymbolWhenCancelling: number;
+    public NoteHelperLinesOffset: number;
+    public MeasureLeftMargin: number;
+    public MeasureRightMargin: number;
+    public DistanceBetweenLastInstructionAndRepetitionBarline: number;
+    public ArpeggioDistance: number;
+    public IdealStemLength: number;
+    public StemNoteHeadBorderYOffset: number;
+    public StemWidth: number;
+    public StemMargin: number;
+    public StemMinLength: number;
+    public StemMaxLength: number;
+    public BeamSlopeMaxAngle: number;
+    public StemMinAllowedDistanceBetweenNoteHeadAndBeamLine: number;
+    public SetWantedStemDirectionByXml: boolean;
+    public GraceNoteScalingFactor: number;
+    public GraceNoteXOffset: number;
+    public WedgeOpeningLength: number;
+    public WedgeMeasureEndOpeningLength: number;
+    public WedgeMeasureBeginOpeningLength: number;
+    public WedgePlacementAboveY: number;
+    public WedgePlacementBelowY: number;
+    public WedgeHorizontalMargin: number;
+    public WedgeVerticalMargin: number;
+    public DistanceOffsetBetweenTwoHorizontallyCrossedWedges: number;
+    public WedgeMinLength: number;
+    public DistanceBetweenAdjacentDynamics: number;
+    public TempoChangeMeasureValidity: number;
+    public TempoContinousFactor: number;
+    public StaccatoScalingFactor: number;
+    public BetweenDotsDistance: number;
+    public OrnamentAccidentalScalingFactor: number;
+    public ChordSymbolTextHeight: number;
+    public ChordSymbolTextAlignment: TextAlignmentEnum;
+    public ChordSymbolRelativeXOffset: number;
+    public ChordSymbolXSpacing: number;
+    public ChordOverlapAllowedIntoNextMeasure: number;
+    public ChordSymbolYOffset: number;
+    public ChordSymbolLabelTexts: Dictionary<ChordSymbolEnum, string>;
+    public CustomChords: CustomChord[];
+    public RepetitionSymbolsYOffset: number;
+    public RehearsalMarkXOffset: number;
+    public RehearsalMarkXOffsetDefault: number;
+    public RehearsalMarkXOffsetSystemStartMeasure: number;
+    public RehearsalMarkYOffset: number;
+    public RehearsalMarkYOffsetDefault: number;
+    public RehearsalMarkFontSize: number;
+    public MeasureNumberLabelHeight: number;
+    public MeasureNumberLabelOffset: number;
+    public MeasureNumberLabelXOffset: number;
+    /** Whether tuplets should display ratio (3:2 instead of 3 for triplet). Default false. */
+    public TupletsRatioed: boolean;
+    /** Whether all tuplets should be bracketed (e.g. |--5--| instead of 5). Default false.
+     * If false, only tuplets given as bracketed in XML (bracket="yes") will be bracketed.
+     * (If not given in XML, bracketing is implementation-dependent according to standard)
+     */
+    public TupletsBracketed: boolean;
+    /** Whether all triplets should be bracketed. Overrides tupletsBracketed for triplets.
+     * If false, only triplets given as bracketed in XML (bracket="yes") will be bracketed.
+     * (Bracketing all triplets can be cluttering)
+     */
+    public TripletsBracketed: boolean;
+    public TupletNumberLabelHeight: number;
+    public TupletNumberYOffset: number;
+    public LabelMarginBorderFactor: number;
+    public TupletVerticalLineLength: number;
+    public TupletNumbersInTabs: boolean;
+
+    public RepetitionEndingLabelHeight: number;
+    public RepetitionEndingLabelXOffset: number;
+    public RepetitionEndingLabelYOffset: number;
+    public RepetitionEndingLineYLowerOffset: number;
+    public RepetitionEndingLineYUpperOffset: number;
+    public VoltaOffset: number;
+    /** Default alignment of lyrics.
+     * Left alignments will extend text to the right of the bounding box,
+     * which facilitates spacing by extending measure width.
+     */
+    public LyricsAlignmentStandard: TextAlignmentEnum;
+    public LyricsHeight: number;
+    public LyricsYOffsetToStaffHeight: number;
+    public VerticalBetweenLyricsDistance: number;
+    public HorizontalBetweenLyricsDistance: number;
+    public BetweenSyllableMaximumDistance: number;
+    public BetweenSyllableMinimumDistance: number;
+    public LyricOverlapAllowedIntoNextMeasure: number;
+    public MinimumDistanceBetweenDashes: number;
+    public MaximumLyricsElongationFactor: number;
+
+    public SlurPlacementFromXML: boolean;
+    public BezierCurveStepSize: number;
+    public TPower3: number[];
+    public OneMinusTPower3: number[];
+    public FactorOne: number[];
+    public FactorTwo: number[];
+    public TieGhostObjectWidth: number;
+    public TieYPositionOffsetFactor: number;
+    public MinimumNeededXspaceForTieGhostObject: number;
+    public TieHeightMinimum: number;
+    public TieHeightMaximum: number;
+    public TieHeightInterpolationK: number;
+    public TieHeightInterpolationD: number;
+    public SlurNoteHeadYOffset: number;
+    public SlurStemXOffset: number;
+    public SlurSlopeMaxAngle: number;
+    public SlurTangentMinAngle: number;
+    public SlurTangentMaxAngle: number;
+    public SlursStartingAtSameStaffEntryYOffset: number;
+    public InstantaneousTempoTextHeight: number;
+    public ContinuousDynamicTextHeight: number;
+    public MoodTextHeight: number;
+    public UnknownTextHeight: number;
+    public ContinuousTempoTextHeight: number;
+    public VexFlowDefaultNotationFontScale: number;
+    public VexFlowDefaultTabFontScale: number;
+    public TremoloStrokeScale: number;
+    public TremoloYSpacingScale: number;
+    public StaffLineWidth: number;
+    public StaffLineColor: string;
+    public LedgerLineWidth: number;
+    public LedgerLineStrokeStyle: string;
+    public LedgerLineColorDefault: string;
+    public WedgeLineWidth: number;
+    public TupletLineWidth: number;
+    public LyricUnderscoreLineWidth: number;
+    public SystemThinLineWidth: number;
+    public SystemBoldLineWidth: number;
+    public SystemRepetitionEndingLineWidth: number;
+    public SystemDotWidth: number;
+    public MultipleRestMeasureDefaultWidth: number;
+    public DistanceBetweenVerticalSystemLines: number;
+    public DistanceBetweenDotAndLine: number;
+    public OctaveShiftLineWidth: number;
+    public OctaveShiftVerticalLineLength: number;
+    public GraceLineWidth: number;
+    public MinimumStaffLineDistance: number;
+    public MinSkyBottomDistBetweenStaves: number;
+    public MinimumCrossedBeamDifferenceMargin: number;
+
+    public VoiceSpacingMultiplierVexflow: number;
+    public VoiceSpacingAddendVexflow: number;
+    public PickupMeasureWidthMultiplier: number;
+    public DisplacedNoteMargin: number;
+    public MinNoteDistance: number;
+    public SubMeasureXSpacingThreshold: number;
+    public MeasureDynamicsMaxScalingFactor: number;
+    public WholeRestXShiftVexflow: number;
+    public MetronomeMarksDrawn: boolean;
+    public MetronomeMarkXShift: number;
+    public MetronomeMarkYShift: number;
+    public SoftmaxFactorVexFlow: number;
+    public MaxInstructionsConstValue: number;
+    public NoteDistances: number[] = [1.0, 1.0, 1.3, 1.6, 2.0, 2.5, 3.0, 4.0];
+    public NoteDistancesScalingFactors: number[] = [1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0];
+    public DurationDistanceDict: {[_: number]: number } = {};
+    public DurationScalingDistanceDict: {[_: number]: number } = {};
+
+    public AlignRests: number; // 0 = false, 1 = true, 2 = auto
+    public FillEmptyMeasuresWithWholeRest: FillEmptyMeasuresWithWholeRests | number;
+    public ArpeggiosGoAcrossVoices: boolean;
+    public RenderArpeggios: boolean;
+    public RenderSlurs: boolean;
+    public ColoringMode: ColoringMode;
+    public ColoringEnabled: boolean;
+    public ColorStemsLikeNoteheads: boolean;
+    public ColorFlags: boolean;
+    public ColorBeams: boolean;
+    public ColoringSetCurrent: Dictionary<NoteEnum|number, string>;
+    public DefaultColorNotehead: string;
+    public DefaultColorRest: string;
+    public DefaultColorStem: string;
+    public DefaultColorLabel: string;
+    public DefaultColorTitle: string;
+    public DefaultColorCursor: string;
+    public DefaultFontFamily: string;
+    public DefaultFontStyle: FontStyles;
+    public DefaultVexFlowNoteFont: string;
+    public MaxMeasureToDrawIndex: number;
+    public MinMeasureToDrawIndex: number;
+    public MaxPageToDrawNumber: number;
+    public MaxSystemToDrawNumber: number;
+
+    /** Whether to render a label for the composer of the piece at the top of the sheet. */
+    public RenderComposer: boolean;
+    public RenderTitle: boolean;
+    public RenderSubtitle: boolean;
+    public RenderLyricist: boolean;
+    public RenderPartNames: boolean;
+    public RenderPartAbbreviations: boolean;
+    public RenderFingerings: boolean;
+    public RenderMeasureNumbers: boolean;
+    public RenderMeasureNumbersOnlyAtSystemStart: boolean;
+    public UseXMLMeasureNumbers: boolean;
+    public RenderLyrics: boolean;
+    public RenderChordSymbols: boolean;
+    public RenderMultipleRestMeasures: boolean;
+    public AutoGenerateMutipleRestMeasuresFromRestMeasures: boolean;
+    public RenderRehearsalMarks: boolean;
+    public RenderKeySignatures: boolean;
+    public RenderTimeSignatures: boolean;
+    public DynamicExpressionMaxDistance: number;
+    public DynamicExpressionSpacer: number;
+    public MpatMode: boolean;
+
+    public ArticulationPlacementFromXML: boolean;
+    /** Position of fingering label in relation to corresponding note (left, right supported, above, below experimental) */
+    public FingeringPosition: PlacementEnum;
+    public FingeringInsideStafflines: boolean;
+    public FingeringLabelFontHeight: number;
+    public FingeringOffsetX: number;
+    /** Whether to render string numbers in classical scores, i.e. not the string numbers in tabs, but e.g. for violin. */
+    public RenderStringNumbersClassical: boolean;
+    /** This is not for tabs, but for classical scores, especially violin. */
+    public StringNumberOffsetY: number;
+    public NewSystemAtXMLNewSystemAttribute: boolean;
+    public NewPageAtXMLNewPageAttribute: boolean;
+    public PageFormat: PageFormat;
+    public PageBackgroundColor: string; // vexflow-color-string (#FFFFFF). Default undefined/transparent.
+    public RenderSingleHorizontalStaffline: boolean;
+    public RestoreCursorAfterRerender: boolean;
+    public StretchLastSystemLine: boolean;
+    public SpacingBetweenTextLines: number;
+
+    public NoteToGraphicalNoteMap: Dictionary<number, GraphicalNote>;
+    // this is basically a WeakMap, except we save the id in the Note instead of using a WeakMap.
+    public NoteToGraphicalNoteMapObjectCount: number = 0;
+
+    public static FixStafflineBoundingBox: boolean; // TODO temporary workaround
+
+    constructor() {
+        this.loadDefaultValues();
+    }
+
+    public loadDefaultValues(): void {
+        // global variables
+        this.SamplingUnit = EngravingRules.unit * 3;
+
+        // mpat specific settings
+        this.MpatMode = true;
+
+        // Page Label Variables
+        this.SheetTitleHeight = 4.0;
+        this.SheetSubtitleHeight = 2.0;
+        this.SheetMinimumDistanceBetweenTitleAndSubtitle = 1.0;
+        this.SheetComposerHeight = 2.0;
+        this.SheetAuthorHeight = 2.0;
+
+        // Staff sizing Variables
+        this.CompactMode = false;
+        this.PagePlacementEnum = PagePlacementEnum.Down;
+        this.PageHeight = 100001.0;
+        this.PageTopMargin = 5.0;
+        this.PageTopMarginNarrow = 0.0; // for compact mode
+        this.PageBottomMargin = 5.0;
+        this.PageLeftMargin = 5.0;
+        this.PageRightMargin = 5.0;
+        this.TitleTopDistance = 5.0;
+        this.TitleBottomDistance = 1.0;
+        this.StaffDistance = 7.0;
+        this.BetweenStaffDistance = 5.0;
+        this.MinimumStaffLineDistance = 4.0;
+        this.MinSkyBottomDistBetweenStaves = 1.0; // default. compacttight mode sets it to 1.0 (as well).
+
+        // System Sizing and Label Variables
+        this.StaffHeight = 4.0;
+        this.TabStaffInterlineHeight = 1.1111;
+        this.BetweenStaffLinesDistance = EngravingRules.unit;
+        this.SystemLeftMargin = 0.0;
+        this.SystemRightMargin = 0.0;
+        this.SystemLabelsRightMargin = 2.0;
+        this.SystemComposerDistance = 2.0;
+        this.InstrumentLabelTextHeight = 2;
+        this.MinimumDistanceBetweenSystems = 7.0;
+        this.MinSkyBottomDistBetweenSystems = 5.0;
+        this.LastSystemMaxScalingFactor = 1.4;
+
+        // autoBeam options
+        this.AutoBeamNotes = false;
+        this.AutoBeamOptions = {
+            beam_middle_rests_only: false,
+            beam_rests: false,
+            maintain_stem_directions: false
+        };
+
+        // Beam Sizing Variables
+        this.BeamWidth = EngravingRules.unit / 2.0;
+        this.BeamSpaceWidth = EngravingRules.unit / 3.0;
+        this.BeamForwardLength = 1.25 * EngravingRules.unit;
+
+        this.FlatBeams = false;
+        this.FlatBeamOffset = 20;
+        this.FlatBeamOffsetPerBeam = 10;
+
+        // Beam Sizing Variables
+        this.ClefLeftMargin = 0.5;
+        this.ClefRightMargin = 0.75;
+        this.PercussionOneLineCutoff = 3; // percussion parts with <3 unique note positions rendered on one line
+        this.PercussionForceVoicesOneLineCutoff = 1;
+        this.PercussionOneLineUseXMLDisplayStep = true;
+        this.PercussionOneLineXMLDisplayStepOctaveOffset = 0;
+        this.BetweenKeySymbolsDistance = 0.2;
+        this.KeyRightMargin = 0.75;
+        this.RhythmRightMargin = 1.25;
+        this.ShowRhythmAgainAfterPartEndOrFinalBarline = true;
+        this.NewPartAndSystemAfterFinalBarline = false;
+        this.InStaffClefScalingFactor = 0.8;
+        this.DistanceBetweenNaturalAndSymbolWhenCancelling = 0.4;
+
+        // Beam Sizing Variables
+        this.NoteHelperLinesOffset = 0.25;
+        this.MeasureLeftMargin = 0.7;
+        this.MeasureRightMargin = 0.0;
+        this.DistanceBetweenLastInstructionAndRepetitionBarline = 1.0;
+        this.ArpeggioDistance = 0.6;
+
+        // Stems Variables
+        this.StaccatoShorteningFactor = 2;
+        this.IdealStemLength = 3.0;
+        this.StemNoteHeadBorderYOffset = 0.2;
+        this.StemMargin = 0.2;
+        this.StemMinLength = 2.5;
+        this.StemMaxLength = 4.5;
+        this.BeamSlopeMaxAngle = 10.0;
+        this.StemMinAllowedDistanceBetweenNoteHeadAndBeamLine = 1.0;
+        this.SetWantedStemDirectionByXml = true;
+        // also see stemwidth further below
+
+        // GraceNote Variables
+        this.GraceNoteScalingFactor = 0.6;
+        this.GraceNoteXOffset = 0.2;
+
+        // Wedge Variables
+        this.WedgeOpeningLength = 1.2;
+        this.WedgeMeasureEndOpeningLength = 0.75;
+        this.WedgeMeasureBeginOpeningLength = 0.75;
+        this.WedgePlacementAboveY = -1.5;
+        this.WedgePlacementBelowY = 1.5;
+        this.WedgeHorizontalMargin = 0.6;
+        this.WedgeVerticalMargin = 0.5;
+        this.DistanceOffsetBetweenTwoHorizontallyCrossedWedges = 0.3;
+        this.WedgeMinLength = 2.0;
+        this.DistanceBetweenAdjacentDynamics = 0.75;
+
+        // Tempo Variables
+        this.TempoChangeMeasureValidity = 4;
+        this.TempoContinousFactor = 0.7;
+
+        // various
+        this.StaccatoScalingFactor = 0.8;
+        this.BetweenDotsDistance = 0.8;
+        this.OrnamentAccidentalScalingFactor = 0.65;
+        this.ChordSymbolTextHeight = 2.0;
+        this.ChordSymbolTextAlignment = TextAlignmentEnum.LeftBottom;
+        this.ChordSymbolRelativeXOffset = -1.0;
+        this.ChordSymbolXSpacing = 1.0;
+        this.ChordOverlapAllowedIntoNextMeasure = 0;
+        this.ChordSymbolYOffset = 2.0;
+        this.ChordSymbolLabelTexts = new Dictionary<ChordSymbolEnum, string>();
+        this.resetChordSymbolLabelTexts(this.ChordSymbolLabelTexts);
+        this.CustomChords = [];
+        this.resetChordNames();
+        this.RepetitionSymbolsYOffset = 0;
+        this.RehearsalMarkXOffsetDefault = 10; // avoid collision with metronome number
+        this.RehearsalMarkXOffset = 0; // user defined
+        this.RehearsalMarkXOffsetSystemStartMeasure = -20; // good test: Haydn Concertante
+        this.RehearsalMarkYOffsetDefault = -15;
+        this.RehearsalMarkYOffset = 0; // user defined
+        this.RehearsalMarkFontSize = 10; // vexflow default: 12, too big with chord symbols
+
+        // Tuplets, MeasureNumber and TupletNumber Labels
+        this.MeasureNumberLabelHeight = 1.5 * EngravingRules.unit;
+        this.MeasureNumberLabelOffset = 2;
+        this.MeasureNumberLabelXOffset = -0.5;
+        this.TupletsRatioed = false;
+        this.TupletsBracketed = false;
+        this.TripletsBracketed = false; // special setting for triplets, overrides tuplet setting (for triplets only)
+        this.TupletNumberLabelHeight = 1.5 * EngravingRules.unit;
+        this.TupletNumberYOffset = 0.5;
+        this.LabelMarginBorderFactor = 0.1;
+        this.TupletVerticalLineLength = 0.5;
+        this.TupletNumbersInTabs = false; // disabled by default, nonstandard in tabs, at least how we show them in non-tabs.
+
+        // Slur and Tie variables
+        this.SlurPlacementFromXML = true;
+        this.BezierCurveStepSize = 1000;
+        this.calculateCurveParametersArrays();
+        this.TieGhostObjectWidth = 0.75;
+        this.TieYPositionOffsetFactor = 0.3;
+        this.MinimumNeededXspaceForTieGhostObject = 1.0;
+        this.TieHeightMinimum = 0.28;
+        this.TieHeightMaximum = 1.2;
+        this.TieHeightInterpolationK = 0.0288;
+        this.TieHeightInterpolationD = 0.136;
+        this.SlurNoteHeadYOffset = 0.5;
+        this.SlurStemXOffset = 0.3;
+        this.SlurSlopeMaxAngle = 15.0;
+        this.SlurTangentMinAngle = 30.0;
+        this.SlurTangentMaxAngle = 80.0;
+        this.SlursStartingAtSameStaffEntryYOffset = 0.8;
+
+        // Repetitions
+        this.RepetitionEndingLabelHeight = 2.0;
+        this.RepetitionEndingLabelXOffset = 0.5;
+        this.RepetitionEndingLabelYOffset = 0.3;
+        this.RepetitionEndingLineYLowerOffset = 0.5;
+        this.RepetitionEndingLineYUpperOffset = 0.3;
+        this.VoltaOffset = 2.5;
+
+        // Lyrics
+        this.LyricsAlignmentStandard = TextAlignmentEnum.LeftBottom; // CenterBottom and LeftBottom tested, spacing-optimized
+        this.LyricsHeight = 2.0; // actually size of lyrics
+        this.LyricsYOffsetToStaffHeight = 0.0; // distance between lyrics and staff. could partly be even lower/dynamic
+        this.VerticalBetweenLyricsDistance = 0.5;
+        this.HorizontalBetweenLyricsDistance = 0.2;
+        this.BetweenSyllableMaximumDistance = 10.0;
+        this.BetweenSyllableMinimumDistance = 0.5; // + 1.0 for CenterAlignment added in lyrics spacing
+        this.LyricOverlapAllowedIntoNextMeasure = 3.4; // optimal for dashed last lyric, see Land der Berge
+        this.MinimumDistanceBetweenDashes = 10;
+        this.MaximumLyricsElongationFactor = 2.5;
+
+        // expressions variables
+        this.InstantaneousTempoTextHeight = 2.3;
+        this.ContinuousDynamicTextHeight = 2.3;
+        this.MoodTextHeight = 2.3;
+        this.UnknownTextHeight = 2.0;
+        this.ContinuousTempoTextHeight = 2.3;
+        this.DynamicExpressionMaxDistance = 2;
+        this.DynamicExpressionSpacer = 0.5;
+
+        // Line Widths
+        this.VexFlowDefaultNotationFontScale = 39; // scales notes, including rests. default value 39 in Vexflow.
+        this.VexFlowDefaultTabFontScale = 39;
+        this.TremoloStrokeScale = 1;
+        this.TremoloYSpacingScale = 1;
+        this.StemWidth = 0.15; // originally 0.13. vexflow default 0.15. should probably be adjusted when increasing vexFlowDefaultNotationFontScale,
+        this.StaffLineWidth = 0.10; // originally 0.12, but this will be pixels in Vexflow (*10).
+        this.StaffLineColor = undefined; // if undefined, vexflow default (grey). not a width, but affects visual line clarity.
+        this.LedgerLineWidth = 1; // vexflow units (pixels). if not undefined, the vexflow default will be overwritten
+        this.LedgerLineStrokeStyle = undefined; // if not undefined, the vexflow default will be overwritten
+        this.LedgerLineColorDefault = "#000000"; // black, previously grey by default
+        this.WedgeLineWidth = 0.12;
+        this.TupletLineWidth = 0.12;
+        this.LyricUnderscoreLineWidth = 0.12;
+        this.SystemThinLineWidth = 0.12;
+        this.SystemBoldLineWidth = EngravingRules.unit / 2.0;
+        this.SystemRepetitionEndingLineWidth = 0.12;
+        this.SystemDotWidth = EngravingRules.unit / 5.0;
+        this.DistanceBetweenVerticalSystemLines = 0.35;
+        this.DistanceBetweenDotAndLine = 0.7;
+        this.OctaveShiftLineWidth = 0.12;
+        this.OctaveShiftVerticalLineLength = EngravingRules.unit;
+        this.GraceLineWidth = this.StaffLineWidth * this.GraceNoteScalingFactor;
+
+        this.MultipleRestMeasureDefaultWidth = 4;
+
+        // Line Widths
+        this.MinimumCrossedBeamDifferenceMargin = 0.0001;
+
+        // xSpacing Variables
+        this.VoiceSpacingMultiplierVexflow = 0.85;
+        this.VoiceSpacingAddendVexflow = 3.0;
+        this.PickupMeasureWidthMultiplier = 1.0;
+        this.DisplacedNoteMargin = 0.1;
+        this.MinNoteDistance = 2.0;
+        this.SubMeasureXSpacingThreshold = 35;
+        this.MeasureDynamicsMaxScalingFactor = 2.5;
+        this.WholeRestXShiftVexflow = -1.5; // VexFlow draws rest notes too far to the right
+        this.MetronomeMarksDrawn = true;
+        this.MetronomeMarkXShift = -6; // our unit, is taken * unitInPixels
+        this.MetronomeMarkYShift = -0.5;
+        this.SoftmaxFactorVexFlow = 15; // only applies to Vexflow 3.x. 15 seems like the sweet spot. Vexflow default is 100.
+        // if too high, score gets too big, especially half notes. with half note quarter quarter, the quarters get squeezed.
+        // if too low, smaller notes aren't positioned correctly.
+
+        // Render options (whether to render specific or invisible elements)
+        this.AlignRests = AlignRestOption.Never; // 0 = false, 1 = true, 2 = auto
+        this.FillEmptyMeasuresWithWholeRest = FillEmptyMeasuresWithWholeRests.No;
+        this.ArpeggiosGoAcrossVoices = false; // safe option, as otherwise arpeggios will always go across all voices in Vexflow, which is often unwanted
+        this.RenderArpeggios = true;
+        this.RenderSlurs = true;
+        this.ColoringMode = ColoringMode.XML;
+        this.ColoringEnabled = true;
+        this.ColorStemsLikeNoteheads = false;
+        this.ColorBeams = true;
+        this.ColorFlags = true;
+        this.DefaultColorNotehead = "#000000"; // black. undefined is only black if a note's color hasn't been changed before.
+        this.DefaultColorRest = this.DefaultColorNotehead;
+        this.DefaultColorStem = this.DefaultColorNotehead;
+        this.DefaultColorLabel = this.DefaultColorNotehead;
+        this.DefaultColorTitle = this.DefaultColorNotehead;
+        this.DefaultColorCursor = "#33e02f"; // green
+        this.DefaultFontFamily = "Times New Roman"; // what OSMD was initially optimized for
+        this.DefaultFontStyle = FontStyles.Regular;
+        this.DefaultVexFlowNoteFont = "gonville"; // was the default vexflow font up to vexflow 1.2.93, now it's Bravura, which is more cursive/bold
+        this.MaxMeasureToDrawIndex = Number.MAX_VALUE;
+        this.MinMeasureToDrawIndex = 0;
+        this.MaxSystemToDrawNumber = Number.MAX_VALUE;
+        this.MaxPageToDrawNumber = Number.MAX_VALUE;
+        this.RenderComposer = true;
+        this.RenderTitle = true;
+        this.RenderSubtitle = true;
+        this.RenderLyricist = true;
+        this.RenderPartNames = true;
+        this.RenderPartAbbreviations = true;
+        this.RenderFingerings = true;
+        this.RenderMeasureNumbers = true;
+        this.RenderMeasureNumbersOnlyAtSystemStart = false;
+        this.UseXMLMeasureNumbers = true;
+        this.RenderLyrics = true;
+        this.RenderChordSymbols = true;
+        this.RenderMultipleRestMeasures = true;
+        this.AutoGenerateMutipleRestMeasuresFromRestMeasures = true;
+        this.RenderRehearsalMarks = true;
+        this.RenderKeySignatures = true;
+        this.RenderTimeSignatures = true;
+        this.ArticulationPlacementFromXML = true;
+        this.FingeringPosition = PlacementEnum.Left; // easier to get bounding box, and safer for vertical layout
+        this.FingeringInsideStafflines = false;
+        this.FingeringLabelFontHeight = 1.7;
+        this.FingeringOffsetX = 0.0;
+        this.RenderStringNumbersClassical = true;
+        this.StringNumberOffsetY = 0.0;
+        this.NewSystemAtXMLNewSystemAttribute = false;
+        this.NewPageAtXMLNewPageAttribute = false;
+        this.RestoreCursorAfterRerender = true;
+        this.StretchLastSystemLine = false;
+
+        EngravingRules.FixStafflineBoundingBox = false; // TODO temporary workaround
+
+        this.PageFormat = PageFormat.UndefinedPageFormat; // default: undefined / 'infinite' height page, using the canvas'/container's width and height
+        this.PageBackgroundColor = undefined; // default: transparent. half-transparent white: #FFFFFF88"
+        this.RenderSingleHorizontalStaffline = false;
+        this.SpacingBetweenTextLines = 0;
+
+        this.NoteToGraphicalNoteMap = new Dictionary<number, GraphicalNote>();
+        this.NoteToGraphicalNoteMapObjectCount = 0;
+
+        // this.populateDictionaries(); // these values aren't used currently
+        try {
+            this.MaxInstructionsConstValue = this.ClefLeftMargin + this.ClefRightMargin + this.KeyRightMargin + this.RhythmRightMargin + 11;
+            //if (FontInfo.Info) {
+            //    this.maxInstructionsConstValue += FontInfo.Info.getBoundingBox(MusicSymbol.G_CLEF).width
+            //        + FontInfo.Info.getBoundingBox(MusicSymbol.FOUR).width
+            //        + 7 * FontInfo.Info.getBoundingBox(MusicSymbol.SHARP).width;
+            //}
+        } catch (ex) {
+            log.info("EngravingRules()", ex);
+        }
+
+        // collect mpat-specific changes at the end
+        if (this.MpatMode) {
+            this.NewPartAndSystemAfterFinalBarline = true;
+        }
+    }
+
+    public addGraphicalNoteToNoteMap(note: Note, graphicalNote: GraphicalNote): void {
+        note.NoteToGraphicalNoteObjectId = this.NoteToGraphicalNoteMapObjectCount;
+        this.NoteToGraphicalNoteMap.setValue(note.NoteToGraphicalNoteObjectId, graphicalNote);
+        this.NoteToGraphicalNoteMapObjectCount++;
+    }
+
+    public GNote(note: Note): GraphicalNote {
+        return GraphicalNote.FromNote(note, this);
+    }
+
+    /** This should be done before a new sheet is loaded, not each re-render (otherwise the map would end empty). */
+    public clearMusicSheetObjects(): void {
+        this.NoteToGraphicalNoteMap = new Dictionary<number, GraphicalNote>();
+        this.NoteToGraphicalNoteMapObjectCount = 0;
+    }
+
+    public setChordSymbolLabelText(key: ChordSymbolEnum, value: string): void {
+        this.ChordSymbolLabelTexts.setValue(key, value);
+    }
+    public resetChordSymbolLabelTexts(chordtexts: Dictionary<ChordSymbolEnum, string>): Dictionary<ChordSymbolEnum, string> {
+        chordtexts.setValue(ChordSymbolEnum.minor, "m");
+        chordtexts.setValue(ChordSymbolEnum.augmented, "aug");
+        chordtexts.setValue(ChordSymbolEnum.diminished, "dim");
+        chordtexts.setValue(ChordSymbolEnum.dominant, "7");
+        chordtexts.setValue(ChordSymbolEnum.majorseventh, "maj7");
+        chordtexts.setValue(ChordSymbolEnum.minorseventh, "m7");
+        chordtexts.setValue(ChordSymbolEnum.diminishedseventh, "dim7");
+        chordtexts.setValue(ChordSymbolEnum.augmentedseventh, "aug7");
+        chordtexts.setValue(ChordSymbolEnum.halfdiminished, "m7b5");
+        chordtexts.setValue(ChordSymbolEnum.majorminor, "m(maj7)");
+        chordtexts.setValue(ChordSymbolEnum.majorsixth, "maj6");
+        chordtexts.setValue(ChordSymbolEnum.minorsixth, "m6");
+        chordtexts.setValue(ChordSymbolEnum.dominantninth, "9");
+        chordtexts.setValue(ChordSymbolEnum.majorninth, "maj9");
+        chordtexts.setValue(ChordSymbolEnum.minorninth, "m9");
+        chordtexts.setValue(ChordSymbolEnum.dominant11th, "11");
+        chordtexts.setValue(ChordSymbolEnum.major11th, "maj11");
+        chordtexts.setValue(ChordSymbolEnum.minor11th, "m11");
+        chordtexts.setValue(ChordSymbolEnum.dominant13th, "13");
+        chordtexts.setValue(ChordSymbolEnum.major13th, "maj13");
+        chordtexts.setValue(ChordSymbolEnum.minor13th, "m13");
+        chordtexts.setValue(ChordSymbolEnum.suspendedsecond, "sus2");
+        chordtexts.setValue(ChordSymbolEnum.suspendedfourth, "sus4");
+        chordtexts.setValue(ChordSymbolEnum.power, "5");
+        chordtexts.setValue(ChordSymbolEnum.none, "N.C.");
+
+        return chordtexts;
+    }
+
+    public addChordName(
+        altName: string,
+        chordKindText: string,
+        adds: string[],
+        alts: string[],
+        subs: string[],
+    ): void {
+        if (ChordSymbolEnum[chordKindText] !== undefined) {
+            const degrees: DegreesInfo = {
+                adds,
+                alts,
+                subs,
+            };
+            this.CustomChords.push(CustomChord.createCustomChord(altName, ChordSymbolEnum[chordKindText], degrees));
+        }
+    }
+
+    public renameChord(altName: string, newAltName: string): void {
+        CustomChord.renameCustomChord(altName, newAltName, this.CustomChords);
+    }
+
+    public resetChordNames(): void {
+        // addChordName(alternateName, chordKindText, adds, alters, subtracts)
+        this.addChordName("alt", "major", ["#5", "b9", "#9"], ["b5"], []);
+        this.addChordName("7alt", "dominant", ["#5", "b9", "#9"], ["b5"], []);
+        this.addChordName("7sus4", "dominant", ["4"], [], ["3"]);
+        this.addChordName("7sus4", "suspendedfourth", ["7"], [], []);
+        this.addChordName("9sus4", "dominantninth", ["4"], [], ["3"]);
+        this.addChordName("9sus4", "suspendedfourth", ["9"], [], []);
+        this.addChordName("11sus4", "dominant11th", ["4"], [], ["3"]);
+        this.addChordName("11sus4", "suspendedfourth", ["11"], [], []);
+        this.addChordName("13sus4", "dominant13th", ["4"], [], ["3"]);
+        this.addChordName("13sus4", "suspendedfourth", ["13"], [], []);
+        this.addChordName("7sus2", "dominant", ["2"], [], ["3"]);
+        this.addChordName("7sus2", "suspendedsecond", ["7"], [], []);
+        this.addChordName("m7b5", "minorseventh", [], ["b5"], []);
+        this.addChordName("9sus2", "dominantninth", ["2"], [], ["3"]);
+        this.addChordName("9sus2", "suspendedsecond", ["9"], [], []);
+        this.addChordName("11sus2", "dominant11th", ["2"], [], ["3"]);
+        this.addChordName("11sus2", "suspendedsecond", ["11"], [], []);
+        this.addChordName("13sus2", "dominant13th", ["2"], [], ["3"]);
+        this.addChordName("13sus2", "suspendedsecond", ["13"], [], []);
+        this.addChordName("m(maj9)", "majorminor", ["9"], [], []);
+        this.addChordName("m(maj11)", "majorminor", ["11"], [], []);
+        this.addChordName("m(maj13)", "majorminor", ["13"], [], []);
+        this.addChordName("69", "majorsixth", ["9"], [], []);
+        this.addChordName("mi69", "minorsixth", ["9"], [], []);
+    }
+
+    /**
+     * This method maps NoteDurations to Distances and DistancesScalingFactors.
+     */
+    // private populateDictionaries(): void {
+    //     for (let i: number = 0; i < this.NoteDistances.length; i++) {
+    //         switch (i) {
+    //             case 0:
+    //                 this.DurationDistanceDict[0.015625] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[0.015625] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             case 1:
+    //                 this.DurationDistanceDict[0.03125] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[0.03125] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             case 2:
+    //                 this.DurationDistanceDict[0.0625] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[0.0625] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             case 3:
+    //                 this.DurationDistanceDict[0.125] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[0.125] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             case 4:
+    //                 this.DurationDistanceDict[0.25] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[0.25] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             case 5:
+    //                 this.DurationDistanceDict[0.5] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[0.5] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             case 6:
+    //                 this.DurationDistanceDict[1.0] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[1.0] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             case 7:
+    //                 this.DurationDistanceDict[2.0] = this.NoteDistances[i];
+    //                 this.DurationScalingDistanceDict[2.0] = this.NoteDistancesScalingFactors[i];
+    //                 break;
+    //             default:
+    //                 // FIXME
+    //         }
+    //     }
+    // }
+
+    /**
+     * Calculate Curve-independend factors, to be used later in the Slur- and TieCurvePoints calculation
+     */
+    private calculateCurveParametersArrays(): void {
+        this.TPower3 = new Array(this.BezierCurveStepSize);
+        this.OneMinusTPower3 = new Array(this.BezierCurveStepSize);
+        this.FactorOne = new Array(this.BezierCurveStepSize);
+        this.FactorTwo = new Array(this.BezierCurveStepSize);
+        for (let i: number = 0; i < this.BezierCurveStepSize; i++) {
+            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;
+            this.FactorTwo[i] = 3 * (1 - t) * Math.pow(t, 2);
+        }
+    }
+}
+
+// TODO maybe this should be moved to OSMDOptions. Also see OpenSheetMusicDisplay.PageFormatStandards
+export class PageFormat {
+    constructor(width: number, height: number, idString: string = "noIdStringGiven") {
+        this.width = width;
+        this.height = height;
+        this.idString = idString;
+    }
+    public width: number;
+    public height: number;
+    public idString: string;
+    public get aspectRatio(): number {
+        if (!this.IsUndefined) {
+            return this.width / this.height;
+        } else {
+            return 0; // infinite page height
+        }
+    }
+    /** Undefined page format: use default page format. */
+    public get IsUndefined(): boolean {
+        return this.width === undefined || this.height === undefined || this.height === 0 || this.width === 0;
+    }
+    public static get UndefinedPageFormat(): PageFormat {
+        return new PageFormat(0, 0);
+    }
+    public Equals(otherPageFormat: PageFormat): boolean {
+        if (!otherPageFormat) {
+            return false;
+        }
+        return otherPageFormat.width === this.width && otherPageFormat.height === this.height;
+    }
+}

+ 34 - 0
src/MusicalScore/Graphical/GraphicalChordSymbolContainer.ts

@@ -0,0 +1,34 @@
+import {Label} from "../Label";
+import {GraphicalLabel} from "./GraphicalLabel";
+import {ChordSymbolContainer} from "../VoiceData/ChordSymbolContainer";
+import {BoundingBox} from "./BoundingBox";
+import {GraphicalObject} from "./GraphicalObject";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {EngravingRules} from "./EngravingRules";
+import { KeyInstruction } from "../VoiceData/Instructions/KeyInstruction";
+
+export class GraphicalChordSymbolContainer extends GraphicalObject {
+    private chordSymbolContainer: ChordSymbolContainer;
+    private graphicalLabel: GraphicalLabel;
+    private rules: EngravingRules;
+
+    constructor(chordSymbolContainer: ChordSymbolContainer, parent: BoundingBox, textHeight: number,
+                keyInstruction: KeyInstruction, transposeHalftones: number, rules: EngravingRules) {
+        super();
+        this.chordSymbolContainer = chordSymbolContainer;
+        this.boundingBox = new BoundingBox(this, parent);
+        this.rules = rules;
+        this.calculateLabel(textHeight, transposeHalftones, keyInstruction);
+    }
+    public get GetChordSymbolContainer(): ChordSymbolContainer {
+        return this.chordSymbolContainer;
+    }
+    public get GraphicalLabel(): GraphicalLabel {
+        return this.graphicalLabel;
+    }
+    private calculateLabel(textHeight: number, transposeHalftones: number, keyInstruction: KeyInstruction): void {
+        const text: string = ChordSymbolContainer.calculateChordText(this.chordSymbolContainer, transposeHalftones, keyInstruction);
+        this.graphicalLabel = new GraphicalLabel(new Label(text), textHeight, this.rules.ChordSymbolTextAlignment, this.rules, this.boundingBox);
+        this.graphicalLabel.PositionAndShape.RelativePosition = new PointF2D(this.rules.ChordSymbolRelativeXOffset, 0.0);
+    }
+}

+ 367 - 0
src/MusicalScore/Graphical/GraphicalContinuousDynamicExpression.ts

@@ -0,0 +1,367 @@
+import { GraphicalLine } from "./GraphicalLine";
+import { StaffLine } from "./StaffLine";
+import { GraphicalMeasure } from "./GraphicalMeasure";
+import { ContDynamicEnum, ContinuousDynamicExpression } from "../VoiceData/Expressions/ContinuousExpressions/ContinuousDynamicExpression";
+import { PointF2D } from "../../Common/DataObjects/PointF2D";
+import { AbstractGraphicalExpression } from "./AbstractGraphicalExpression";
+import { PlacementEnum } from "../VoiceData/Expressions/AbstractExpression";
+import { SkyBottomLineCalculator } from "./SkyBottomLineCalculator";
+import { ISqueezable } from "./ISqueezable";
+import log from "loglevel";
+import { SourceMeasure } from "../VoiceData/SourceMeasure";
+
+/**
+ * This class prepares the graphical elements for a continuous expression. It calculates the wedges and
+ * wrappings if they are split over system breaks.
+ */
+export class GraphicalContinuousDynamicExpression extends AbstractGraphicalExpression implements ISqueezable {
+    /** True if expression is split over system borders */
+    private isSplittedPart: boolean;
+    /** True if this expression should not be removed if re-rendered */
+    private notToBeRemoved: boolean;
+    /** Holds the line objects that can be drawn via implementation */
+    private lines: GraphicalLine[] = [];
+    private startMeasure: GraphicalMeasure;
+    private endMeasure: GraphicalMeasure;
+
+    /**
+     * Create a new instance of the GraphicalContinuousDynamicExpression
+     * @param continuousDynamic The continuous dynamic instruction read via ExpressionReader
+     * @param staffLine The staffline where the expression is attached
+     */
+    constructor(continuousDynamic: ContinuousDynamicExpression, staffLine: StaffLine, measure: SourceMeasure) {
+        super(staffLine, continuousDynamic, measure);
+
+        this.isSplittedPart = false;
+        this.notToBeRemoved = false;
+    }
+
+    //#region Getter / Setter
+
+    /** The graphical measure where the parent continuous dynamic expression starts */
+    public get StartMeasure(): GraphicalMeasure { return this.startMeasure; }
+    public set StartMeasure(value: GraphicalMeasure) { this.startMeasure = value; }
+    /** The graphical measure where the parent continuous dynamic expression ends */
+    public get EndMeasure(): GraphicalMeasure { return this.endMeasure; }
+    public set EndMeasure(value: GraphicalMeasure) { this.endMeasure = value; }
+    /** The staff lin where the graphical dynamic expressions ends */
+    public get EndStaffLine(): StaffLine { return this.endMeasure ? this.endMeasure.ParentStaffLine : undefined; }
+    /**  Is true if this continuous expression is a wedge, that reaches over a system border and needs to be split into two. */
+    public get IsSplittedPart(): boolean { return this.isSplittedPart; }
+    public set IsSplittedPart(value: boolean) { this.isSplittedPart = value; }
+    /**  Is true if the dynamic is not a symbol but a text instruction. E.g. "decrescendo" */
+    public get IsVerbal(): boolean { return this.ContinuousDynamic.Label && this.ContinuousDynamic.Label.length > 0; }
+    /** True if this expression should not be removed if re-rendered */
+    public get NotToBeRemoved(): boolean { return this.notToBeRemoved; }
+    public set NotToBeRemoved(value: boolean) { this.notToBeRemoved = value; }
+    /** Holds the line objects that can be drawn via implementation */
+    public get Lines(): GraphicalLine[] { return this.lines; }
+
+    public get ContinuousDynamic(): ContinuousDynamicExpression { return this.SourceExpression as ContinuousDynamicExpression; }
+    //#endregion
+
+    //#region Public methods
+
+    public updateSkyBottomLine(): void {
+        // update Sky-BottomLine
+        const skyBottomLineCalculator: SkyBottomLineCalculator = this.parentStaffLine.SkyBottomLineCalculator;
+        const left: number = this.IsVerbal ? this.label.PositionAndShape.RelativePosition.x + this.label.PositionAndShape.BorderMarginLeft : 0;
+        const right: number = this.IsVerbal ? this.label.PositionAndShape.RelativePosition.x + this.label.PositionAndShape.BorderMarginRight : 0;
+        if (!this.IsVerbal && this.lines.length < 2) {
+            log.warn("Not enough lines for SkyBottomLine calculation");
+        }
+        if (!this.IsVerbal) {
+            if (this.ContinuousDynamic.DynamicType !== ContDynamicEnum.crescendo &&
+                this.ContinuousDynamic.DynamicType !== ContDynamicEnum.diminuendo) {
+                // for now there is only crescendo or decrescendo anyways, but this will catch errors when we add new types in the future
+                log.warn("GraphicalContinuousDynamicExpression.updateSkyBottomLine(): " +
+                    "unhandled continuous dynamic type. start measure: " + this.startMeasure?.MeasureNumber);
+            }
+        }
+        switch (this.Placement) {
+            case PlacementEnum.Above:
+                if (!this.IsVerbal) {
+                    if (this.ContinuousDynamic.DynamicType === ContDynamicEnum.crescendo) {
+                        skyBottomLineCalculator.updateSkyLineWithWedge(this.lines[0].Start, this.lines[0].End);
+                    } else if (this.ContinuousDynamic.DynamicType === ContDynamicEnum.diminuendo) {
+                        skyBottomLineCalculator.updateSkyLineWithWedge(this.lines[0].End, this.lines[0].Start);
+                    } // else covered with the log.warn above
+                } else {
+                    const yValue: number = this.label.PositionAndShape.BorderMarginTop + this.label.PositionAndShape.RelativePosition.y;
+                    skyBottomLineCalculator.updateSkyLineInRange(left, right, yValue);
+                }
+                break;
+            case PlacementEnum.Below:
+                if (!this.IsVerbal) {
+                    // console.log(`id: ${this.parentStaffLine.ParentStaff.Id}`);
+                    if (this.ContinuousDynamic.DynamicType === ContDynamicEnum.crescendo) {
+                        skyBottomLineCalculator.updateBottomLineWithWedge(this.lines[1].Start, this.lines[1].End);
+                    } else if (this.ContinuousDynamic.DynamicType === ContDynamicEnum.diminuendo) {
+                        skyBottomLineCalculator.updateBottomLineWithWedge(this.lines[1].End, this.lines[1].Start);
+                    } // else covered with the log.warn above
+                } else {
+                    const yValue: number = this.label.PositionAndShape.BorderMarginBottom + this.label.PositionAndShape.RelativePosition.y;
+                    skyBottomLineCalculator.updateBottomLineInRange(left, right, yValue);
+                }
+                break;
+            default:
+                log.error("Placement for GraphicalContinuousDynamicExpression is unknown");
+        }
+    }
+
+    /**
+     * Calculate crescendo lines for (full).
+     * @param startX left most starting point
+     * @param endX right mist ending point
+     * @param y y placement
+     * @param wedgeOpeningLength length of the opening
+     * @param wedgeLineWidth line width of the wedge
+     */
+    public createCrescendoLines(startX: number, endX: number, y: number,
+                                wedgeOpeningLength: number = this.rules.WedgeOpeningLength, wedgeLineWidth: number = this.rules.WedgeLineWidth): void {
+        const lineStart: PointF2D = new PointF2D(startX, y);
+        const upperLineEnd: PointF2D = new PointF2D(endX, y - wedgeOpeningLength / 2);
+        const lowerLineEnd: PointF2D = new PointF2D(endX, y + wedgeOpeningLength / 2);
+        this.addWedgeLines(lineStart, upperLineEnd, lowerLineEnd, wedgeLineWidth);
+    }
+
+    /**
+     * Calculate crescendo lines for system break (first part).
+     * @param startX left most starting point
+     * @param endX right mist ending point
+     * @param y y placement
+     * @param wedgeMeasureEndOpeningLength length of opening at measure end
+     * @param wedgeOpeningLength length of the opening
+     * @param wedgeLineWidth line width of the wedge
+     */
+    public createFirstHalfCrescendoLines(startX: number, endX: number, y: number,
+                                         wedgeMeasureEndOpeningLength: number = this.rules.WedgeMeasureEndOpeningLength,
+                                         wedgeLineWidth: number = this.rules.WedgeLineWidth): void {
+        const lineStart: PointF2D = new PointF2D(startX, y);
+        const upperLineEnd: PointF2D = new PointF2D(endX, y - wedgeMeasureEndOpeningLength / 2);
+        const lowerLineEnd: PointF2D = new PointF2D(endX, y + wedgeMeasureEndOpeningLength / 2);
+        this.addWedgeLines(lineStart, upperLineEnd, lowerLineEnd, wedgeLineWidth);
+    }
+
+
+    /**
+     * Calculate crescendo lines for system break (second part).
+     * @param startX left most starting point
+     * @param endX right mist ending point
+     * @param y y placement
+     * @param wedgeMeasureBeginOpeningLength length of opening at measure start
+     * @param wedgeOpeningLength length of the opening
+     * @param wedgeLineWidth line width of the wedge
+     */
+    public createSecondHalfCrescendoLines(startX: number, endX: number, y: number,
+                                          wedgeMeasureBeginOpeningLength: number = this.rules.WedgeMeasureBeginOpeningLength,
+                                          wedgeOpeningLength: number = this.rules.WedgeOpeningLength,
+                                          wedgeLineWidth: number = this.rules.WedgeLineWidth): void {
+        const upperLineStart: PointF2D = new PointF2D(startX, y - wedgeMeasureBeginOpeningLength / 2);
+        const lowerLineStart: PointF2D = new PointF2D(startX, y + wedgeMeasureBeginOpeningLength / 2);
+        const upperLineEnd: PointF2D = new PointF2D(endX, y - wedgeOpeningLength / 2);
+        const lowerLineEnd: PointF2D = new PointF2D(endX, y + wedgeOpeningLength / 2);
+        this.addDoubleLines(upperLineStart, upperLineEnd, lowerLineStart, lowerLineEnd, wedgeLineWidth);
+    }
+
+    /**
+     * This method recalculates the Crescendo Lines (for all cases).
+     * @param startX left most starting point
+     * @param endX right most ending point
+     * @param y y placement
+     */
+    public recalculateCrescendoLines(startX: number, endX: number, y: number): void {
+        const isSecondHalfSplit: boolean = Math.abs(this.lines[0].Start.y - this.lines[1].Start.y) > 0.0001;
+        this.lines.clear();
+
+        if (isSecondHalfSplit) {
+            this.createSecondHalfCrescendoLines(startX, endX, y);
+        } else if (this.isSplittedPart) {
+            this.createFirstHalfCrescendoLines(startX, endX, y);
+        } else {
+            this.createCrescendoLines(startX, endX, y);
+        }
+    }
+
+    /**
+     * Calculate diminuendo lines for system break (full).
+     * @param startX left most starting point
+     * @param endX right mist ending point
+     * @param y y placement
+     * @param wedgeOpeningLength length of the opening
+     * @param wedgeLineWidth line width of the wedge
+     */
+    public createDiminuendoLines(startX: number, endX: number, y: number,
+                                 wedgeOpeningLength: number = this.rules.WedgeOpeningLength, wedgeLineWidth: number = this.rules.WedgeLineWidth): void {
+        const upperWedgeStart: PointF2D = new PointF2D(startX, y - wedgeOpeningLength / 2);
+        const lowerWedgeStart: PointF2D = new PointF2D(startX, y + wedgeOpeningLength / 2);
+        const wedgeEnd: PointF2D = new PointF2D(endX, y);
+        this.addWedgeLines(wedgeEnd, upperWedgeStart, lowerWedgeStart, wedgeLineWidth);
+    }
+
+    /**
+     * Calculate diminuendo lines for system break (first part).
+     * @param startX left most starting point
+     * @param endX right mist ending point
+     * @param y y placement
+     * @param wedgeOpeningLength length of the opening
+     * @param wedgeMeasureEndOpeningLength length of opening at measure end
+     * @param wedgeLineWidth line width of the wedge
+     */
+    public createFirstHalfDiminuendoLines(startX: number, endX: number, y: number,
+                                          wedgeOpeningLength: number = this.rules.WedgeOpeningLength,
+                                          wedgeMeasureEndOpeningLength: number = this.rules.WedgeMeasureEndOpeningLength,
+                                          wedgeLineWidth: number = this.rules.WedgeLineWidth): void {
+        const upperLineStart: PointF2D = new PointF2D(startX, y - wedgeOpeningLength / 2);
+        const lowerLineStart: PointF2D = new PointF2D(startX, y + wedgeOpeningLength / 2);
+        const upperLineEnd: PointF2D = new PointF2D(endX, y - wedgeMeasureEndOpeningLength / 2);
+        const lowerLineEnd: PointF2D = new PointF2D(endX, y + wedgeMeasureEndOpeningLength / 2);
+        this.addDoubleLines(upperLineStart, upperLineEnd, lowerLineStart, lowerLineEnd, wedgeLineWidth);
+    }
+
+    /**
+     * Calculate diminuendo lines for system break (second part).
+     * @param startX left most starting point
+     * @param endX right mist ending point
+     * @param y y placement
+     * @param wedgeMeasureBeginOpeningLength length of opening at measure start
+     * @param wedgeLineWidth line width of the wedge
+     */
+    public createSecondHalfDiminuendoLines(startX: number, endX: number, y: number,
+                                           wedgeMeasureBeginOpeningLength: number = this.rules.WedgeMeasureBeginOpeningLength,
+                                           wedgeLineWidth: number = this.rules.WedgeLineWidth): void {
+        const upperLineStart: PointF2D = new PointF2D(startX, y - wedgeMeasureBeginOpeningLength / 2);
+        const lowerLineStart: PointF2D = new PointF2D(startX, y + wedgeMeasureBeginOpeningLength / 2);
+        const lineEnd: PointF2D = new PointF2D(endX, y);
+        this.addWedgeLines(lineEnd, upperLineStart, lowerLineStart, wedgeLineWidth);
+    }
+
+    /**
+     * This method recalculates the diminuendo lines (for all cases).
+     * @param startX left most starting point
+     * @param endX right most ending point
+     * @param y y placement
+     */
+    public recalculateDiminuendoLines(startX: number, endX: number, yPosition: number): void {
+        const isFirstHalfSplit: boolean = Math.abs(this.lines[0].End.y - this.lines[1].End.y) > 0.0001;
+        this.lines.clear();
+        if (isFirstHalfSplit) {
+            this.createFirstHalfDiminuendoLines(startX, endX, yPosition);
+        } else if (this.isSplittedPart) {
+            this.createSecondHalfDiminuendoLines(startX, endX, yPosition);
+        } else {
+            this.createDiminuendoLines(startX, endX, yPosition);
+        }
+    }
+
+    /**
+     * Calculate the BoundingBox (as a box around the Wedge).
+     */
+    public calcPsi(): void {
+        if (this.IsVerbal) {
+            this.PositionAndShape.calculateBoundingBox();
+            return;
+        }
+        this.PositionAndShape.RelativePosition = this.lines[0].Start;
+        this.PositionAndShape.BorderMarginTop = this.lines[0].End.y - this.lines[0].Start.y;
+        this.PositionAndShape.BorderMarginBottom = this.lines[1].End.y - this.lines[1].Start.y;
+        this.PositionAndShape.Center.y = (this.PositionAndShape.BorderMarginTop + this.PositionAndShape.BorderMarginBottom) / 2;
+        // TODO is the center position correct? it wasn't set before, important for AlignmentManager.alignDynamicExpressions()
+        // console.log(`relative y, center y: ${this.PositionAndShape.RelativePosition.y},${this.PositionAndShape.Center.y})`);
+
+
+        if (this.ContinuousDynamic.DynamicType === ContDynamicEnum.crescendo) {
+            this.PositionAndShape.BorderMarginLeft = 0;
+            this.PositionAndShape.BorderMarginRight = this.lines[0].End.x - this.lines[0].Start.x;
+        } else {
+            this.PositionAndShape.BorderMarginLeft = this.lines[0].End.x - this.lines[0].Start.x;
+            this.PositionAndShape.BorderMarginRight = 0;
+        }
+    }
+
+    /**
+     * Clear Lines
+     */
+    public cleanUp(): void {
+        this.lines.clear();
+    }
+
+    /**
+     * Shift wedge in y position
+     * @param shift Number to shift
+     */
+    public shiftYPosition(shift: number): void {
+        if (this.IsVerbal) {
+            this.PositionAndShape.RelativePosition.y += shift;
+            this.PositionAndShape.calculateBoundingBox();
+        } else {
+            this.lines[0].Start.y += shift;
+            this.lines[0].End.y += shift;
+            this.lines[1].End.y += shift;
+        }
+    }
+
+    public squeeze(value: number): void {
+        // Verbal expressions are not squeezable and squeezing below the width is also not possible
+        if (this.IsVerbal) {
+            return;
+        }
+        const width: number = Math.abs(this.lines[0].End.x - this.lines[0].Start.x);
+        if (width < Math.abs(value)) {
+            return;
+        }
+        if (this.ContinuousDynamic.DynamicType === ContDynamicEnum.crescendo) {
+            if (value > 0) {
+                this.lines[0].Start.x += value;
+            } else {
+                this.lines[0].End.x += value;
+                this.lines[1].End.x += value;
+            }
+        } else {
+            if (value < 0) {
+                this.lines[0].Start.x += value;
+            } else {
+                this.lines[0].End.x += value;
+                this.lines[1].End.x += value;
+            }
+        }
+        this.calcPsi();
+    }
+
+    //#endregion
+
+    //#region Private methods
+
+    /**
+     * Create lines from points and add them to the memory
+     * @param wedgePoint start of the expression
+     * @param upperWedgeEnd end of the upper line
+     * @param lowerWedgeEnd end of lower line
+     * @param wedgeLineWidth line width
+     */
+    private addWedgeLines(wedgePoint: PointF2D, upperWedgeEnd: PointF2D, lowerWedgeEnd: PointF2D, wedgeLineWidth: number): void {
+        const upperLine: GraphicalLine = new GraphicalLine(wedgePoint, upperWedgeEnd, wedgeLineWidth);
+        const lowerLine: GraphicalLine = new GraphicalLine(wedgePoint, lowerWedgeEnd, wedgeLineWidth);
+
+        this.lines.push(upperLine);
+        this.lines.push(lowerLine);
+    }
+
+    /**
+     * Create top and bottom lines for continuing wedges
+     * @param upperLineStart start of the upper line
+     * @param upperLineEnd end of the upper line
+     * @param lowerLineStart start of the lower line
+     * @param lowerLineEnd end of lower line
+     * @param wedgeLineWidth line width
+     */
+    private addDoubleLines(upperLineStart: PointF2D, upperLineEnd: PointF2D, lowerLineStart: PointF2D, lowerLineEnd: PointF2D, wedgeLineWidth: number): void {
+        const upperLine: GraphicalLine = new GraphicalLine(upperLineStart, upperLineEnd, wedgeLineWidth);
+        const lowerLine: GraphicalLine = new GraphicalLine(lowerLineStart, lowerLineEnd, wedgeLineWidth);
+
+        this.lines.push(upperLine);
+        this.lines.push(lowerLine);
+    }
+
+    //#endregion
+}

+ 49 - 0
src/MusicalScore/Graphical/GraphicalCurve.ts

@@ -0,0 +1,49 @@
+import { PointF2D } from "../../Common/DataObjects/PointF2D";
+
+export class GraphicalCurve {
+    private static bezierCurveStepSize: number = 1000;
+    private static tPow3: number[];
+    private static oneMinusTPow3: number[];
+    private static bezierFactorOne: number[];
+    private static bezierFactorTwo: number[];
+
+    // Pre-calculate Curve-independend factors, to be used later in the Slur- and TieCurvePoints calculation.
+    constructor() {
+        GraphicalCurve.tPow3 = new Array(GraphicalCurve.bezierCurveStepSize);
+        GraphicalCurve.oneMinusTPow3 = new Array(GraphicalCurve.bezierCurveStepSize);
+        GraphicalCurve.bezierFactorOne = new Array(GraphicalCurve.bezierCurveStepSize);
+        GraphicalCurve.bezierFactorTwo = new Array(GraphicalCurve.bezierCurveStepSize);
+        for (let i: number = 0; i < GraphicalCurve.bezierCurveStepSize; i++) {
+            const t: number =  i / GraphicalCurve.bezierCurveStepSize;
+
+            GraphicalCurve.tPow3[i] = Math.pow(t, 3);
+            GraphicalCurve.oneMinusTPow3[i] = Math.pow((1 - t), 3);
+            GraphicalCurve.bezierFactorOne[i] = 3 * Math.pow((1 - t), 2) * t;
+            GraphicalCurve.bezierFactorTwo[i] = 3 * (1 - t) * Math.pow(t, 2);
+        }
+    }
+
+    public bezierStartPt: PointF2D;
+    public bezierStartControlPt: PointF2D;
+    public bezierEndControlPt: PointF2D;
+    public bezierEndPt: PointF2D;
+
+    /**
+     *
+     * @param relativePosition
+     */
+    public calculateCurvePointAtIndex(relativePosition: number): PointF2D {
+        const index: number =  Math.round(relativePosition * GraphicalCurve.bezierCurveStepSize);
+        if (index < 0 || index >= GraphicalCurve.bezierCurveStepSize) {
+            return new PointF2D();
+        }
+
+        return new PointF2D(  (GraphicalCurve.oneMinusTPow3[index] * this.bezierStartPt.x
+            + GraphicalCurve.bezierFactorOne[index] * this.bezierStartControlPt.x
+            + GraphicalCurve.bezierFactorTwo[index] * this.bezierEndControlPt.x
+            + GraphicalCurve.tPow3[index] * this.bezierEndPt.x)
+            ,                 (GraphicalCurve.oneMinusTPow3[index] * this.bezierStartPt.y
+            + GraphicalCurve.bezierFactorOne[index] * this.bezierStartControlPt.y
+            + GraphicalCurve.bezierFactorTwo[index] * this.bezierEndControlPt.y + GraphicalCurve.tPow3[index] * this.bezierEndPt.y));
+    }
+}

+ 37 - 0
src/MusicalScore/Graphical/GraphicalInstantaneousDynamicExpression.ts

@@ -0,0 +1,37 @@
+import { StaffLine } from "./StaffLine";
+import { InstantaneousDynamicExpression } from "../VoiceData/Expressions/InstantaneousDynamicExpression";
+import { GraphicalMeasure } from "./GraphicalMeasure";
+import { AbstractGraphicalExpression } from "./AbstractGraphicalExpression";
+import { SkyBottomLineCalculator } from "./SkyBottomLineCalculator";
+import { PlacementEnum } from "../VoiceData/Expressions/AbstractExpression";
+import log from "loglevel";
+
+export class GraphicalInstantaneousDynamicExpression extends AbstractGraphicalExpression {
+    protected mInstantaneousDynamicExpression: InstantaneousDynamicExpression;
+    protected mMeasure: GraphicalMeasure;
+
+    constructor(instantaneousDynamic: InstantaneousDynamicExpression, staffLine: StaffLine, measure: GraphicalMeasure) {
+        super(staffLine, instantaneousDynamic, measure.parentSourceMeasure);
+        this.mInstantaneousDynamicExpression = instantaneousDynamic;
+        this.mMeasure = measure;
+    }
+
+    public updateSkyBottomLine(): void {
+        const skyBottomLineCalculator: SkyBottomLineCalculator = this.parentStaffLine.SkyBottomLineCalculator;
+        const left: number = this.PositionAndShape.RelativePosition.x + this.PositionAndShape.BorderMarginLeft;
+        const right: number = this.PositionAndShape.RelativePosition.x + this.PositionAndShape.BorderMarginRight;
+        let yValue: number = 0;
+        switch (this.Placement) {
+            case PlacementEnum.Above:
+                yValue = this.PositionAndShape.RelativePosition.y + this.PositionAndShape.BorderMarginTop;
+                skyBottomLineCalculator.updateSkyLineInRange(left, right, yValue);
+                break;
+            case PlacementEnum.Below:
+                yValue = this.PositionAndShape.RelativePosition.y + this.PositionAndShape.BorderMarginBottom;
+                skyBottomLineCalculator.updateBottomLineInRange(left, right, yValue);
+                break;
+            default:
+                log.error("Placement for GraphicalInstantaneousDynamicExpression is unknown");
+        }
+    }
+}

+ 21 - 0
src/MusicalScore/Graphical/GraphicalInstantaneousTempoExpression.ts

@@ -0,0 +1,21 @@
+
+import { StaffLine } from "./StaffLine";
+import { AbstractTempoExpression } from "../VoiceData/Expressions/AbstractTempoExpression";
+import { GraphicalLabel } from "./GraphicalLabel";
+import { AbstractGraphicalExpression } from "./AbstractGraphicalExpression";
+
+export class GraphicalInstantaneousTempoExpression extends AbstractGraphicalExpression {
+
+    constructor(tempoExpresssion: AbstractTempoExpression, label: GraphicalLabel) {
+        super((label.PositionAndShape.Parent.DataObject as StaffLine), tempoExpresssion, tempoExpresssion.parentMeasure);
+        this.label = label;
+    }
+
+    public get GraphicalLabel(): GraphicalLabel {
+        return this.label;
+    }
+
+    public updateSkyBottomLine(): void {
+        // Not implemented
+    }
+}

+ 163 - 0
src/MusicalScore/Graphical/GraphicalLabel.ts

@@ -0,0 +1,163 @@
+import { TextAlignmentEnum } from "../../Common/Enums/TextAlignment";
+import { Label } from "../Label";
+import { BoundingBox } from "./BoundingBox";
+import { Clickable } from "./Clickable";
+import { EngravingRules } from "./EngravingRules";
+import { MusicSheetCalculator } from "./MusicSheetCalculator";
+
+/**
+ * The graphical counterpart of a Label
+ */
+export class GraphicalLabel extends Clickable {
+    private label: Label;
+    private rules: EngravingRules;
+    public TextLines: {text: string, xOffset: number, width: number}[];
+
+    /**
+     * Creates a new GraphicalLabel from a Label
+     * @param label  label object containing text
+     * @param textHeight Height of text
+     * @param alignment Alignement like left, right, top, ...
+     * @param parent Parent Bounding Box where the label is attached to
+     */
+    constructor(label: Label, textHeight: number, alignment: TextAlignmentEnum, rules: EngravingRules,
+                parent: BoundingBox = undefined, ) {
+        super();
+        this.label = label;
+        this.boundingBox = new BoundingBox(this, parent);
+        this.label.fontHeight = textHeight;
+        this.label.textAlignment = alignment;
+        this.rules = rules;
+
+        if (this.rules.MpatMode) {
+            if (this.label.text === "TRIO") {
+                this.label.fontFamily = "Arial";
+            }
+        }
+    }
+
+    public get Label(): Label {
+        return this.label;
+    }
+
+    public toString(): string {
+        return `${this.label.text} (${this.boundingBox.RelativePosition.x},${this.boundingBox.RelativePosition.y})`;
+    }
+
+    /**
+     * Calculate GraphicalLabel's Borders according to its Alignment
+     * Create also the text-lines and their offsets here
+     */
+    public setLabelPositionAndShapeBorders(): void {
+        if (this.Label.text.trim() === "") {
+            return;
+        }
+        this.TextLines = [];
+        const labelMarginBorderFactor: number = this.rules?.LabelMarginBorderFactor ?? 0.1;
+        const lines: string[] = this.Label.text.split(/[\n\r]+/g);
+        const numOfLines: number = lines.length;
+        let maxWidth: number = 0;
+        for (let i: number = 0; i < numOfLines; i++) {
+            const line: string = lines[i].trim();
+            if (!line || line === "") {
+                continue;
+            }
+            const widthToHeightRatio: number =
+            MusicSheetCalculator.TextMeasurer.computeTextWidthToHeightRatio(
+               line, this.Label.font, this.Label.fontStyle, this.label.fontFamily);
+            const currWidth: number = this.Label.fontHeight * widthToHeightRatio;
+            maxWidth = Math.max(maxWidth, currWidth);
+            // here push only text and width of the text:
+            this.TextLines.push({text: line, xOffset: 0, width: currWidth});
+        }
+
+        // maxWidth is calculated ->
+        // now also set the x-offsets:
+        for (const line of this.TextLines) {
+            let xOffset: number = 0;
+            switch (this.Label.textAlignment) {
+                case TextAlignmentEnum.RightBottom:
+                case TextAlignmentEnum.RightCenter:
+                case TextAlignmentEnum.RightTop:
+                    xOffset = maxWidth - line.width;
+                    break;
+                case TextAlignmentEnum.CenterBottom:
+                case TextAlignmentEnum.CenterCenter:
+                case TextAlignmentEnum.CenterTop:
+                    xOffset = (maxWidth - line.width) / 2;
+                    break;
+                default:
+                    break;
+            }
+            line.xOffset = xOffset;
+        }
+
+        let height: number = this.Label.fontHeight * numOfLines;
+        if (this.rules.SpacingBetweenTextLines > 0 && this.TextLines.length > 1) {
+            height += (this.rules.SpacingBetweenTextLines * numOfLines) / 10;
+        }
+        const bbox: BoundingBox = this.PositionAndShape;
+
+        switch (this.Label.textAlignment) {
+            case TextAlignmentEnum.CenterBottom:
+                bbox.BorderTop = -height;
+                bbox.BorderLeft = -maxWidth / 2;
+                bbox.BorderBottom = 0;
+                bbox.BorderRight = maxWidth / 2;
+                break;
+            case TextAlignmentEnum.CenterCenter:
+                bbox.BorderTop = -height / 2;
+                bbox.BorderLeft = -maxWidth / 2;
+                bbox.BorderBottom = height / 2;
+                bbox.BorderRight = maxWidth / 2;
+                break;
+            case TextAlignmentEnum.CenterTop:
+                bbox.BorderTop = 0;
+                bbox.BorderLeft = -maxWidth / 2;
+                bbox.BorderBottom = height;
+                bbox.BorderRight = maxWidth / 2;
+                break;
+            case TextAlignmentEnum.LeftBottom:
+                bbox.BorderTop = -height;
+                bbox.BorderLeft = 0;
+                bbox.BorderBottom = 0;
+                bbox.BorderRight = maxWidth;
+                break;
+            case TextAlignmentEnum.LeftCenter:
+                bbox.BorderTop = -height / 2;
+                bbox.BorderLeft = 0;
+                bbox.BorderBottom = height / 2;
+                bbox.BorderRight = maxWidth;
+                break;
+            case TextAlignmentEnum.LeftTop:
+                bbox.BorderTop = 0;
+                bbox.BorderLeft = 0;
+                bbox.BorderBottom = height;
+                bbox.BorderRight = maxWidth;
+                break;
+            case TextAlignmentEnum.RightBottom:
+                bbox.BorderTop = -height;
+                bbox.BorderLeft = -maxWidth;
+                bbox.BorderBottom = 0;
+                bbox.BorderRight = 0;
+                break;
+            case TextAlignmentEnum.RightCenter:
+                bbox.BorderTop = -height / 2;
+                bbox.BorderLeft = -maxWidth;
+                bbox.BorderBottom = height / 2;
+                bbox.BorderRight = 0;
+                break;
+            case TextAlignmentEnum.RightTop:
+                bbox.BorderTop = 0;
+                bbox.BorderLeft = -maxWidth;
+                bbox.BorderBottom = height;
+                bbox.BorderRight = 0;
+                break;
+            default:
+        }
+        bbox.BorderMarginTop = bbox.BorderTop - height * labelMarginBorderFactor;
+        bbox.BorderMarginLeft = bbox.BorderLeft - height * labelMarginBorderFactor;
+        bbox.BorderMarginBottom = bbox.BorderBottom + height * labelMarginBorderFactor;
+        bbox.BorderMarginRight = bbox.BorderRight + height * labelMarginBorderFactor;
+    }
+}

+ 22 - 0
src/MusicalScore/Graphical/GraphicalLayer.ts

@@ -0,0 +1,22 @@
+import { v4 as uuidv4 } from "uuid";
+import { GraphicalObject } from "./GraphicalObject";
+
+export class GraphicalLayer<T extends GraphicalObject> {
+    public readonly UUID: string;
+    public Name: string;
+    public MemberObjects: T[];
+
+    constructor(layerName?: string, UUID?: string) {
+        this.Name = layerName;
+        if (UUID) {
+            this.UUID = UUID;
+        } else {
+            this.UUID = uuidv4();
+        }
+        this.MemberObjects = [];
+    }
+
+    public Equals(otherLayer: GraphicalLayer<T>): boolean {
+        return this.UUID === otherLayer.UUID;
+    }
+}

+ 40 - 0
src/MusicalScore/Graphical/GraphicalLine.ts

@@ -0,0 +1,40 @@
+
+import {OutlineAndFillStyleEnum} from "./DrawingEnums";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+
+export class GraphicalLine {
+    constructor(start: PointF2D, end: PointF2D, width: number = 0,
+        styleEnum: OutlineAndFillStyleEnum = OutlineAndFillStyleEnum.BaseWritingColor,
+        colorHex: string = undefined) {
+        this.start = start;
+        this.end = end;
+        this.width = width;
+        this.styleId = <number>styleEnum;
+        this.colorHex = colorHex;
+    }
+    public styleId: number;
+
+    private start: PointF2D;
+    private end: PointF2D;
+    private width: number;
+    public colorHex: string; // will override styleId if not undefined
+
+    public get Start(): PointF2D {
+        return this.start;
+    }
+    public set Start(value: PointF2D) {
+        this.start = value;
+    }
+    public get End(): PointF2D {
+        return this.end;
+    }
+    public set End(value: PointF2D) {
+        this.end = value;
+    }
+    public get Width(): number {
+        return this.width;
+    }
+    public set Width(value: number) {
+        this.width = value;
+    }
+}

+ 64 - 0
src/MusicalScore/Graphical/GraphicalLyricEntry.ts

@@ -0,0 +1,64 @@
+import {LyricsEntry} from "../VoiceData/Lyrics/LyricsEntry";
+import {GraphicalLyricWord} from "./GraphicalLyricWord";
+import {GraphicalLabel} from "./GraphicalLabel";
+import {GraphicalStaffEntry} from "./GraphicalStaffEntry";
+import {Label} from "../Label";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {TextAlignmentEnum} from "../../Common/Enums/TextAlignment";
+
+/**
+ * The graphical counterpart of a [[LyricsEntry]]
+ */
+export class GraphicalLyricEntry {
+    private lyricsEntry: LyricsEntry;
+    private graphicalLyricWord: GraphicalLyricWord;
+    private graphicalLabel: GraphicalLabel;
+    private graphicalStaffEntry: GraphicalStaffEntry;
+
+    constructor(lyricsEntry: LyricsEntry, graphicalStaffEntry: GraphicalStaffEntry, lyricsHeight: number, staffHeight: number) {
+        this.lyricsEntry = lyricsEntry;
+        this.graphicalStaffEntry = graphicalStaffEntry;
+        const lyricsTextAlignment: TextAlignmentEnum = graphicalStaffEntry.parentMeasure.parentSourceMeasure.Rules.LyricsAlignmentStandard;
+        // for small notes with long text, use center alignment
+        // TODO use this, fix center+left alignment combination spacing
+        if (lyricsEntry.Text.length >= 4
+            && lyricsEntry.Parent.Notes[0].Length.Denominator > 4
+            && lyricsTextAlignment === TextAlignmentEnum.LeftBottom) {
+            // lyricsTextAlignment = TextAlignmentAndPlacement.CenterBottom;
+        }
+        const label: Label = new Label(lyricsEntry.Text);
+        this.graphicalLabel = new GraphicalLabel(
+            label,
+            lyricsHeight,
+            lyricsTextAlignment,
+            this.graphicalStaffEntry.parentMeasure.parentSourceMeasure.Rules,
+            graphicalStaffEntry.PositionAndShape,
+        );
+        this.graphicalLabel.PositionAndShape.RelativePosition = new PointF2D(0, staffHeight);
+        if (lyricsTextAlignment === TextAlignmentEnum.LeftBottom) {
+            this.graphicalLabel.PositionAndShape.RelativePosition.x -= 1; // make lyrics optically left-aligned
+        }
+    }
+
+    public get LyricsEntry(): LyricsEntry {
+        return this.lyricsEntry;
+    }
+    public get ParentLyricWord(): GraphicalLyricWord {
+        return this.graphicalLyricWord;
+    }
+    public set ParentLyricWord(value: GraphicalLyricWord) {
+        this.graphicalLyricWord = value;
+    }
+    public get GraphicalLabel(): GraphicalLabel {
+        return this.graphicalLabel;
+    }
+    public set GraphicalLabel(value: GraphicalLabel) {
+        this.graphicalLabel = value;
+    }
+    public get StaffEntryParent(): GraphicalStaffEntry {
+        return this.graphicalStaffEntry;
+    }
+    public set StaffEntryParent(value: GraphicalStaffEntry) {
+        this.graphicalStaffEntry = value;
+    }
+}

+ 43 - 0
src/MusicalScore/Graphical/GraphicalLyricWord.ts

@@ -0,0 +1,43 @@
+import {LyricWord} from "../VoiceData/Lyrics/LyricsWord";
+import {GraphicalLyricEntry} from "./GraphicalLyricEntry";
+
+/**
+ * The graphical counterpart of a [[LyricWord]]
+ */
+export class GraphicalLyricWord {
+    private lyricWord: LyricWord;
+    private graphicalLyricsEntries: GraphicalLyricEntry[] = [];
+
+    constructor(lyricWord: LyricWord) {
+        this.lyricWord = lyricWord;
+        this.initialize();
+    }
+
+    public get GetLyricWord(): LyricWord {
+        return this.lyricWord;
+    }
+
+    public get GraphicalLyricsEntries(): GraphicalLyricEntry[] {
+        return this.graphicalLyricsEntries;
+    }
+
+    public set GraphicalLyricsEntries(value: GraphicalLyricEntry[]) {
+        this.graphicalLyricsEntries = value;
+    }
+
+    public isFilled(): boolean {
+        for (let i: number = 0; i < this.graphicalLyricsEntries.length; i++) {
+            if (!this.graphicalLyricsEntries[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private initialize(): void {
+        // FIXME: This is actually not needed in Javascript as we have dynamic memory allication?
+        for (let i: number = 0; i < this.lyricWord.Syllables.length; i++) {
+            this.graphicalLyricsEntries.push(undefined);
+        }
+    }
+}

+ 17 - 0
src/MusicalScore/Graphical/GraphicalMarkedArea.ts

@@ -0,0 +1,17 @@
+import {GraphicalLabel} from "./GraphicalLabel";
+import {GraphicalRectangle} from "./GraphicalRectangle";
+
+export class GraphicalMarkedArea {
+    constructor(systemRectangle: GraphicalRectangle, labelRectangle: GraphicalRectangle = undefined, label: GraphicalLabel = undefined,
+                settingsLabel: GraphicalLabel = undefined) {
+        this.systemRectangle = systemRectangle;
+        this.labelRectangle = labelRectangle;
+        this.label = label;
+        this.settings = settingsLabel;
+    }
+
+    public systemRectangle: GraphicalRectangle;
+    public labelRectangle: GraphicalRectangle;
+    public label: GraphicalLabel;
+    public settings: GraphicalLabel;
+}

+ 359 - 0
src/MusicalScore/Graphical/GraphicalMeasure.ts

@@ -0,0 +1,359 @@
+import {MusicSystem} from "./MusicSystem";
+import {GraphicalStaffEntry} from "./GraphicalStaffEntry";
+import {SourceMeasure} from "../VoiceData/SourceMeasure";
+import {StaffLine} from "./StaffLine";
+import {Staff} from "../VoiceData/Staff";
+import {GraphicalObject} from "./GraphicalObject";
+import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
+import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction";
+import {RhythmInstruction} from "../VoiceData/Instructions/RhythmInstruction";
+import {Fraction} from "../../Common/DataObjects/Fraction";
+import {Voice} from "../VoiceData/Voice";
+import {VoiceEntry} from "../VoiceData/VoiceEntry";
+import {SystemLinesEnum} from "./SystemLinesEnum";
+import {BoundingBox} from "./BoundingBox";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+
+/**
+ * Represents a measure in the music sheet (one measure in one staff line)
+ */
+export abstract class GraphicalMeasure extends GraphicalObject {
+    protected firstInstructionStaffEntry: GraphicalStaffEntry;
+    protected lastInstructionStaffEntry: GraphicalStaffEntry;
+
+    constructor(staff: Staff = undefined, parentSourceMeasure: SourceMeasure = undefined, staffLine: StaffLine = undefined) {
+        super();
+        this.parentStaff = staff;
+        this.parentSourceMeasure = parentSourceMeasure;
+        this.parentStaffLine = staffLine;
+        if (staffLine) {
+            this.parentStaff = staffLine.ParentStaff;
+            this.PositionAndShape = new BoundingBox(this, staffLine.PositionAndShape);
+        } else {
+            this.PositionAndShape = new BoundingBox(this);
+        }
+        this.PositionAndShape.BorderBottom = 4;
+        if (this.parentSourceMeasure) {
+            this.measureNumber = this.parentSourceMeasure.MeasureNumber;
+        }
+
+        this.staffEntries = [];
+    }
+
+    public parentSourceMeasure: SourceMeasure;
+    public staffEntries: GraphicalStaffEntry[];
+    /**
+     * The x-width of possibly existing: repetition start line, clef, key, rhythm.
+     */
+    public beginInstructionsWidth: number;
+    /**
+     * The minimum possible x-width of all staff entries without overlapping.
+     */
+    public minimumStaffEntriesWidth: number;
+    /**
+     * Will be set by music system builder while building systems.
+     */
+    public staffEntriesScaleFactor: number;
+    /**
+     * The x-width of possibly existing: repetition end line, clef.
+     */
+    public endInstructionsWidth: number;
+    public hasError: boolean;
+    /**
+     * Whether or not this measure is nothing but rest(s).
+     * Also see SourceMeasure.allRests, which is not the same, because a source measure can have multiple staffs/graphicalMeasures.
+     */
+    public hasOnlyRests: boolean = false;
+
+    private parentStaff: Staff;
+    private parentMusicSystem: MusicSystem;
+    private measureNumber: number = -1;
+    private parentStaffLine: StaffLine;
+
+    public get ParentStaff(): Staff {
+        return this.parentStaff;
+    }
+
+    public get ParentMusicSystem(): MusicSystem {
+        return this.parentMusicSystem;
+    }
+
+    public set ParentMusicSystem(value: MusicSystem) {
+        this.parentMusicSystem = value;
+    }
+
+    public get MeasureNumber(): number {
+        return this.measureNumber;
+    }
+
+    public get FirstInstructionStaffEntry(): GraphicalStaffEntry {
+        return this.firstInstructionStaffEntry;
+    }
+
+    public set FirstInstructionStaffEntry(value: GraphicalStaffEntry) {
+        this.firstInstructionStaffEntry = value;
+    }
+
+    public get LastInstructionStaffEntry(): GraphicalStaffEntry {
+        return this.lastInstructionStaffEntry;
+    }
+
+    public set LastInstructionStaffEntry(value: GraphicalStaffEntry) {
+        this.lastInstructionStaffEntry = value;
+    }
+
+    public get ParentStaffLine(): StaffLine {
+        return this.parentStaffLine;
+    }
+
+    public set ParentStaffLine(value: StaffLine) {
+        this.parentStaffLine = value;
+        if (this.parentStaffLine) {
+            this.PositionAndShape.Parent = this.parentStaffLine.PositionAndShape;
+        }
+    }
+
+    /**
+     * Reset all the geometric values and parameters of this measure and put it in an initialized state.
+     * This is needed to evaluate a measure a second time by system builder.
+     */
+    public resetLayout(): void {
+        throw new Error("not implemented");
+    }
+
+    /**
+     * Return the x-width of a given measure line.
+     * @param line
+     */
+    public getLineWidth(line: SystemLinesEnum): number {
+        throw new Error("not implemented");
+    }
+
+    /**
+     * Add the given clef to the begin of the measure.
+     * This has to update/increase BeginInstructionsWidth.
+     * @param clef
+     */
+    public addClefAtBegin(clef: ClefInstruction): void {
+        throw new Error("not implemented");
+    }
+
+    /**
+     * Add the given key to the begin of the measure.
+     * This has to update/increase BeginInstructionsWidth.
+     * @param currentKey - The new valid key.
+     * @param previousKey - The old cancelled key. Needed to show which accidentals are not valid any more.
+     * @param currentClef - The valid clef. Needed to put the accidentals on the right y-positions.
+     */
+    public addKeyAtBegin(currentKey: KeyInstruction, previousKey: KeyInstruction, currentClef: ClefInstruction): void {
+        throw new Error("not implemented");
+    }
+
+    /**
+     * Add the given rhythm to the begin of the measure.
+     * This has to update/increase BeginInstructionsWidth.
+     * @param rhythm
+     */
+    public addRhythmAtBegin(rhythm: RhythmInstruction): void {
+        throw new Error("not implemented");
+    }
+
+    /**
+     * Add the given clef to the end of the measure.
+     * This has to update/increase EndInstructionsWidth.
+     * @param clef
+     */
+    public addClefAtEnd(clef: ClefInstruction, visible: boolean = true): void {
+        throw new Error("not implemented");
+    }
+
+    /**
+     * Set the x-position relative to the staffline (y-Position is always 0 relative to the staffline).
+     * @param xPos
+     */
+    public setPositionInStaffline(xPos: number): void {
+        this.PositionAndShape.RelativePosition = new PointF2D(xPos, 0);
+    }
+
+    /**
+     * Set the overall x-width of the measure.
+     * @param width
+     */
+    public setWidth(width: number): void {
+        this.PositionAndShape.BorderRight = width;
+    }
+
+    /**
+     * This method is called after the StaffEntriesScaleFactor has been set.
+     * Here the final x-positions of the staff entries have to be set.
+     * (multiply the minimal positions with the scaling factor, considering the BeginInstructionsWidth).
+     */
+    public layoutSymbols(): void {
+        throw new Error("not implemented");
+    }
+
+    public findGraphicalStaffEntryFromTimestamp(relativeTimestamp: Fraction): GraphicalStaffEntry {
+        for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            if (graphicalStaffEntry.relInMeasureTimestamp?.Equals(relativeTimestamp)) {
+                return graphicalStaffEntry;
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * Iterate from start to end and find the [[GraphicalStaffEntry]] with the same absolute timestamp.
+     * @param absoluteTimestamp
+     * @returns {any}
+     */
+    public findGraphicalStaffEntryFromVerticalContainerTimestamp(absoluteTimestamp: Fraction): GraphicalStaffEntry {
+        for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            if (graphicalStaffEntry.sourceStaffEntry.VerticalContainerParent.getAbsoluteTimestamp().Equals(absoluteTimestamp)) {
+                return graphicalStaffEntry;
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * Check if the all the [[GraphicalMeasure]]'s [[StaffEntry]]s (their minimum Length) have the same duration with the [[SourceMeasure]].
+     * @returns {boolean}
+     */
+    public hasSameDurationWithSourceMeasureParent(): boolean {
+        const duration: Fraction = new Fraction(0, 1);
+        for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            duration.Add(graphicalStaffEntry.findStaffEntryMinNoteLength());
+        }
+        return duration.Equals(this.parentSourceMeasure.Duration);
+    }
+
+    /**
+     * Check a whole [[Measure]] for the presence of multiple Voices (used for Stem direction).
+     * @returns {boolean}
+     */
+    public hasMultipleVoices(): boolean {
+        if (this.staffEntries.length === 0) {
+            return false;
+        }
+        const voices: Voice[] = [];
+        for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
+            const staffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            for (let idx2: number = 0, len2: number = staffEntry.sourceStaffEntry.VoiceEntries.length; idx2 < len2; ++idx2) {
+                const voiceEntry: VoiceEntry = staffEntry.sourceStaffEntry.VoiceEntries[idx2];
+                if (voices.indexOf(voiceEntry.ParentVoice) < 0) {
+                    voices.push(voiceEntry.ParentVoice);
+                }
+            }
+        }
+        if (voices.length > 1) {
+            return true;
+        }
+        return false;
+    }
+
+    public isVisible(): boolean {
+        return this.ParentStaff.ParentInstrument.Visible;
+    }
+
+    public getGraphicalMeasureDurationFromStaffEntries(): Fraction {
+        let duration: Fraction = new Fraction(0, 1);
+        const voices: Voice[] = [];
+        for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            for (let idx2: number = 0, len2: number = graphicalStaffEntry.sourceStaffEntry.VoiceEntries.length; idx2 < len2; ++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) {
+            const voice: Voice = voices[idx];
+            const voiceDuration: Fraction = new Fraction(0, 1);
+            for (const graphicalStaffEntry of this.staffEntries) {
+                for (const gve of graphicalStaffEntry.graphicalVoiceEntries) {
+                    if (gve.parentVoiceEntry.ParentVoice === voice && gve.notes.length > 0) {
+                        voiceDuration.Add(gve.notes[0].graphicalNoteLength);
+                    }
+                }
+            }
+            if (duration.lt(voiceDuration)) {
+                duration = Fraction.createFromFraction(voiceDuration);
+            }
+        }
+        return duration;
+    }
+
+    public addGraphicalStaffEntry(graphicalStaffEntry: GraphicalStaffEntry): void {
+        this.staffEntries.push(graphicalStaffEntry);
+    }
+
+    /**
+     * Add a [[StaffEntry]] (along with its [[BoundingBox]]) to the current Measure.
+     * @param staffEntry
+     */
+    public addGraphicalStaffEntryAtTimestamp(staffEntry: GraphicalStaffEntry): void {
+        if (staffEntry) {
+            if (this.staffEntries.length === 0 || this.staffEntries[this.staffEntries.length - 1].relInMeasureTimestamp.lt(staffEntry.relInMeasureTimestamp)) {
+                this.staffEntries.push(staffEntry);
+            } else {
+                for (let i: number = this.staffEntries.length - 1; i >= 0; i--) {
+                    if (this.staffEntries[i].relInMeasureTimestamp.lt(staffEntry.relInMeasureTimestamp)) {
+                        this.staffEntries.splice(i + 1, 0, staffEntry);
+                        break;
+                    }
+                    if (i === 0) {
+                        this.staffEntries.splice(i, 0, staffEntry);
+                    }
+                }
+            }
+        }
+    }
+
+    public beginsWithLineRepetition(): boolean {
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        if (!sourceMeasure) {
+            return false;
+        }
+        return sourceMeasure.beginsWithLineRepetition();
+    }
+
+    /**
+     * Check if this Measure is a Repetition Ending.
+     * @returns {boolean}
+     */
+    public endsWithLineRepetition(): boolean {
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        if (!sourceMeasure) {
+            return false;
+        }
+        return sourceMeasure.endsWithLineRepetition();
+    }
+
+    /**
+     * Check if a Repetition starts at the next Measure.
+     * @returns {boolean}
+     */
+    public beginsWithWordRepetition(): boolean {
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        if (!sourceMeasure) {
+            return false;
+        }
+        return sourceMeasure.beginsWithWordRepetition();
+    }
+
+    /**
+     * Check if this Measure is a Repetition Ending.
+     */
+    public endsWithWordRepetition(): boolean {
+        const sourceMeasure: SourceMeasure = this.parentSourceMeasure;
+        if (!sourceMeasure) {
+            return false;
+        }
+        return sourceMeasure.endsWithWordRepetition();
+    }
+}
+

+ 90 - 0
src/MusicalScore/Graphical/GraphicalMusicPage.ts

@@ -0,0 +1,90 @@
+import {BoundingBox} from "./BoundingBox";
+import {GraphicalObject} from "./GraphicalObject";
+import {GraphicalLabel} from "./GraphicalLabel";
+import {MusicSystem} from "./MusicSystem";
+import {EngravingRules} from "./EngravingRules";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {GraphicalMusicSheet} from "./GraphicalMusicSheet";
+
+export class GraphicalMusicPage extends GraphicalObject {
+    private musicSystems: MusicSystem[] = [];
+    private labels: GraphicalLabel[] = [];
+    private parent: GraphicalMusicSheet;
+    private pageNumber: number;
+
+    constructor(parent: GraphicalMusicSheet) {
+        super();
+        this.parent = parent;
+        this.boundingBox = new BoundingBox(this, undefined);
+    }
+
+    public get MusicSystems(): MusicSystem[] {
+        return this.musicSystems;
+    }
+
+    public set MusicSystems(value: MusicSystem[]) {
+        this.musicSystems = value;
+    }
+
+    public get Labels(): GraphicalLabel[] {
+        return this.labels;
+    }
+
+    public set Labels(value: GraphicalLabel[]) {
+        this.labels = value;
+    }
+
+    public get Parent(): GraphicalMusicSheet {
+        return this.parent;
+    }
+
+    public set Parent(value: GraphicalMusicSheet) {
+        this.parent = value;
+    }
+
+    public get PageNumber(): number {
+        return this.pageNumber;
+    }
+
+    public set PageNumber(value: number) {
+        this.pageNumber = value;
+    }
+
+    /**
+     * This method calculates the absolute Position of each GraphicalMusicPage according to a given placement
+     * @param pageIndex
+     * @param rules
+     * @returns {PointF2D}
+     */
+    public setMusicPageAbsolutePosition(pageIndex: number, rules: EngravingRules): PointF2D {
+        return new PointF2D(0.0, 0.0);
+
+        // use this code if pages are rendered on only one canvas:
+        // if (rules.PagePlacement === PagePlacementEnum.Down) {
+        //     return new PointF2D(0.0, pageIndex * rules.PageHeight);
+        // } else if (rules.PagePlacement === PagePlacementEnum.Right) {
+        //     return new PointF2D(pageIndex * this.parent.ParentMusicSheet.pageWidth, 0.0);
+        // } else {
+        //     // placement RightDown
+        //     if (pageIndex % 2 === 0) {
+        //         if (pageIndex === 0) {
+        //             return new PointF2D(0.0, pageIndex * rules.PageHeight);
+        //         } else {
+        //             return new PointF2D(0.0, (pageIndex - 1) * rules.PageHeight);
+        //         }
+        //     } else {
+        //         if (pageIndex === 1) {
+        //             return new PointF2D(this.parent.ParentMusicSheet.pageWidth, (pageIndex - 1) * rules.PageHeight);
+        //         } else {
+        //             return new PointF2D(this.parent.ParentMusicSheet.pageWidth, (pageIndex - 2) * rules.PageHeight);
+        //         }
+        //     }
+        // }
+    }
+}
+
+export enum PagePlacementEnum {
+    Down,
+    Right,
+    RightDown
+}

+ 1006 - 0
src/MusicalScore/Graphical/GraphicalMusicSheet.ts

@@ -0,0 +1,1006 @@
+import {MusicSheet} from "../MusicSheet";
+import {SourceMeasure} from "../VoiceData/SourceMeasure";
+import {GraphicalMeasure} from "./GraphicalMeasure";
+import {GraphicalMusicPage} from "./GraphicalMusicPage";
+import {VerticalGraphicalStaffEntryContainer} from "./VerticalGraphicalStaffEntryContainer";
+import {GraphicalLabel} from "./GraphicalLabel";
+import {GraphicalLine} from "./GraphicalLine";
+import {MusicSystem} from "./MusicSystem";
+import {GraphicalStaffEntry} from "./GraphicalStaffEntry";
+import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
+import {AbstractNotationInstruction} from "../VoiceData/Instructions/AbstractNotationInstruction";
+import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction";
+import {Fraction} from "../../Common/DataObjects/Fraction";
+import {GraphicalNote} from "./GraphicalNote";
+import {Instrument} from "../Instrument";
+import {BoundingBox} from "./BoundingBox";
+import {MusicSheetCalculator} from "./MusicSheetCalculator";
+import log from "loglevel";
+import {CollectionUtil} from "../../Util/CollectionUtil";
+import {SelectionStartSymbol} from "./SelectionStartSymbol";
+import {SelectionEndSymbol} from "./SelectionEndSymbol";
+import {OutlineAndFillStyleEnum} from "./DrawingEnums";
+import { Clickable } from "./Clickable";
+import { StaffLine } from ".";
+import { MusicSheetDrawer } from "./MusicSheetDrawer";
+import { GraphicalVoiceEntry } from "./GraphicalVoiceEntry";
+import { GraphicalObject } from "./GraphicalObject";
+// import { VexFlowMusicSheetDrawer } from "./VexFlow/VexFlowMusicSheetDrawer";
+// import { SvgVexFlowBackend } from "./VexFlow/SvgVexFlowBackend"; // causes build problem with npm start
+
+/**
+ * The graphical counterpart of a [[MusicSheet]]
+ */
+export class GraphicalMusicSheet {
+    constructor(musicSheet: MusicSheet, calculator: MusicSheetCalculator) {
+        this.musicSheet = musicSheet;
+        this.numberOfStaves = this.musicSheet.Staves.length;
+        this.calculator = calculator;
+        this.calculator.initialize(this);
+    }
+
+    private musicSheet: MusicSheet;
+    //private fontInfo: FontInfo = FontInfo.Info;
+    private calculator: MusicSheetCalculator;
+    public drawer: MusicSheetDrawer;
+    private musicPages: GraphicalMusicPage[] = [];
+    /** measures (i,j) where i is the measure number and j the staff index (e.g. staff indices 0, 1 for two piano parts) */
+    private measureList: GraphicalMeasure[][] = [];
+    private verticalGraphicalStaffEntryContainers: VerticalGraphicalStaffEntryContainer[] = [];
+    private title: GraphicalLabel;
+    private subtitle: GraphicalLabel;
+    private composer: GraphicalLabel;
+    private lyricist: GraphicalLabel;
+    private cursors: GraphicalLine[] = [];
+    private selectionStartSymbol: SelectionStartSymbol;
+    private selectionEndSymbol: SelectionEndSymbol;
+    private minAllowedSystemWidth: number;
+    //private systemImages: Dictionary<MusicSystem, SystemImageProperties> = new Dictionary<MusicSystem, SystemImageProperties>();
+    private numberOfStaves: number;
+    private leadSheet: boolean = false;
+
+    public get ParentMusicSheet(): MusicSheet {
+        return this.musicSheet;
+    }
+
+    public get GetCalculator(): MusicSheetCalculator {
+        return this.calculator;
+    }
+
+    public get MusicPages(): GraphicalMusicPage[] {
+        return this.musicPages;
+    }
+
+    public set MusicPages(value: GraphicalMusicPage[]) {
+        this.musicPages = value;
+    }
+
+    //public get FontInfo(): FontInfo {
+    //    return this.fontInfo;
+    //}
+
+    public get MeasureList(): GraphicalMeasure[][] {
+        return this.measureList;
+    }
+
+    public set MeasureList(value: GraphicalMeasure[][]) {
+        this.measureList = value;
+    }
+
+    public get VerticalGraphicalStaffEntryContainers(): VerticalGraphicalStaffEntryContainer[] {
+        return this.verticalGraphicalStaffEntryContainers;
+    }
+
+    public set VerticalGraphicalStaffEntryContainers(value: VerticalGraphicalStaffEntryContainer[]) {
+        this.verticalGraphicalStaffEntryContainers = value;
+    }
+
+    public get Title(): GraphicalLabel {
+        return this.title;
+    }
+
+    public set Title(value: GraphicalLabel) {
+        this.title = value;
+    }
+
+    public get Subtitle(): GraphicalLabel {
+        return this.subtitle;
+    }
+
+    public set Subtitle(value: GraphicalLabel) {
+        this.subtitle = value;
+    }
+
+    public get Composer(): GraphicalLabel {
+        return this.composer;
+    }
+
+    public set Composer(value: GraphicalLabel) {
+        this.composer = value;
+    }
+
+    public get Lyricist(): GraphicalLabel {
+        return this.lyricist;
+    }
+
+    public set Lyricist(value: GraphicalLabel) {
+        this.lyricist = value;
+    }
+
+    public get Cursors(): GraphicalLine[] {
+        return this.cursors;
+    }
+
+    public get SelectionStartSymbol(): SelectionStartSymbol {
+        return this.selectionStartSymbol;
+    }
+
+    public get SelectionEndSymbol(): SelectionEndSymbol {
+        return this.selectionEndSymbol;
+    }
+
+    public get MinAllowedSystemWidth(): number {
+        return this.minAllowedSystemWidth;
+    }
+
+    public set MinAllowedSystemWidth(value: number) {
+        this.minAllowedSystemWidth = value;
+    }
+
+    // public get SystemImages(): Dictionary<MusicSystem, SystemImageProperties> {
+    //     return this.systemImages;
+    // }
+
+    public get NumberOfStaves(): number {
+        return this.numberOfStaves;
+    }
+
+    public get LeadSheet(): boolean {
+        return this.leadSheet;
+    }
+
+    public set LeadSheet(value: boolean) {
+        this.leadSheet = value;
+    }
+
+    /**
+     * Calculate the Absolute Positions from the Relative Positions.
+     * @param graphicalMusicSheet
+     */
+    public static transformRelativeToAbsolutePosition(graphicalMusicSheet: GraphicalMusicSheet): void {
+        for (let i: number = 0; i < graphicalMusicSheet.MusicPages.length; 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);
+        }
+    }
+
+    public Initialize(): void {
+        this.verticalGraphicalStaffEntryContainers = [];
+        this.musicPages = [];
+        this.measureList = [];
+    }
+
+    public reCalculate(): void {
+        this.calculator.calculate();
+    }
+
+    // unused method
+    // public prepare(): void {
+    //     this.calculator.prepareGraphicalMusicSheet();
+    // }
+
+    public EnforceRedrawOfMusicSystems(): void {
+        for (let idx: number = 0, len: number = this.musicPages.length; idx < len; ++idx) {
+            const graphicalMusicPage: GraphicalMusicPage = this.musicPages[idx];
+            for (let idx2: number = 0, len2: number = graphicalMusicPage.MusicSystems.length; idx2 < len2; ++idx2) {
+                const musicSystem: MusicSystem = graphicalMusicPage.MusicSystems[idx2];
+                musicSystem.needsToBeRedrawn = true;
+            }
+        }
+    }
+
+    public getClickedObject<T>(positionOnMusicSheet: PointF2D): T {
+        for (let idx: number = 0, len: number = this.MusicPages.length; idx < len; ++idx) {
+            const graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
+            return graphicalMusicPage.PositionAndShape.getClickedObjectOfType<T>(positionOnMusicSheet);
+        }
+        return undefined;
+    }
+
+    public findGraphicalMeasure(measureIndex: number, staffIndex: number): GraphicalMeasure {
+        for (let i: number = measureIndex; i >= 0; i--) {
+            const gMeasure: GraphicalMeasure = this.measureList[i][staffIndex];
+            if (gMeasure) {
+                return gMeasure;
+            }
+            // else look backwards (previous measures). this is only really valid for MultipleRestMeasures of course.
+        }
+        return undefined; // shouldn't happen
+    }
+
+    /**
+     * Search the MeasureList for a certain GraphicalStaffEntry with the given SourceStaffEntry,
+     * at a certain verticalIndex (eg a corresponding Staff), starting at a specific horizontalIndex (eg specific GraphicalMeasure).
+     * @param staffIndex
+     * @param measureIndex
+     * @param sourceStaffEntry
+     * @returns {any}
+     */
+    public findGraphicalStaffEntryFromMeasureList(staffIndex: number, measureIndex: number, sourceStaffEntry: SourceStaffEntry): GraphicalStaffEntry {
+        for (let i: number = measureIndex; i < this.measureList.length; i++) {
+            const graphicalMeasure: GraphicalMeasure = this.measureList[i][staffIndex];
+            if (!graphicalMeasure) {
+                continue;
+            }
+            for (let idx: number = 0, len: number = graphicalMeasure.staffEntries.length; idx < len; ++idx) {
+                const graphicalStaffEntry: GraphicalStaffEntry = graphicalMeasure.staffEntries[idx];
+                if (graphicalStaffEntry.sourceStaffEntry === sourceStaffEntry) {
+                    return graphicalStaffEntry;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * Return the next (to the right) not null GraphicalStaffEntry from a given Index.
+     * @param staffIndex
+     * @param measureIndex
+     * @param graphicalStaffEntry
+     * @returns {any}
+     */
+    public findNextGraphicalStaffEntry(staffIndex: number, measureIndex: number, graphicalStaffEntry: GraphicalStaffEntry): GraphicalStaffEntry {
+        const graphicalMeasure: GraphicalMeasure = 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) {
+            const nextMeasure: GraphicalMeasure = this.measureList[measureIndex + 1][staffIndex];
+            if (nextMeasure.staffEntries.length > 0) {
+                return nextMeasure.staffEntries[0];
+            }
+        }
+        return undefined;
+    }
+
+    public getFirstVisibleMeasuresListFromIndices(start: number, end: number): GraphicalMeasure[] {
+        const graphicalMeasures: GraphicalMeasure[] = [];
+        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()) {
+                    graphicalMeasures.push(this.measureList[i][j]);
+                    break;
+                }
+            }
+        }
+        return graphicalMeasures;
+    }
+
+    public orderMeasuresByStaffLine(measures: GraphicalMeasure[]): GraphicalMeasure[][] {
+        const orderedMeasures: GraphicalMeasure[][] = [];
+        let mList: GraphicalMeasure[] = [];
+        orderedMeasures.push(mList);
+        for (let i: number = 0; i < measures.length; i++) {
+            if (i === 0) {
+                mList.push(measures[0]);
+            } else {
+                if (measures[i].ParentStaffLine === measures[i - 1].ParentStaffLine) {
+                    mList.push(measures[i]);
+                } else {
+                    if (orderedMeasures.indexOf(mList) === -1) {
+                        orderedMeasures.push(mList);
+                    }
+                    mList = [];
+                    orderedMeasures.push(mList);
+                    mList.push(measures[i]);
+                }
+            }
+        }
+        return orderedMeasures;
+    }
+
+    /**
+     * Return the active Clefs at the start of the first SourceMeasure.
+     * @returns {ClefInstruction[]}
+     */
+    public initializeActiveClefs(): ClefInstruction[] {
+        const activeClefs: ClefInstruction[] = [];
+        const firstSourceMeasure: SourceMeasure = this.musicSheet.getFirstSourceMeasure();
+        if (firstSourceMeasure) {
+            for (let i: number = 0; i < firstSourceMeasure.CompleteNumberOfStaves; i++) {
+                let clef: ClefInstruction = new ClefInstruction();
+                if (firstSourceMeasure.FirstInstructionsStaffEntries[i]) {
+                    for (let idx: number = 0, len: number = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions.length; idx < len; ++idx) {
+                        const abstractNotationInstruction: AbstractNotationInstruction = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions[idx];
+                        if (abstractNotationInstruction instanceof ClefInstruction) {
+                            clef = <ClefInstruction>abstractNotationInstruction;
+
+                        }
+                    }
+                }
+                activeClefs.push(clef);
+            }
+        }
+        return activeClefs;
+    }
+
+    public GetMainKey(): KeyInstruction {
+        const firstSourceMeasure: SourceMeasure = this.musicSheet.getFirstSourceMeasure();
+        if (firstSourceMeasure) {
+            for (let i: number = 0; i < firstSourceMeasure.CompleteNumberOfStaves; i++) {
+                for (let idx: number = 0, len: number = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions.length; idx < len; ++idx) {
+                    const abstractNotationInstruction: AbstractNotationInstruction = firstSourceMeasure.FirstInstructionsStaffEntries[i].Instructions[idx];
+                    if (abstractNotationInstruction instanceof KeyInstruction) {
+                        return <KeyInstruction>abstractNotationInstruction;
+                    }
+                }
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * Create the VerticalContainer and adds it to the List at the correct Timestamp position.
+     * @param timestamp
+     * @returns {any}
+     */
+    public getOrCreateVerticalContainer(timestamp: Fraction): VerticalGraphicalStaffEntryContainer {
+        if (this.verticalGraphicalStaffEntryContainers.length === 0 ||
+            (CollectionUtil.getLastElement(this.verticalGraphicalStaffEntryContainers).AbsoluteTimestamp).lt(timestamp)) {
+            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)) {
+                const verticalGraphicalStaffEntryContainer: VerticalGraphicalStaffEntryContainer =
+                    new VerticalGraphicalStaffEntryContainer(this.numberOfStaves, timestamp);
+                this.verticalGraphicalStaffEntryContainers.splice(i + 1, 0, verticalGraphicalStaffEntryContainer);
+                return verticalGraphicalStaffEntryContainer;
+            }
+            if (this.verticalGraphicalStaffEntryContainers[i].AbsoluteTimestamp.Equals(timestamp)) {
+                return this.verticalGraphicalStaffEntryContainers[i];
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * Does a binary search on the container list and returns the VerticalContainer with the given Timestamp.
+     * The search begins at startIndex, if given.
+     * If the timestamp cannot be found, null is returned.
+     * @param timestamp - The timestamp for which the container shall be found.
+     * @param startIndex - The index from which the search starts in the container list.
+     * @returns {any}
+     * @constructor
+     */
+    public GetVerticalContainerFromTimestamp(timestamp: Fraction, startIndex: number = 0): VerticalGraphicalStaffEntryContainer {
+        const index: number = CollectionUtil.binarySearch(this.verticalGraphicalStaffEntryContainers,
+                                                          new VerticalGraphicalStaffEntryContainer(0, timestamp),
+                                                          VerticalGraphicalStaffEntryContainer.compareByTimestamp,
+                                                          startIndex);
+        if (index >= 0) {
+            return this.verticalGraphicalStaffEntryContainers[index];
+        }
+        return undefined;
+    }
+
+    /**
+     * Perform a binary search for the absolute given Timestamp in all the GraphicalVerticalContainers.
+     * @param musicTimestamp
+     * @returns {number}
+     * @constructor
+     */
+    public GetInterpolatedIndexInVerticalContainers(musicTimestamp: Fraction): number {
+        const containers: VerticalGraphicalStaffEntryContainer[] = this.verticalGraphicalStaffEntryContainers;
+        let leftIndex: number = 0;
+        let rightIndex: number = containers.length - 1;
+        let leftTS: Fraction = undefined;
+        let rightTS: Fraction = undefined;
+        if (musicTimestamp.lte(containers[containers.length - 1].AbsoluteTimestamp)) {
+            while (rightIndex - leftIndex > 1) {
+                const middleIndex: number = Math.floor((rightIndex + leftIndex) / 2);
+                if (containers[leftIndex].AbsoluteTimestamp.Equals(musicTimestamp)) {
+                    rightIndex = leftIndex;
+                    break;
+                } else if (containers[rightIndex].AbsoluteTimestamp.Equals(musicTimestamp)) {
+                    leftIndex = rightIndex;
+                    break;
+                } else if (containers[middleIndex].AbsoluteTimestamp.Equals(musicTimestamp)) {
+                    return this.verticalGraphicalStaffEntryContainers.indexOf(containers[middleIndex]);
+                } else if (musicTimestamp.lt(containers[middleIndex].AbsoluteTimestamp)) {
+                    rightIndex = middleIndex;
+                } else {
+                    leftIndex = middleIndex;
+                }
+            }
+
+            // no interpolation needed
+            if (leftIndex === rightIndex) {
+                return this.verticalGraphicalStaffEntryContainers.indexOf(containers[leftIndex]);
+            }
+            leftTS = containers[leftIndex].AbsoluteTimestamp;
+            rightTS = containers[rightIndex].AbsoluteTimestamp;
+        } else {
+            leftTS = containers[containers.length - 1].AbsoluteTimestamp;
+            rightTS = Fraction.plus(this.getLongestStaffEntryDuration(containers.length - 1), leftTS);
+            rightIndex = containers.length;
+        }
+        const diff: number = rightTS.RealValue - leftTS.RealValue;
+        const diffTS: number = rightTS.RealValue - musicTimestamp.RealValue;
+
+        // estimate the interpolated index
+        const foundIndex: number = rightIndex - (diffTS / diff);
+        return Math.min(foundIndex, this.verticalGraphicalStaffEntryContainers.length);
+    }
+
+    /**
+     * Get a List with the indices of all the visible GraphicalMeasures and calculates their
+     * corresponding indices in the first SourceMeasure, taking into account Instruments with multiple Staves.
+     * @param visibleMeasures
+     * @returns {number[]}
+     */
+    public getVisibleStavesIndicesFromSourceMeasure(visibleMeasures: GraphicalMeasure[]): number[] {
+        const visibleInstruments: Instrument[] = [];
+        const visibleStavesIndices: number[] = [];
+        for (let idx: number = 0, len: number = visibleMeasures.length; idx < len; ++idx) {
+            const graphicalMeasure: GraphicalMeasure = 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) {
+            const instrument: Instrument = visibleInstruments[idx];
+            const index: number = this.musicSheet.getGlobalStaffIndexOfFirstStaff(instrument);
+            for (let j: number = 0; j < instrument.Staves.length; j++) {
+                visibleStavesIndices.push(index + j);
+            }
+        }
+        return visibleStavesIndices;
+    }
+
+    /**
+     * Returns the GraphicalMeasure with the given SourceMeasure as Parent at the given staff index.
+     * @param sourceMeasure
+     * @param staffIndex
+     * @returns {any}
+     */
+    public getGraphicalMeasureFromSourceMeasureAndIndex(sourceMeasure: SourceMeasure, staffIndex: number): GraphicalMeasure {
+        for (let i: number = 0; i < this.measureList.length; i++) {
+            if (this.measureList[i][0]?.parentSourceMeasure === sourceMeasure) {
+                return this.measureList[i][staffIndex];
+            }
+        }
+        return undefined;
+    }
+
+    public getLastGraphicalMeasureFromIndex(staffIndex: number, lastRendered: boolean = true): GraphicalMeasure {
+        let measureIndex: number = this.measureList.length - 1;
+        if (lastRendered) {
+            measureIndex = Math.min(measureIndex, this.musicSheet.Rules.MaxMeasureToDrawIndex);
+        }
+        return this.measureList[measureIndex][staffIndex];
+    }
+
+    public getMeasureIndex(graphicalMeasure: GraphicalMeasure, measureIndex: number, inListIndex: number): boolean {
+        measureIndex = 0;
+        inListIndex = 0;
+        for (; measureIndex < this.measureList.length; measureIndex++) {
+            for (let idx: number = 0, len: number = this.measureList[measureIndex].length; idx < len; ++idx) {
+                const measure: GraphicalMeasure = this.measureList[measureIndex][idx];
+                if (measure === graphicalMeasure) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Generic method to find graphical objects on the sheet at a given location.
+     * @param clickPosition Position in units where we are searching on the sheet
+     * @param className String representation of the class we want to find. Must extend GraphicalObject
+     * @param startSearchArea The area in units around our point to look for our graphical object, default 5
+     * @param maxSearchArea The max area we want to search around our point
+     * @param searchAreaIncrement The amount we expand our search area for each iteration that we don't find an object of the given type
+     * @param shouldBeIncludedTest A callback that determines if the object should be included in our results- return false for no, true for yes
+     */
+    private GetNearestGraphicalObject<T extends GraphicalObject>(
+        clickPosition: PointF2D, className: string = GraphicalObject.name,
+        startSearchArea: number = 5, maxSearchArea: number = 20, searchAreaIncrement: number = 5,
+        shouldBeIncludedTest: (objectToTest: T) => boolean = undefined): T {
+        const foundEntries: T[] = [];
+        //Loop until we find some, or our search area is out of bounds
+        while (foundEntries.length === 0 && startSearchArea <= maxSearchArea) {
+            //Prepare search area
+            const region: BoundingBox = new BoundingBox(undefined);
+            region.BorderLeft = clickPosition.x - startSearchArea;
+            region.BorderTop = clickPosition.y - startSearchArea;
+            region.BorderRight = clickPosition.x + startSearchArea;
+            region.BorderBottom = clickPosition.y + startSearchArea;
+            region.AbsolutePosition = new PointF2D(clickPosition.x, clickPosition.y);
+            region.calculateAbsolutePosition();
+            //Loop through music pages
+            for (let idx: number = 0, len: number = this.MusicPages.length; idx < len; ++idx) {
+                const graphicalMusicPage: GraphicalMusicPage = this.MusicPages[idx];
+                const entries: T[] = graphicalMusicPage.PositionAndShape.getObjectsInRegion<T>(region, false, className);
+                //If we have no entries on this page, skip to next (if exists)
+                if (!entries || entries.length === 0) {
+                    continue;
+                } else {
+                    //Otherwise test all our entries if applicable, store on our found list
+                    for (let idx2: number = 0, len2: number = entries.length; idx2 < len2; ++idx2) {
+                        if (!shouldBeIncludedTest) {
+                            foundEntries.push(entries[idx2]);
+                        } else if (shouldBeIncludedTest(entries[idx2])) {
+                            foundEntries.push(entries[idx2]);
+                        }
+                    }
+                }
+            }
+            //Expand search area, we haven't found anything yet
+            startSearchArea += searchAreaIncrement;
+        }
+        // Get closest entry
+        let closest: T = undefined;
+        for (let idx: number = 0, len: number = foundEntries.length; idx < len; ++idx) {
+            const object: T = foundEntries[idx];
+            if (closest === undefined) {
+                closest = object;
+            } else {
+                const deltaNew: number = this.CalculateDistance(object.PositionAndShape.AbsolutePosition, clickPosition);
+                const deltaOld: number = this.CalculateDistance(closest.PositionAndShape.AbsolutePosition, clickPosition);
+                if (deltaNew < deltaOld) {
+                    closest = object;
+                }
+            }
+        }
+        if (closest) {
+            return closest;
+        }
+        return undefined;
+    }
+
+    public GetNearestVoiceEntry(clickPosition: PointF2D): GraphicalVoiceEntry {
+        return this.GetNearestGraphicalObject<GraphicalVoiceEntry>(clickPosition, GraphicalVoiceEntry.name, 5, 20, 5,
+                                                                   (object: GraphicalVoiceEntry) =>
+                                                                        object.parentStaffEntry.relInMeasureTimestamp !== undefined);
+    }
+
+    public GetNearestNote(clickPosition: PointF2D, maxClickDist: PointF2D): GraphicalNote {
+        // return this.GetNearestGraphicalObject<GraphicalNote>
+        //     (clickPosition, GraphicalNote.name, 10, 10, 1,
+        //      function(note: GraphicalNote): boolean {
+        //          if (Math.abs(note.PositionAndShape.AbsolutePosition.x - clickPosition.x) < maxClickDist.x
+        //              && Math.abs(note.PositionAndShape.AbsolutePosition.y - clickPosition.y) < maxClickDist.y) {
+        //          return true;
+        //          } else {
+        //              return false;
+        //          }
+        //      });
+        //TODO: This functions a little bit different than our GetGraphicalObject method... Perhaps close enough to consolidate
+        //Investigate
+
+        const nearestVoiceEntry: GraphicalVoiceEntry = this.GetNearestVoiceEntry(clickPosition);
+        if (!nearestVoiceEntry) {
+            return undefined;
+        }
+        let closestNote: GraphicalNote;
+        let closestDist: number = Number.MAX_SAFE_INTEGER;
+        // debug: show position in sheet. line starts from the click position, until clickposition.x + 2
+        // (this.drawer as any).DrawOverlayLine( // as VexFlowMusicSheetDrawer
+        //     clickPosition,
+        //     new PointF2D(clickPosition.x + 2, clickPosition.y),
+        //     this.MusicPages[0]);
+        for (const note of nearestVoiceEntry.notes) {
+            const posY: number = note.PositionAndShape.AbsolutePosition.y;
+            const distX: number = Math.abs(note.PositionAndShape.AbsolutePosition.x - clickPosition.x);
+            const distY: number = Math.abs(posY - clickPosition.y);
+            // console.log("note: " + note.sourceNote.Pitch.ToString());
+            if (distX + distY < closestDist) {
+                closestNote = note;
+                closestDist = distX + distY;
+            }
+        }
+        return closestNote;
+    }
+
+    public domToSvg(point: PointF2D): PointF2D {
+        return this.domToSvgTransform(point, true);
+    }
+
+    public svgToDom(point: PointF2D): PointF2D {
+        return this.domToSvgTransform(point, false);
+    }
+
+    public svgToOsmd(point: PointF2D): PointF2D {
+        const pt: PointF2D = new PointF2D(point.x, point.y);
+        pt.x /= 10; // unitInPixels would need to be imported from VexFlowMusicSheetDrawer
+        pt.y /= 10;
+        return pt;
+    }
+
+    // TODO move to VexFlowMusicSheetDrawer? better fit for imports
+    private domToSvgTransform(point: PointF2D, inverse: boolean): PointF2D {
+        const svgBackend: any = (this.drawer as any).Backends[0]; // as SvgVexFlowBackend;
+        // TODO importing SvgVexFlowBackend here causes build problems. Importing VexFlowMusicSheetDrawer seems to be fine, but unnecessary.
+        // if (!(svgBackend instanceof SvgVexFlowBackend)) {
+        //     return undefined;
+        // }
+        const svg: SVGSVGElement = svgBackend.getSvgElement() as SVGSVGElement;
+        const pt: SVGPoint = svg.createSVGPoint();
+        pt.x = point.x;
+        pt.y = point.y;
+        let transformMatrix: DOMMatrix = svg.getScreenCTM();
+        if (inverse) {
+            transformMatrix = transformMatrix.inverse();
+        }
+        const sp: SVGPoint = pt.matrixTransform(transformMatrix);
+        return new PointF2D(sp.x, sp.y);
+    }
+
+    public GetClickableLabel(clickPosition: PointF2D): GraphicalLabel {
+        const initialSearchAreaX: number = 4;
+        const initialSearchAreaY: number = 4;
+        // Prepare search area
+        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) {
+            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) {
+                    const clickedLabel: GraphicalLabel = entries[idx2];
+                    return clickedLabel;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    public GetPossibleCommentAnchor(clickPosition: PointF2D): SourceStaffEntry {
+        const entry: GraphicalVoiceEntry = this.GetNearestVoiceEntry(clickPosition);
+        if (!entry) {
+            return undefined;
+        }
+        return entry.parentStaffEntry.sourceStaffEntry;
+    }
+
+    public GetClickedObjectOfType<T>(positionOnMusicSheet: PointF2D): T {
+        for (let idx: number = 0, len: number = this.musicPages.length; idx < len; ++idx) {
+            const page: GraphicalMusicPage = this.musicPages[idx];
+            const o: Object = page.PositionAndShape.getClickedObjectOfType<T>(positionOnMusicSheet);
+            if (o) {
+                return (o as T);
+            }
+        }
+        return undefined;
+    }
+
+    //Comment copied from Bounding box method:
+    //Generics don't work like this in TS. Casting doesn't filter out objects.
+    //instanceof doesn't work either with generic types. Hopefully instanceof becomes available at some point, for now we have to do annoyingly
+    //specific implementations after calling this to filter the objects.
+    public GetClickedClickable(positionOnMusicSheet: PointF2D): Clickable {
+        for (let idx: number = 0, len: number = this.musicPages.length; idx < len; ++idx) {
+            const page: GraphicalMusicPage = this.musicPages[idx];
+            const o: Object = page.PositionAndShape.getClickedClickable(positionOnMusicSheet);
+            if (o && o instanceof Clickable) {
+                return o;
+            }
+        }
+        return undefined;
+    }
+
+    public tryGetTimestampFromPosition(positionOnMusicSheet: PointF2D): Fraction {
+        const entry: GraphicalStaffEntry = this.GetClickedObjectOfType<GraphicalStaffEntry>(positionOnMusicSheet);
+        if (!entry) {
+            return undefined;
+        }
+        return entry.getAbsoluteTimestamp();
+    }
+
+    public tryGetClickableLabel(positionOnMusicSheet: PointF2D): GraphicalLabel {
+        try {
+            return this.GetClickableLabel(positionOnMusicSheet);
+        } catch (ex) {
+            log.info("GraphicalMusicSheet.tryGetClickableObject", "positionOnMusicSheet: " + positionOnMusicSheet, ex);
+        }
+
+        return undefined;
+    }
+
+    public tryGetTimeStampFromPosition(positionOnMusicSheet: PointF2D): Fraction {
+        try {
+            const entry: GraphicalVoiceEntry = this.GetNearestVoiceEntry(positionOnMusicSheet);
+            if (!entry) {
+                return undefined;
+            }
+            return entry.parentStaffEntry.getAbsoluteTimestamp();
+        } catch (ex) {
+            log.info(
+                "GraphicalMusicSheet.tryGetTimeStampFromPosition",
+                "positionOnMusicSheet: " + positionOnMusicSheet, ex
+            );
+        }
+
+        return undefined;
+    }
+
+    /**
+     * Get visible staffentry for the container given by the index.
+     * @param index
+     * @returns {GraphicalStaffEntry}
+     */
+    public getStaffEntry(index: number): GraphicalStaffEntry {
+        const container: VerticalGraphicalStaffEntryContainer = this.VerticalGraphicalStaffEntryContainers[index];
+        let staffEntry: GraphicalStaffEntry = undefined;
+        try {
+            for (let idx: number = 0, len: number = container.StaffEntries.length; idx < len; ++idx) {
+                const entry: GraphicalStaffEntry = container.StaffEntries[idx];
+                if (!entry || !entry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
+                    continue;
+                }
+                if (!staffEntry) {
+                    staffEntry = entry;
+                } else if (entry.PositionAndShape && staffEntry.PositionAndShape) {
+                    if (staffEntry.PositionAndShape.RelativePosition.x > entry.PositionAndShape.RelativePosition.x) {
+                        staffEntry = entry;
+                    }
+                }
+            }
+        } catch (ex) {
+            log.info("GraphicalMusicSheet.getStaffEntry", ex);
+        }
+
+        return staffEntry;
+    }
+
+    /**
+     * Returns the index of the closest previous (earlier) vertical container which has at least some visible staff entry, with respect to the given index.
+     * @param index
+     * @returns {number}
+     * @constructor
+     */
+    public GetPreviousVisibleContainerIndex(index: number): number {
+        for (let i: number = index - 1; i >= 0; i--) {
+            const entries: GraphicalStaffEntry[] = this.verticalGraphicalStaffEntryContainers[i].StaffEntries;
+            for (let idx: number = 0, len: number = entries.length; idx < len; ++idx) {
+                const entry: GraphicalStaffEntry = entries[idx];
+                if (entry && entry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the closest next (later) vertical container which has at least some visible staff entry, with respect to the given index.
+     * @param index
+     * @returns {number}
+     * @constructor
+     */
+    public GetNextVisibleContainerIndex(index: number): number {
+        for (let i: number = index + 1; i < this.verticalGraphicalStaffEntryContainers.length; ++i) {
+            const entries: GraphicalStaffEntry[] = this.verticalGraphicalStaffEntryContainers[i].StaffEntries;
+            for (let idx: number = 0, len: number = entries.length; idx < len; ++idx) {
+                const entry: GraphicalStaffEntry = entries[idx];
+                if (entry && entry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    public findClosestLeftStaffEntry(fractionalIndex: number, searchOnlyVisibleEntries: boolean): GraphicalStaffEntry {
+        let foundEntry: GraphicalStaffEntry = undefined;
+        let leftIndex: number = Math.floor(fractionalIndex);
+        leftIndex = Math.min(this.VerticalGraphicalStaffEntryContainers.length - 1, leftIndex);
+        for (let i: number = leftIndex; i >= 0; i--) {
+            foundEntry = this.getStaffEntry(i);
+            if (foundEntry) {
+                if (searchOnlyVisibleEntries) {
+                    if (foundEntry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
+                        return foundEntry;
+                    }
+                } else {
+                    return foundEntry;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    public findClosestRightStaffEntry(fractionalIndex: number, returnOnlyVisibleEntries: boolean): GraphicalStaffEntry {
+        let foundEntry: GraphicalStaffEntry = undefined;
+        const rightIndex: number = Math.max(0, Math.ceil(fractionalIndex));
+        for (let i: number = rightIndex; i < this.VerticalGraphicalStaffEntryContainers.length; i++) {
+            foundEntry = this.getStaffEntry(i);
+            if (foundEntry) {
+                if (returnOnlyVisibleEntries) {
+                    if (foundEntry.sourceStaffEntry.ParentStaff.ParentInstrument.Visible) {
+                        return foundEntry;
+                    }
+                } else {
+                    return foundEntry;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    public calculateCursorLineAtTimestamp(musicTimestamp: Fraction, styleEnum: OutlineAndFillStyleEnum): GraphicalLine {
+        const result: [number, MusicSystem] = this.calculateXPositionFromTimestamp(musicTimestamp);
+        const xPos: number = result[0];
+        const correspondingMusicSystem: MusicSystem = result[1];
+        if (!correspondingMusicSystem || correspondingMusicSystem.StaffLines.length === 0) {
+            return undefined;
+        }
+        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;
+        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 && !nextStaffEntry) {
+            return [0, undefined];
+        }
+        let previousStaffEntryMusicSystem: MusicSystem = undefined;
+        if (previousStaffEntry) {
+            // TODO sometimes one of these ParentStaffLine is undefined, either fix this or handle it here
+            previousStaffEntryMusicSystem = previousStaffEntry.parentMeasure.ParentStaffLine?.ParentMusicSystem;
+        } else {
+            previousStaffEntryMusicSystem = nextStaffEntry.parentMeasure.ParentStaffLine?.ParentMusicSystem;
+        }
+        let nextStaffEntryMusicSystem: MusicSystem = undefined;
+        if (nextStaffEntry) {
+            nextStaffEntryMusicSystem = nextStaffEntry.parentMeasure.ParentStaffLine?.ParentMusicSystem;
+        } else {
+            nextStaffEntryMusicSystem = previousStaffEntry.parentMeasure.ParentStaffLine?.ParentMusicSystem;
+        }
+        if (previousStaffEntryMusicSystem === nextStaffEntryMusicSystem) {
+            currentMusicSystem = previousStaffEntryMusicSystem;
+            let fraction: number;
+            let previousStaffEntryPositionX: number;
+            let nextStaffEntryPositionX: number;
+            if (!previousStaffEntry) {
+                previousStaffEntryPositionX = nextStaffEntryPositionX = nextStaffEntry.PositionAndShape.AbsolutePosition.x;
+                fraction = 0;
+            } else if (!nextStaffEntry) {
+                previousStaffEntryPositionX = previousStaffEntry.PositionAndShape.AbsolutePosition.x;
+                nextStaffEntryPositionX = currentMusicSystem.GetRightBorderAbsoluteXPosition();
+                const sm: SourceMeasure = previousStaffEntry.parentMeasure.parentSourceMeasure;
+                fraction = (currentTimeStamp - previousStaffEntry.getAbsoluteTimestamp().RealValue) / (
+                    Fraction.plus(sm.AbsoluteTimestamp, sm.Duration).RealValue - previousStaffEntry.getAbsoluteTimestamp().RealValue);
+            } else {
+                previousStaffEntryPositionX = previousStaffEntry.PositionAndShape.AbsolutePosition.x;
+                nextStaffEntryPositionX = nextStaffEntry.PositionAndShape.AbsolutePosition.x;
+                if (previousStaffEntry === nextStaffEntry) {
+                    fraction = 0;
+                } else {
+                    fraction = (currentTimeStamp - previousStaffEntry.getAbsoluteTimestamp().RealValue) /
+                        (nextStaffEntry.getAbsoluteTimestamp().RealValue - previousStaffEntry.getAbsoluteTimestamp().RealValue);
+                }
+            }
+            fraction = Math.min(1, Math.max(0, fraction));
+            const interpolatedXPosition: number = previousStaffEntryPositionX + fraction * (nextStaffEntryPositionX - previousStaffEntryPositionX);
+            return [interpolatedXPosition, currentMusicSystem];
+        } else {
+            const nextSystemLeftBorderTimeStamp: number = nextStaffEntry.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.RealValue;
+            let fraction: number;
+            let interpolatedXPosition: number;
+            if (currentTimeStamp < nextSystemLeftBorderTimeStamp) {
+                currentMusicSystem = previousStaffEntryMusicSystem;
+                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;
+                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));
+                interpolatedXPosition = nextSystemLeftBorderX + fraction * (nextStaffEntryPositionX - nextSystemLeftBorderX);
+            }
+            return [interpolatedXPosition, currentMusicSystem];
+        }
+    }
+
+    public calculateCursorPoints(xPos: number, correspondingSystem: MusicSystem): [PointF2D, PointF2D] {
+        if (correspondingSystem === undefined || correspondingSystem.StaffLines.length === 0) {
+            return [new PointF2D(), new PointF2D()];
+        }
+
+        const yCoordinate: number = correspondingSystem.PositionAndShape.AbsolutePosition.y;
+        const lastStaffLine: StaffLine = correspondingSystem.StaffLines.last();
+        const height: number = lastStaffLine.PositionAndShape.RelativePosition.y + lastStaffLine.StaffHeight;
+
+        return [new PointF2D(xPos, yCoordinate), new PointF2D(xPos, yCoordinate + height)];
+      }
+
+    public GetNumberOfVisibleInstruments(): number {
+        let visibleInstrumentCount: number = 0;
+        for (let idx: number = 0, len: number = this.musicSheet.Instruments.length; idx < len; ++idx) {
+            const instrument: Instrument = this.musicSheet.Instruments[idx];
+            if (instrument.Visible === true) {
+                visibleInstrumentCount++;
+            }
+        }
+        return visibleInstrumentCount;
+    }
+
+    public GetNumberOfFollowedInstruments(): number {
+        let followedInstrumentCount: number = 0;
+        for (let idx: number = 0, len: number = this.musicSheet.Instruments.length; idx < len; ++idx) {
+            const instrument: Instrument = this.musicSheet.Instruments[idx];
+            if (instrument.Following === true) {
+                followedInstrumentCount++;
+            }
+        }
+        return followedInstrumentCount;
+    }
+
+    /*public GetGraphicalFromSourceMeasure(sourceMeasure: SourceMeasure): GraphicalMeasure[] {
+        return this.sourceToGraphicalMeasureLinks.getValue(sourceMeasure); // TODO gets wrong measure because sourceMeasure is not a valid key
+    }*/
+
+    public GetGraphicalFromSourceStaffEntry(sourceStaffEntry: SourceStaffEntry): GraphicalStaffEntry {
+        const graphicalMeasure: GraphicalMeasure = sourceStaffEntry.VerticalContainerParent.ParentMeasure.VerticalMeasureList
+            [sourceStaffEntry.ParentStaff.idInMusicSheet];
+        return graphicalMeasure.findGraphicalStaffEntryFromTimestamp(sourceStaffEntry.Timestamp);
+    }
+
+    private CalculateDistance(pt1: PointF2D, pt2: PointF2D): number {
+        const deltaX: number = pt1.x - pt2.x;
+        const deltaY: number = pt1.y - pt2.y;
+        return (deltaX * deltaX) + (deltaY * deltaY);
+    }
+
+    /**
+     * Return the longest StaffEntry duration from a GraphicalVerticalContainer.
+     * @param index the index of the vertical container
+     * @returns {Fraction}
+     */
+    private getLongestStaffEntryDuration(index: number): Fraction {
+        let maxLength: Fraction = new Fraction(0, 1);
+        for (const graphicalStaffEntry of this.verticalGraphicalStaffEntryContainers[index].StaffEntries) {
+            if (!graphicalStaffEntry) {
+                continue;
+            }
+            const maxLengthInStaffEntry: Fraction = graphicalStaffEntry.findStaffEntryMaxNoteLength();
+            if (maxLength.lt(maxLengthInStaffEntry)) {
+                maxLength = maxLengthInStaffEntry;
+            }
+        }
+        return maxLength;
+    }
+}
+
+export class SystemImageProperties {
+    public positionInPixels: PointF2D;
+    public systemImageId: number;
+    public system: MusicSystem;
+}

+ 79 - 0
src/MusicalScore/Graphical/GraphicalNote.ts

@@ -0,0 +1,79 @@
+import {Note} from "../VoiceData/Note";
+import {Fraction} from "../../Common/DataObjects/Fraction";
+import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction";
+import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
+import {OctaveEnum} from "../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
+import {AccidentalEnum, Pitch} from "../../Common/DataObjects/Pitch";
+import {GraphicalObject} from "./GraphicalObject";
+import {MusicSheetCalculator} from "./MusicSheetCalculator";
+import {BoundingBox} from "./BoundingBox";
+import {GraphicalVoiceEntry} from "./GraphicalVoiceEntry";
+import {GraphicalMusicPage} from "./GraphicalMusicPage";
+import { EngravingRules } from "./EngravingRules";
+
+/**
+ * The graphical counterpart of a [[Note]]
+ */
+export class GraphicalNote extends GraphicalObject {
+    constructor(note: Note, parent: GraphicalVoiceEntry, rules: EngravingRules, graphicalNoteLength: Fraction = undefined) {
+        super();
+        this.sourceNote = note;
+        this.parentVoiceEntry = parent;
+        this.PositionAndShape = new BoundingBox(this, parent.PositionAndShape);
+        if (graphicalNoteLength) {
+            this.graphicalNoteLength = graphicalNoteLength;
+        } else {
+            this.graphicalNoteLength = note.Length;
+        }
+
+        this.numberOfDots = this.calculateNumberOfNeededDots(this.graphicalNoteLength);
+        this.rules = rules;
+        this.rules.addGraphicalNoteToNoteMap(note, this);
+    }
+
+    public sourceNote: Note;
+    public DrawnAccidental: AccidentalEnum = AccidentalEnum.NONE;
+    public graphicalNoteLength: Fraction;
+    public parentVoiceEntry: GraphicalVoiceEntry;
+    public numberOfDots: number;
+    public rules: EngravingRules;
+    public staffLine: number;
+    public baseFingeringXOffset: number;
+    public baseStringNumberXOffset: number;
+
+    public Transpose(keyInstruction: KeyInstruction, activeClef: ClefInstruction, halfTones: number, octaveEnum: OctaveEnum): Pitch {
+        let transposedPitch: Pitch = this.sourceNote.Pitch;
+        if (MusicSheetCalculator.transposeCalculator) {
+            transposedPitch = MusicSheetCalculator.transposeCalculator.transposePitch(this.sourceNote.Pitch, keyInstruction, halfTones);
+        }
+        return transposedPitch;
+    }
+
+    /**
+     * Return the number of dots needed to represent the given fraction.
+     * @param fraction
+     * @returns {number}
+     */
+    private calculateNumberOfNeededDots(fraction: Fraction): number {
+      let num: number = 1;
+      let product: number = 2;
+      const expandedNumerator: number = fraction.GetExpandedNumerator();
+      if (!this.sourceNote || !this.sourceNote.NoteTuplet) {
+        while (product < expandedNumerator) {
+          num++;
+          product = Math.pow(2, num);
+        }
+      }
+      return Math.min(3, num - 1);
+    }
+
+    public get ParentMusicPage(): GraphicalMusicPage {
+      return this.parentVoiceEntry.parentStaffEntry.parentMeasure.ParentMusicSystem.Parent;
+    }
+
+    /** Get a GraphicalNote from a Note. Use osmd.rules as the second parameter (instance reference).
+     *  Also more easily available via osmd.rules.GNote(note). */
+    public static FromNote(note: Note, rules: EngravingRules): GraphicalNote {
+      return rules.NoteToGraphicalNoteMap.getValue(note.NoteToGraphicalNoteObjectId);
+    }
+}

+ 16 - 0
src/MusicalScore/Graphical/GraphicalObject.ts

@@ -0,0 +1,16 @@
+import { AClassHierarchyTrackable } from "../../Common/Interfaces/AClassHierarchyTrackable";
+import {BoundingBox} from "./BoundingBox";
+
+export class GraphicalObject extends AClassHierarchyTrackable {
+
+    protected boundingBox: BoundingBox;
+
+    public get PositionAndShape(): BoundingBox {
+        return this.boundingBox;
+    }
+
+    public set PositionAndShape(value: BoundingBox) {
+        this.boundingBox = value;
+    }
+
+}

+ 49 - 0
src/MusicalScore/Graphical/GraphicalOctaveShift.ts

@@ -0,0 +1,49 @@
+import {GraphicalObject} from "./GraphicalObject";
+import {OctaveShift, OctaveEnum} from "../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
+import {BoundingBox} from "./BoundingBox";
+import {MusicSymbol} from "./MusicSymbol";
+import {ArgumentOutOfRangeException} from "../Exceptions";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+
+/**
+ * The graphical counterpart of an [[OctaveShift]]
+ */
+export class GraphicalOctaveShift extends GraphicalObject {
+
+    constructor(octaveShift: OctaveShift, parent: BoundingBox) {
+        super();
+        this.getOctaveShift = octaveShift;
+        this.setSymbol();
+        // ToDo: set the size again due to the given symbol...
+        //this.PositionAndShape = new BoundingBox(parent, this.octaveSymbol, this);
+        this.PositionAndShape = new BoundingBox(this, parent);
+    }
+
+    public getOctaveShift: OctaveShift;
+    public octaveSymbol: MusicSymbol;
+    public dashesStart: PointF2D;
+    public dashesEnd: PointF2D;
+    public endsOnDifferentStaffLine: boolean;
+    public isFirstPart: boolean;
+    public isSecondPart: boolean;
+
+    private setSymbol(): void {
+        switch (this.getOctaveShift.Type) {
+            case OctaveEnum.VA8:
+                this.octaveSymbol = MusicSymbol.VA8;
+                break;
+            case OctaveEnum.VB8:
+                this.octaveSymbol = MusicSymbol.VB8;
+                break;
+            case OctaveEnum.MA15:
+                this.octaveSymbol = MusicSymbol.MA15;
+                break;
+            case OctaveEnum.MB15:
+                this.octaveSymbol = MusicSymbol.MB15;
+                break;
+            default:
+                throw new ArgumentOutOfRangeException("");
+        }
+    }
+
+}

+ 18 - 0
src/MusicalScore/Graphical/GraphicalRectangle.ts

@@ -0,0 +1,18 @@
+import {OutlineAndFillStyleEnum} from "./DrawingEnums";
+import {BoundingBox} from "./BoundingBox";
+import {PointF2D} from "../../Common/DataObjects/PointF2D";
+import {GraphicalObject} from "./GraphicalObject";
+
+export class GraphicalRectangle extends GraphicalObject {
+
+    constructor(upperLeftPoint: PointF2D, lowerRightPoint: PointF2D, parent: BoundingBox, style: OutlineAndFillStyleEnum) {
+        super();
+        this.boundingBox = new BoundingBox(parent);
+        this.boundingBox.RelativePosition = upperLeftPoint;
+        this.boundingBox.BorderRight = lowerRightPoint.x - upperLeftPoint.x;
+        this.boundingBox.BorderBottom = lowerRightPoint.y - upperLeftPoint.y;
+        this.style = style;
+    }
+
+    public style: OutlineAndFillStyleEnum;
+}

+ 924 - 0
src/MusicalScore/Graphical/GraphicalSlur.ts

@@ -0,0 +1,924 @@
+
+import { PointF2D } from "../../Common/DataObjects/PointF2D";
+import { GraphicalNote } from "./GraphicalNote";
+import { GraphicalCurve } from "./GraphicalCurve";
+import { Slur } from "../VoiceData/Expressions/ContinuousExpressions/Slur";
+import { PlacementEnum } from "../VoiceData/Expressions/AbstractExpression";
+import { EngravingRules } from "./EngravingRules";
+import { StaffLine } from "./StaffLine";
+import { SkyBottomLineCalculator } from "./SkyBottomLineCalculator";
+import { Matrix2D } from "../../Common/DataObjects/Matrix2D";
+import { LinkedVoice } from "../VoiceData/LinkedVoice";
+import { GraphicalVoiceEntry } from "./GraphicalVoiceEntry";
+import { GraphicalStaffEntry } from "./GraphicalStaffEntry";
+import { Fraction } from "../../Common/DataObjects/Fraction";
+import { StemDirectionType } from "../VoiceData/VoiceEntry";
+
+export class GraphicalSlur extends GraphicalCurve {
+    // private intersection: PointF2D;
+
+    constructor(slur: Slur, rules: EngravingRules) {
+        super();
+        this.slur = slur;
+        this.rules = rules;
+    }
+
+    public slur: Slur;
+    public staffEntries: GraphicalStaffEntry[] = [];
+    public placement: PlacementEnum;
+    public graceStart: boolean;
+    public graceEnd: boolean;
+    private rules: EngravingRules;
+
+    /**
+     * Compares the timespan of two Graphical Slurs
+     * @param x
+     * @param y
+     */
+    public static Compare (x: GraphicalSlur, y: GraphicalSlur ): number {
+        if (x.staffEntries.length < 1) { // x.staffEntries[i] can return undefined in Beethoven Moonlight Sonata sample
+            return -1;
+        } else if (y.staffEntries.length < 1) {
+            return 1;
+        }
+        const xTimestampSpan: Fraction = Fraction.minus(x.staffEntries[x.staffEntries.length - 1].getAbsoluteTimestamp(),
+                                                        x.staffEntries[0].getAbsoluteTimestamp());
+        const yTimestampSpan: Fraction = Fraction.minus(y.staffEntries[y.staffEntries.length - 1].getAbsoluteTimestamp(),
+                                                        y.staffEntries[0].getAbsoluteTimestamp());
+
+        if (xTimestampSpan.RealValue > yTimestampSpan.RealValue) {
+            return 1;
+        }
+
+        if (yTimestampSpan.RealValue > xTimestampSpan.RealValue) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    /**
+     *
+     * @param rules
+     */
+    public calculateCurve(rules: EngravingRules): void {
+
+        // single GraphicalSlur means a single Curve, eg each GraphicalSlurObject is meant to be on the same StaffLine
+        // a Slur can span more than one GraphicalSlurObjects
+        const startStaffEntry: GraphicalStaffEntry = this.staffEntries[0];
+        const endStaffEntry: GraphicalStaffEntry = this.staffEntries[this.staffEntries.length - 1];
+
+        // where the Slur (not the graphicalObject) starts and ends (could belong to another StaffLine)
+        let slurStartNote: GraphicalNote = startStaffEntry.findGraphicalNoteFromNote(this.slur.StartNote);
+        if (!slurStartNote && this.graceStart) {
+            slurStartNote = startStaffEntry.findGraphicalNoteFromGraceNote(this.slur.StartNote);
+        }
+        if (!slurStartNote) {
+            slurStartNote = startStaffEntry.findEndTieGraphicalNoteFromNoteWithStartingSlur(this.slur.StartNote, this.slur);
+        }
+        let slurEndNote: GraphicalNote = endStaffEntry.findGraphicalNoteFromNote(this.slur.EndNote);
+        if (!slurEndNote && this.graceEnd) {
+            slurEndNote = endStaffEntry.findGraphicalNoteFromGraceNote(this.slur.EndNote);
+        }
+
+        const staffLine: StaffLine = startStaffEntry.parentMeasure.ParentStaffLine;
+        const skyBottomLineCalculator: SkyBottomLineCalculator = staffLine.SkyBottomLineCalculator;
+
+        this.calculatePlacement(skyBottomLineCalculator, staffLine);
+
+        // the Start- and End Reference Points for the Sky-BottomLine
+        const startEndPoints: {startX: number, startY: number, endX: number, endY: number} =
+            this.calculateStartAndEnd(slurStartNote, slurEndNote, staffLine, rules, skyBottomLineCalculator);
+
+        const startX: number = startEndPoints.startX;
+        const endX: number = startEndPoints.endX;
+        let startY: number = startEndPoints.startY;
+        let endY: number = startEndPoints.endY;
+        const minAngle: number = rules.SlurTangentMinAngle;
+        const maxAngle: number = rules.SlurTangentMaxAngle;
+        let points: PointF2D[];
+
+        if (this.placement === PlacementEnum.Above) {
+            startY -= rules.SlurNoteHeadYOffset;
+            endY -= rules.SlurNoteHeadYOffset;
+            const startUpperRight: PointF2D = new PointF2D(this.staffEntries[0].parentMeasure.PositionAndShape.RelativePosition.x
+                                                           + this.staffEntries[0].PositionAndShape.RelativePosition.x,
+                                                           startY);
+            if (slurStartNote) {
+                    startUpperRight.x += this.staffEntries[0].PositionAndShape.BorderRight;
+            } else  {
+                    // continuing Slur from previous StaffLine - must start after last Instruction of first Measure
+                    startUpperRight.x = this.staffEntries[0].parentMeasure.beginInstructionsWidth;
+            }
+
+            // must also add the GraceStaffEntry's ParentStaffEntry Position
+            if (this.graceStart) {
+                startUpperRight.x += endStaffEntry.PositionAndShape.RelativePosition.x;
+            }
+
+            const endUpperLeft: PointF2D = new PointF2D(this.staffEntries[this.staffEntries.length - 1].parentMeasure.PositionAndShape.RelativePosition.x
+                                                        + this.staffEntries[this.staffEntries.length - 1].PositionAndShape.RelativePosition.x,
+                                                        endY);
+            if (slurEndNote) {
+                    endUpperLeft.x += this.staffEntries[this.staffEntries.length - 1].PositionAndShape.BorderLeft;
+            } else {
+                    // Slur continues to next StaffLine - must reach the end of current StaffLine
+                    endUpperLeft.x = this.staffEntries[this.staffEntries.length - 1].parentMeasure.PositionAndShape.RelativePosition.x
+                    + this.staffEntries[this.staffEntries.length - 1].parentMeasure.PositionAndShape.Size.width;
+            }
+
+            // must also add the GraceStaffEntry's ParentStaffEntry Position
+            if (this.graceEnd) {
+                endUpperLeft.x += endStaffEntry.staffEntryParent.PositionAndShape.RelativePosition.x;
+            }
+
+            // SkyLinePointsList between firstStaffEntry startUpperRightPoint and lastStaffentry endUpperLeftPoint
+            points = this.calculateTopPoints(startUpperRight, endUpperLeft, staffLine, skyBottomLineCalculator);
+
+            if (points.length === 0) {
+                const pointF: PointF2D = new PointF2D((endUpperLeft.x - startUpperRight.x) / 2 + startUpperRight.x,
+                                                      (endUpperLeft.y - startUpperRight.y) / 2 + startUpperRight.y);
+                points.push(pointF);
+            }
+
+            // Angle between original x-Axis and Line from Start-Point to End-Point
+            const startEndLineAngleRadians: number = (Math.atan((endY - startY) / (endX - startX)));
+
+            // translate origin at Start (positiveY from Bottom to Top => change sign for Y)
+            const start2: PointF2D = new PointF2D(0, 0);
+            let end2: PointF2D = new PointF2D(endX - startX, -(endY - startY));
+
+            // and Rotate at new Origin startEndLineAngle degrees
+                // clockwise/counterclockwise Rotation
+                // after Rotation end2.Y must be 0
+                // Inverse of RotationMatrix = TransposeMatrix of RotationMatrix
+            const rotationMatrix: Matrix2D = Matrix2D.getRotationMatrix(startEndLineAngleRadians);
+            const transposeMatrix: Matrix2D = rotationMatrix.getTransposeMatrix();
+            end2 = rotationMatrix.vectorMultiplication(end2);
+            const transformedPoints: PointF2D[] = this.calculateTranslatedAndRotatedPointListAbove(points, startX, startY, rotationMatrix);
+
+            // calculate tangent Lines maximum Slopes between StartPoint and EndPoint to all Points in SkyLine
+                // and tangent Lines characteristica
+            const startLineSlope: number = this.calculateMaxLeftSlope(transformedPoints, start2, end2);
+            const endLineSlope: number = this.calculateMaxRightSlope(transformedPoints, start2, end2);
+            const startLineD: number = start2.y - start2.x * startLineSlope;
+            const endLineD: number = end2.y - end2.x * endLineSlope;
+
+            // calculate IntersectionPoint of the 2 Lines
+                // if same Slope, then Point.X between Start and End and Point.Y fixed
+            const intersectionPoint: PointF2D = new PointF2D();
+            let sameSlope: boolean = false;
+            if (Math.abs(Math.abs(startLineSlope) - Math.abs(endLineSlope)) < 0.0001) {
+                intersectionPoint.x = end2.x / 2;
+                intersectionPoint.y = 0;
+                sameSlope = true;
+            } else {
+                intersectionPoint.x = (endLineD - startLineD) / (startLineSlope - endLineSlope);
+                intersectionPoint.y = startLineSlope * intersectionPoint.x + startLineD;
+            }
+
+            // calculate HeightWidthRatio between the MaxYpoint (from the points between StartPoint and EndPoint)
+            // and the X-distance from StartPoint to EndPoint
+            const heightWidthRatio: number = this.calculateHeightWidthRatio(end2.x, transformedPoints);
+
+            // Shift start- or endPoint and corresponding controlPoint away from note, if needed:
+            // e.g. if there is a close object creating a high slope, better shift it away to reduce the slope:
+            // idea is to compare the half heightWidthRatio of the bounding box of the skyline points with the slope (which is also a ratio: k/1)
+            // if the slope is greater than the half heightWidthRatio (which will 99% be the case),
+            // then add a y-offset to reduce the slope to the same value as the half heightWidthRatio of the bounding box
+            const startYOffset: number = 0;
+            const endYOffset: number = 0;
+            /*if (Math.abs(heightWidthRatio) > 0.001) {
+                // 1. start side:
+                const startSlopeRatio: number = Math.abs(startLineSlope / (heightWidthRatio * 2));
+                const maxLeftYOffset: number = Math.abs(startLineSlope);
+                startYOffset = Math.max(0, maxLeftYOffset * (Math.min(10, startSlopeRatio - 1) / 10));
+                // slope has to be adapted now due to the y-offset:
+                startLineSlope -= startYOffset;
+
+                // 2. end side:
+                const endSlopeRatio: number = Math.abs(endLineSlope / (heightWidthRatio * 2));
+                const maxRightYOffset: number = Math.abs(endLineSlope);
+                endYOffset = Math.max(0, maxRightYOffset * (Math.min(10, endSlopeRatio - 1) / 10));
+                // slope has to be adapted now due to the y-offset:
+                endLineSlope += endYOffset;
+            }*/
+
+
+
+            // calculate tangent Lines Angles
+                // (using the calculated Slopes and the Ratio from the IntersectionPoint's distance to the MaxPoint in the SkyLine)
+            let startAngle: number = minAngle;
+            let endAngle: number = -minAngle;
+            // if the calculated Slopes (start and end) are equal, then Angles have fixed values
+            if (!sameSlope) {
+                const result: {startAngle: number, endAngle: number} =
+                    this.calculateAngles(minAngle, startLineSlope, endLineSlope, maxAngle);
+                startAngle = result.startAngle;
+                endAngle = result.endAngle;
+            }
+
+            // calculate Curve's Control Points
+            const controlPoints: {startControlPoint: PointF2D, endControlPoint: PointF2D} =
+                this.calculateControlPoints(end2.x, startAngle, endAngle, transformedPoints, heightWidthRatio);
+
+            let startControlPoint: PointF2D = controlPoints.startControlPoint;
+            let endControlPoint: PointF2D = controlPoints.endControlPoint;
+
+            // transform ControlPoints to original Coordinate System
+                // (rotate back and translate back)
+            startControlPoint = transposeMatrix.vectorMultiplication(startControlPoint);
+            startControlPoint.x += startX;
+            startControlPoint.y = -startControlPoint.y + startY;
+            endControlPoint = transposeMatrix.vectorMultiplication(endControlPoint);
+            endControlPoint.x += startX;
+            endControlPoint.y = -endControlPoint.y + startY;
+
+            /* for DEBUG only */
+            // this.intersection = transposeMatrix.vectorMultiplication(intersectionPoint);
+            // this.intersection.x += startX;
+            // this.intersection.y = -this.intersection.y + startY;
+            /* for DEBUG only */
+
+            // set private members
+            this.bezierStartPt = new PointF2D(startX, startY - startYOffset);
+            this.bezierStartControlPt = new PointF2D(startControlPoint.x, startControlPoint.y - startYOffset);
+            this.bezierEndControlPt = new PointF2D(endControlPoint.x, endControlPoint.y - endYOffset);
+            this.bezierEndPt = new PointF2D(endX, endY - endYOffset);
+
+            // calculate slur Curvepoints and update Skyline
+            const length: number = staffLine.SkyLine.length;
+            const startIndex: number = skyBottomLineCalculator.getLeftIndexForPointX(this.bezierStartPt.x, length);
+            const endIndex: number = skyBottomLineCalculator.getLeftIndexForPointX(this.bezierEndPt.x, length);
+            const distance: number = this.bezierEndPt.x - this.bezierStartPt.x;
+            const samplingUnit: number = skyBottomLineCalculator.SamplingUnit;
+            for (let i: number = startIndex; i < endIndex; i++) {
+                // get the right distance ratio and index on the curve
+                const diff: number = i / samplingUnit - this.bezierStartPt.x;
+                const curvePoint: PointF2D = this.calculateCurvePointAtIndex(Math.abs(diff) / distance);
+
+                // update left- and rightIndex for better accuracy
+                let index: number = skyBottomLineCalculator.getLeftIndexForPointX(curvePoint.x, length);
+                // update SkyLine with final slur curve:
+                if (index >= startIndex) {
+                    staffLine.SkyLine[index] = Math.min(staffLine.SkyLine[index], curvePoint.y);
+                }
+                index++;
+                if (index < length) {
+                    staffLine.SkyLine[index] = Math.min(staffLine.SkyLine[index], curvePoint.y);
+                }
+            }
+        } else {
+            startY += rules.SlurNoteHeadYOffset;
+            endY += rules.SlurNoteHeadYOffset;
+
+            // firstStaffEntry startLowerRightPoint and lastStaffentry endLowerLeftPoint
+            const startLowerRight: PointF2D = new PointF2D(this.staffEntries[0].parentMeasure.PositionAndShape.RelativePosition.x
+                                                           + this.staffEntries[0].PositionAndShape.RelativePosition.x,
+                                                           startY);
+            if (slurStartNote) {
+                startLowerRight.x += this.staffEntries[0].PositionAndShape.BorderRight;
+            } else {
+                // continuing Slur from previous StaffLine - must start after last Instruction of first Measure
+                startLowerRight.x = this.staffEntries[0].parentMeasure.beginInstructionsWidth;
+            }
+
+            // must also add the GraceStaffEntry's ParentStaffEntry Position
+            if (this.graceStart) {
+                startLowerRight.x += endStaffEntry.PositionAndShape.RelativePosition.x;
+            }
+            const endLowerLeft: PointF2D = new PointF2D(this.staffEntries[this.staffEntries.length - 1].parentMeasure.PositionAndShape.RelativePosition.x
+                                                        + this.staffEntries[this.staffEntries.length - 1].PositionAndShape.RelativePosition.x,
+                                                        endY);
+            if (slurEndNote) {
+                endLowerLeft.x += this.staffEntries[this.staffEntries.length - 1].PositionAndShape.BorderLeft;
+            } else {
+                // Slur continues to next StaffLine - must reach the end of current StaffLine
+                endLowerLeft.x = this.staffEntries[this.staffEntries.length - 1].parentMeasure.PositionAndShape.RelativePosition.x
+                    + this.staffEntries[this.staffEntries.length - 1].parentMeasure.PositionAndShape.Size.width;
+            }
+
+            // must also add the GraceStaffEntry's ParentStaffEntry Position
+            if (this.graceEnd) {
+                endLowerLeft.x += endStaffEntry.staffEntryParent.PositionAndShape.RelativePosition.x;
+            }
+
+            // BottomLinePointsList between firstStaffEntry startLowerRightPoint and lastStaffentry endLowerLeftPoint
+            points = this.calculateBottomPoints(startLowerRight, endLowerLeft, staffLine, skyBottomLineCalculator);
+
+            if (points.length === 0) {
+                const pointF: PointF2D = new PointF2D((endLowerLeft.x - startLowerRight.x) / 2 + startLowerRight.x,
+                                                      (endLowerLeft.y - startLowerRight.y) / 2 + startLowerRight.y);
+                points.push(pointF);
+            }
+
+            // Angle between original x-Axis and Line from Start-Point to End-Point
+            const startEndLineAngleRadians: number = Math.atan((endY - startY) / (endX - startX));
+            // translate origin at Start
+            const start2: PointF2D = new PointF2D(0, 0);
+            let end2: PointF2D = new PointF2D(endX - startX, endY - startY);
+
+            // and Rotate at new Origin startEndLineAngle degrees
+            // clockwise/counterclockwise Rotation
+            // after Rotation end2.Y must be 0
+            // Inverse of RotationMatrix = TransposeMatrix of RotationMatrix
+            const rotationMatrix: Matrix2D = Matrix2D.getRotationMatrix(-startEndLineAngleRadians);
+            const transposeMatrix: Matrix2D = rotationMatrix.getTransposeMatrix();
+            end2 = rotationMatrix.vectorMultiplication(end2);
+            const transformedPoints: PointF2D[] = this.calculateTranslatedAndRotatedPointListBelow(points, startX, startY, rotationMatrix);
+
+            // calculate tangent Lines maximum Slopes between StartPoint and EndPoint to all Points in BottomLine
+            // and tangent Lines characteristica
+            const startLineSlope: number = this.calculateMaxLeftSlope(transformedPoints, start2, end2);
+            const endLineSlope: number = this.calculateMaxRightSlope(transformedPoints, start2, end2);
+            const startLineD: number = start2.y - start2.x * startLineSlope;
+            const endLineD: number = end2.y - end2.x * endLineSlope;
+
+            // calculate IntersectionPoint of the 2 Lines
+            // if same Slope, then Point.X between Start and End and Point.Y fixed
+            const intersectionPoint: PointF2D = new PointF2D();
+            let sameSlope: boolean = false;
+            if (Math.abs(Math.abs(startLineSlope) - Math.abs(endLineSlope)) < 0.0001) {
+                intersectionPoint.x = end2.x / 2;
+                intersectionPoint.y = 0;
+                sameSlope = true;
+            } else {
+                intersectionPoint.x = (endLineD - startLineD) / (startLineSlope - endLineSlope);
+                intersectionPoint.y = startLineSlope * intersectionPoint.x + startLineD;
+            }
+
+            // calculate HeightWidthRatio between the MaxYpoint (from the points between StartPoint and EndPoint)
+            // and the X-distance from StartPoint to EndPoint
+            const heightWidthRatio: number = this.calculateHeightWidthRatio(end2.x, transformedPoints);
+
+            // Shift start- or endPoint and corresponding controlPoint away from note, if needed:
+            // e.g. if there is a close object creating a high slope, better shift it away to reduce the slope:
+            // idea is to compare the half heightWidthRatio of the bounding box of the skyline points with the slope (which is also a ratio: k/1)
+            // if the slope is greater than the half heightWidthRatio (which will 99% be the case),
+            // then add a y-offset to reduce the slope to the same value as the half heightWidthRatio of the bounding box
+            const startYOffset: number = 0;
+            const endYOffset: number = 0;
+            /*if (Math.abs(heightWidthRatio) > 0.001) {
+                // 1. start side:
+                const startSlopeRatio: number = Math.abs(startLineSlope / (heightWidthRatio * 2));
+                const maxLeftYOffset: number = Math.abs(startLineSlope);
+                startYOffset = Math.max(0, maxLeftYOffset * (Math.min(10, startSlopeRatio - 1) / 10));
+                // slope has to be adapted now due to the y-offset:
+                startLineSlope -= startYOffset;
+                // 2. end side:
+                const endSlopeRatio: number = Math.abs(endLineSlope / (heightWidthRatio * 2));
+                const maxRightYOffset: number = Math.abs(endLineSlope);
+                endYOffset = Math.max(0, maxRightYOffset * (Math.min(10, endSlopeRatio - 1) / 10));
+                // slope has to be adapted now due to the y-offset:
+                endLineSlope += endYOffset;
+            } */
+
+            // calculate tangent Lines Angles
+            // (using the calculated Slopes and the Ratio from the IntersectionPoint's distance to the MaxPoint in the SkyLine)
+            let startAngle: number = minAngle;
+            let endAngle: number = -minAngle;
+            // if the calculated Slopes (start and end) are equal, then Angles have fixed values
+            if (!sameSlope) {
+                const result: {startAngle: number, endAngle: number} =
+                    this.calculateAngles(minAngle, startLineSlope, endLineSlope, maxAngle);
+                startAngle = result.startAngle;
+                endAngle = result.endAngle;
+            }
+
+            // calculate Curve's Control Points
+            const controlPoints: {startControlPoint: PointF2D, endControlPoint: PointF2D} =
+                this.calculateControlPoints(end2.x, startAngle, endAngle, transformedPoints, heightWidthRatio);
+            let startControlPoint: PointF2D = controlPoints.startControlPoint;
+            let endControlPoint: PointF2D = controlPoints.endControlPoint;
+
+            // transform ControlPoints to original Coordinate System
+            // (rotate back and translate back)
+            startControlPoint = transposeMatrix.vectorMultiplication(startControlPoint);
+            startControlPoint.x += startX;
+            startControlPoint.y += startY;
+            endControlPoint = transposeMatrix.vectorMultiplication(endControlPoint);
+            endControlPoint.x += startX;
+            endControlPoint.y += startY;
+
+            // set private members
+            this.bezierStartPt = new PointF2D(startX, startY + startYOffset);
+            this.bezierStartControlPt = new PointF2D(startControlPoint.x, startControlPoint.y + startYOffset);
+            this.bezierEndControlPt = new PointF2D(endControlPoint.x, endControlPoint.y + endYOffset);
+            this.bezierEndPt = new PointF2D(endX, endY + endYOffset);
+
+            /* for DEBUG only */
+            // this.intersection = transposeMatrix.vectorMultiplication(intersectionPoint);
+            // this.intersection.x += startX;
+            // this.intersection.y += startY;
+            /* for DEBUG only */
+
+            // calculate CurvePoints
+            const length: number = staffLine.BottomLine.length;
+            const startIndex: number = skyBottomLineCalculator.getLeftIndexForPointX(this.bezierStartPt.x, length);
+            const endIndex: number = skyBottomLineCalculator.getLeftIndexForPointX(this.bezierEndPt.x, length);
+            const distance: number = this.bezierEndPt.x - this.bezierStartPt.x;
+            const samplingUnit: number = skyBottomLineCalculator.SamplingUnit;
+            for (let i: number = startIndex; i < endIndex; i++) {
+                // get the right distance ratio and index on the curve
+                const diff: number = i / samplingUnit - this.bezierStartPt.x;
+                const curvePoint: PointF2D = this.calculateCurvePointAtIndex(Math.abs(diff) / distance);
+
+                // update start- and endIndex for better accuracy
+                let index: number = skyBottomLineCalculator.getLeftIndexForPointX(curvePoint.x, length);
+                // update BottomLine with final slur curve:
+                if (index >= startIndex) {
+                    staffLine.BottomLine[index] = Math.max(staffLine.BottomLine[index], curvePoint.y);
+                }
+                index++;
+                if (index < length) {
+                    staffLine.BottomLine[index] = Math.max(staffLine.BottomLine[index], curvePoint.y);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * This method calculates the Start and End Positions of the Slur Curve.
+     * @param slurStartNote
+     * @param slurEndNote
+     * @param staffLine
+     * @param startX
+     * @param startY
+     * @param endX
+     * @param endY
+     * @param rules
+     * @param skyBottomLineCalculator
+     */
+    private calculateStartAndEnd(   slurStartNote: GraphicalNote,
+                                    slurEndNote: GraphicalNote,
+                                    staffLine: StaffLine,
+                                    rules: EngravingRules,
+                                    skyBottomLineCalculator: SkyBottomLineCalculator): {startX: number, startY: number, endX: number, endY: number} {
+        let startX: number = 0;
+        let startY: number = 0;
+        let endX: number = 0;
+        let endY: number = 0;
+
+        if (slurStartNote) {
+            // must be relative to StaffLine
+            startX = slurStartNote.PositionAndShape.RelativePosition.x + slurStartNote.parentVoiceEntry.parentStaffEntry.PositionAndShape.RelativePosition.x
+                                            + slurStartNote.parentVoiceEntry.parentStaffEntry.parentMeasure.PositionAndShape.RelativePosition.x;
+
+            // If Slur starts on a Gracenote
+            if (this.graceStart) {
+                startX += slurStartNote.parentVoiceEntry.parentStaffEntry.staffEntryParent.PositionAndShape.RelativePosition.x;
+            }
+
+            //const first: GraphicalNote = slurStartNote.parentVoiceEntry.notes[0];
+
+            // Determine Start/End Point coordinates with the VoiceEntry of the Start/EndNote of the slur
+            const slurStartVE: GraphicalVoiceEntry = slurStartNote.parentVoiceEntry;
+
+            if (this.placement === PlacementEnum.Above) {
+                startY = slurStartVE.PositionAndShape.RelativePosition.y + slurStartVE.PositionAndShape.BorderTop;
+            } else {
+                startY = slurStartVE.PositionAndShape.RelativePosition.y + slurStartVE.PositionAndShape.BorderBottom;
+            }
+
+            // If the stem points towards the starting point of the slur, shift the slur by a small amount to start (approximately) at the x-position
+            // of the notehead. Note: an exact calculation using the position of the note is too complicate for the payoff
+            if ( slurStartVE.parentVoiceEntry.StemDirection === StemDirectionType.Down && this.placement === PlacementEnum.Below ) {
+                startX -= 0.5;
+            }
+            if (slurStartVE.parentVoiceEntry.StemDirection === StemDirectionType.Up && this.placement === PlacementEnum.Above) {
+                startX += 0.5;
+            }
+            // if (first.NoteStem && first.NoteStem.Direction === StemEnum.StemUp && this.placement === PlacementEnum.Above) {
+            //     startX += first.NoteStem.PositionAndShape.RelativePosition.x;
+            //     startY = skyBottomLineCalculator.getSkyLineMinAtPoint(staffLine, startX);
+            // } else {
+            //     const last: GraphicalNote = <GraphicalNote>slurStartNote[slurEndNote.parentVoiceEntry.notes.length - 1];
+            //     if (last.NoteStem && last.NoteStem.Direction === StemEnum.StemDown && this.placement === PlacementEnum.Below) {
+            //         startX += last.NoteStem.PositionAndShape.RelativePosition.x;
+            //         startY = skyBottomLineCalculator.getBottomLineMaxAtPoint(staffLine, startX);
+            //     } else {
+            //     }
+            // }
+        } else {
+            startX = staffLine.Measures[0].beginInstructionsWidth;
+        }
+
+        if (slurEndNote) {
+            endX = slurEndNote.PositionAndShape.RelativePosition.x + slurEndNote.parentVoiceEntry.parentStaffEntry.PositionAndShape.RelativePosition.x
+                + slurEndNote.parentVoiceEntry.parentStaffEntry.parentMeasure.PositionAndShape.RelativePosition.x;
+
+            // If Slur ends in a Gracenote
+            if (this.graceEnd) {
+                endX += slurEndNote.parentVoiceEntry.parentStaffEntry.staffEntryParent.PositionAndShape.RelativePosition.x;
+            }
+
+            const slurEndVE: GraphicalVoiceEntry = slurEndNote.parentVoiceEntry;
+            if (this.placement === PlacementEnum.Above) {
+                endY = slurEndVE.PositionAndShape.RelativePosition.y + slurEndVE.PositionAndShape.BorderTop;
+            } else {
+                endY = slurEndVE.PositionAndShape.RelativePosition.y + slurEndVE.PositionAndShape.BorderBottom;
+            }
+
+            // If the stem points towards the endpoint of the slur, shift the slur by a small amount to start (approximately) at the x-position
+            // of the notehead. Note: an exact calculation using the position of the note is too complicate for the payoff
+            if ( slurEndVE.parentVoiceEntry.StemDirection === StemDirectionType.Down && this.placement === PlacementEnum.Below ) {
+                endX -= 0.5;
+            }
+            if (slurEndVE.parentVoiceEntry.StemDirection === StemDirectionType.Up && this.placement === PlacementEnum.Above) {
+                endX += 0.5;
+            }
+            // const first: GraphicalNote = <GraphicalNote>slurEndNote.parentVoiceEntry.notes[0];
+            // if (first.NoteStem && first.NoteStem.Direction === StemEnum.StemUp && this.placement === PlacementEnum.Above) {
+            //     endX += first.NoteStem.PositionAndShape.RelativePosition.x;
+            //     endY = skyBottomLineCalculator.getSkyLineMinAtPoint(staffLine, endX);
+            // } else {
+            //     const last: GraphicalNote = <GraphicalNote>slurEndNote.parentVoiceEntry.notes[slurEndNote.parentVoiceEntry.notes.length - 1];
+            //     if (last.NoteStem && last.NoteStem.Direction === StemEnum.StemDown && this.placement === PlacementEnum.Below) {
+            //         endX += last.NoteStem.PositionAndShape.RelativePosition.x;
+            //         endY = skyBottomLineCalculator.getBottomLineMaxAtPoint(staffLine, endX);
+            //     } else {
+            //         if (this.placement === PlacementEnum.Above) {
+            //             const highestNote: GraphicalNote = last;
+            //             endY = highestNote.PositionAndShape.RelativePosition.y;
+            //             if (highestNote.NoteHead) {
+            //                 endY += highestNote.NoteHead.PositionAndShape.BorderMarginTop;
+            //             } else { endY += highestNote.PositionAndShape.BorderTop; }
+            //         } else {
+            //             const lowestNote: GraphicalNote = first;
+            //             endY = lowestNote.parentVoiceEntry
+            //             lowestNote.PositionAndShape.RelativePosition.y;
+            //             if (lowestNote.NoteHead) {
+            //                 endY += lowestNote.NoteHead.PositionAndShape.BorderMarginBottom;
+            //             } else { endY += lowestNote.PositionAndShape.BorderBottom; }
+            //         }
+            //     }
+            // }
+        } else {
+            endX = staffLine.PositionAndShape.Size.width;
+        }
+
+        // if GraphicalSlur breaks over System, then the end/start of the curve is at the corresponding height with the known start/end
+        if (!slurStartNote && !slurEndNote) {
+            startY = 0;
+            endY = 0;
+        }
+        if (!slurStartNote) {
+            startY = endY;
+        }
+        if (!slurEndNote) {
+            endY = startY;
+        }
+
+        // if two slurs start/end at the same GraphicalNote, then the second gets an offset
+        if (this.slur.startNoteHasMoreStartingSlurs() && this.slur.isSlurLonger()) {
+            if (this.placement === PlacementEnum.Above) {
+                startY -= rules.SlursStartingAtSameStaffEntryYOffset;
+            } else { startY += rules.SlursStartingAtSameStaffEntryYOffset; }
+        }
+        if (this.slur.endNoteHasMoreEndingSlurs() && this.slur.isSlurLonger()) {
+            if (this.placement === PlacementEnum.Above) {
+                endY -= rules.SlursStartingAtSameStaffEntryYOffset;
+            } else { endY += rules.SlursStartingAtSameStaffEntryYOffset; }
+        }
+
+        if (this.placement === PlacementEnum.Above) {
+            startY = Math.min(startY, 1.5);
+            endY = Math.min(endY, 1.5);
+        } else {
+            startY = Math.max(startY, staffLine.StaffHeight - 1.5);
+            endY = Math.max(endY, staffLine.StaffHeight - 1.5);
+        }
+
+        return {startX, startY, endX, endY};
+    }
+
+    /**
+     * This method calculates the placement of the Curve.
+     * @param skyBottomLineCalculator
+     * @param staffLine
+     */
+    private calculatePlacement(skyBottomLineCalculator: SkyBottomLineCalculator, staffLine: StaffLine): void {
+        // old version: when lyrics are given place above:
+        // if ( !this.slur.StartNote.ParentVoiceEntry.LyricsEntries.isEmpty || (this.slur.EndNote
+        //                                     && !this.slur.EndNote.ParentVoiceEntry.LyricsEntries.isEmpty) ) {
+        //     this.placement = PlacementEnum.Above;
+        //     return;
+        // }
+
+        if (this.rules.SlurPlacementFromXML) {
+            this.placement = this.slur.PlacementXml;
+            return;
+        }
+
+        // if any StaffEntry belongs to a Measure with multiple Voices, than
+        // if Slur's Start- or End-Note belongs to a LinkedVoice Below else Above
+        for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            if (graphicalStaffEntry.parentMeasure.hasMultipleVoices()) {
+                if (this.slur.StartNote.ParentVoiceEntry.ParentVoice instanceof LinkedVoice ||
+                    this.slur.EndNote.ParentVoiceEntry.ParentVoice instanceof LinkedVoice) {
+                    this.placement = PlacementEnum.Below;
+                } else { this.placement = PlacementEnum.Above; }
+                return;
+            }
+        }
+
+        // when lyrics are given place above:
+        for (let idx: number = 0, len: number = this.staffEntries.length; idx < len; ++idx) {
+            const graphicalStaffEntry: GraphicalStaffEntry = this.staffEntries[idx];
+            if (graphicalStaffEntry.LyricsEntries.length > 0) {
+                this.placement = PlacementEnum.Above;
+                return;
+            }
+        }
+        const startStaffEntry: GraphicalStaffEntry = this.staffEntries[0];
+        const endStaffEntry: GraphicalStaffEntry = this.staffEntries[this.staffEntries.length - 1];
+
+        // single Voice, opposite to StemDirection
+        // here should only be one voiceEntry, so we can take graphicalVoiceEntries[0]:
+        const startStemDirection: StemDirectionType = startStaffEntry.graphicalVoiceEntries[0].parentVoiceEntry.StemDirection;
+        const endStemDirection: StemDirectionType = endStaffEntry.graphicalVoiceEntries[0].parentVoiceEntry.StemDirection;
+        if (startStemDirection  ===
+            endStemDirection) {
+            this.placement = (startStemDirection === StemDirectionType.Up) ? PlacementEnum.Below : PlacementEnum.Above;
+        } else {
+            // Placement at the side with the minimum border
+            let sX: number = startStaffEntry.PositionAndShape.BorderLeft + startStaffEntry.PositionAndShape.RelativePosition.x
+                        + startStaffEntry.parentMeasure.PositionAndShape.RelativePosition.x;
+            let eX: number = endStaffEntry.PositionAndShape.BorderRight + endStaffEntry.PositionAndShape.RelativePosition.x
+                        + endStaffEntry.parentMeasure.PositionAndShape.RelativePosition.x;
+
+            if (this.graceStart) {
+                sX += endStaffEntry.PositionAndShape.RelativePosition.x;
+            }
+            if (this.graceEnd) {
+                eX += endStaffEntry.staffEntryParent.PositionAndShape.RelativePosition.x;
+            }
+
+            // get SkyBottomLine borders
+            const minAbove: number = skyBottomLineCalculator.getSkyLineMinInRange(sX, eX) * -1;
+            const maxBelow: number = skyBottomLineCalculator.getBottomLineMaxInRange(sX, eX) - staffLine.StaffHeight;
+
+            if (maxBelow > minAbove) {
+                this.placement = PlacementEnum.Above;
+            } else { this.placement = PlacementEnum.Below; }
+        }
+    }
+
+    /**
+     * This method calculates the Points between Start- and EndPoint (case above).
+     * @param start
+     * @param end
+     * @param staffLine
+     * @param skyBottomLineCalculator
+     */
+    private calculateTopPoints(start: PointF2D, end: PointF2D, staffLine: StaffLine, skyBottomLineCalculator: SkyBottomLineCalculator): PointF2D[] {
+        const points: PointF2D[] = [];
+        let startIndex: number = skyBottomLineCalculator.getRightIndexForPointX(start.x, staffLine.SkyLine.length);
+        let endIndex: number = skyBottomLineCalculator.getLeftIndexForPointX(end.x, staffLine.SkyLine.length);
+
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        if (endIndex >= staffLine.SkyLine.length) {
+            endIndex = staffLine.SkyLine.length - 1;
+        }
+
+        for (let i: number = startIndex; i < endIndex; i++) {
+            const skylineValue: number = staffLine.SkyLine[i];
+            // ignore default value (= 0) which is upper border of staffline
+            if (skylineValue !== 0) {
+                const point: PointF2D = new PointF2D((0.5 + i) / skyBottomLineCalculator.SamplingUnit, skylineValue);
+                points.push(point);
+            }
+        }
+
+        return points;
+    }
+
+    /**
+     * This method calculates the Points between Start- and EndPoint (case below).
+     * @param start
+     * @param end
+     * @param staffLine
+     * @param skyBottomLineCalculator
+     */
+    private calculateBottomPoints(start: PointF2D, end: PointF2D, staffLine: StaffLine, skyBottomLineCalculator: SkyBottomLineCalculator): PointF2D[] {
+        const points: PointF2D[] = [];
+
+        // get BottomLine indices
+        let startIndex: number = skyBottomLineCalculator.getRightIndexForPointX(start.x, staffLine.BottomLine.length);
+        let endIndex: number = skyBottomLineCalculator.getLeftIndexForPointX(end.x, staffLine.BottomLine.length);
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+        if (endIndex >= staffLine.BottomLine.length) {
+            endIndex = staffLine.BottomLine.length - 1;
+        }
+
+        for (let i: number = startIndex; i < endIndex; i++) {
+            const bottomLineValue: number = staffLine.BottomLine[i];
+
+            // ignore default value (= 4) which is lower border of staffline
+            if (bottomLineValue !== 0) {
+                const point: PointF2D = new PointF2D((0.5 + i) / skyBottomLineCalculator.SamplingUnit, bottomLineValue);
+                points.push(point);
+            }
+        }
+
+        return points;
+    }
+
+    /**
+     * This method calculates the maximum slope between StartPoint and BetweenPoints.
+     * @param points
+     * @param start
+     * @param end
+     */
+    private calculateMaxLeftSlope(points: PointF2D[], start: PointF2D, end: PointF2D): number {
+        let slope: number = -Number.MAX_VALUE;
+        const x: number = start.x;
+        const y: number = start.y;
+
+        for (let i: number = 0; i < points.length; i++) {
+            if (Math.abs(points[i].y - Number.MAX_VALUE) < 0.0001 || Math.abs(points[i].y - (-Number.MAX_VALUE)) < 0.0001) {
+                continue;
+            }
+            slope = Math.max(slope, (points[i].y - y) / (points[i].x - x));
+        }
+
+        // in case all Points don't have a meaningful value or the slope between Start- and EndPoint is just bigger
+        slope = Math.max(slope, Math.abs(end.y - y) / (end.x - x));
+        //limit to 80 degrees
+        slope = Math.min(slope, 5.6713);
+
+        return slope;
+    }
+
+    /**
+     * This method calculates the maximum slope between EndPoint and BetweenPoints.
+     * @param points
+     * @param start
+     * @param end
+     */
+    private calculateMaxRightSlope(points: PointF2D[], start: PointF2D, end: PointF2D): number {
+        let slope: number = Number.MAX_VALUE;
+        const x: number = end.x;
+        const y: number = end.y;
+
+        for (let i: number = 0; i < points.length; i++) {
+            if (Math.abs(points[i].y - Number.MAX_VALUE) < 0.0001 || Math.abs(points[i].y - (-Number.MAX_VALUE)) < 0.0001) {
+                continue;
+            }
+            slope = Math.min(slope, (y - points[i].y) / (x - points[i].x));
+        }
+
+        // in case no Point has a meaningful value or the slope between Start- and EndPoint is just smaller
+        slope = Math.min(slope, (y - start.y) / (x - start.x));
+        //limit to 80 degrees
+        slope = Math.max(slope, -5.6713);
+
+        return slope;
+    }
+
+    /**
+     * This method returns the maximum (meaningful) points.Y.
+     * @param points
+     */
+    private getPointListMaxY(points: PointF2D[]): number {
+        let max: number = -Number.MAX_VALUE;
+
+        for (let idx: number = 0, len: number = points.length; idx < len; ++idx) {
+            const point: PointF2D = points[idx];
+            if (Math.abs(point.y - (-Number.MAX_VALUE)) < 0.0001 || Math.abs(point.y - Number.MAX_VALUE) < 0.0001) {
+                continue;
+            }
+            max = Math.max(max, point.y);
+        }
+
+        return max;
+    }
+
+    /**
+     * This method calculates the translated and rotated PointsList (case above).
+     * @param points
+     * @param startX
+     * @param startY
+     * @param rotationMatrix
+     */
+    private calculateTranslatedAndRotatedPointListAbove(points: PointF2D[], startX: number, startY: number, rotationMatrix: Matrix2D): PointF2D[] {
+        const transformedPoints: PointF2D[] = [];
+        for (let i: number = 0; i < points.length; i++) {
+            if (Math.abs(points[i].y - Number.MAX_VALUE) < 0.0001 || Math.abs(points[i].y - (-Number.MAX_VALUE)) < 0.0001) {
+                continue;
+            }
+
+            let point: PointF2D = new PointF2D(points[i].x - startX, -(points[i].y - startY));
+            point = rotationMatrix.vectorMultiplication(point);
+            transformedPoints.push(point);
+        }
+
+        return transformedPoints;
+    }
+
+    /**
+     * This method calculates the translated and rotated PointsList (case below).
+     * @param points
+     * @param startX
+     * @param startY
+     * @param rotationMatrix
+     */
+    private calculateTranslatedAndRotatedPointListBelow(points: PointF2D[], startX: number, startY: number, rotationMatrix: Matrix2D): PointF2D[] {
+        const transformedPoints: PointF2D[] = [];
+        for (let i: number = 0; i < points.length; i++) {
+            if (Math.abs(points[i].y - Number.MAX_VALUE) < 0.0001 || Math.abs(points[i].y - (-Number.MAX_VALUE)) < 0.0001) {
+                continue;
+            }
+            let point: PointF2D = new PointF2D(points[i].x - startX, points[i].y - startY);
+            point = rotationMatrix.vectorMultiplication(point);
+            transformedPoints.push(point);
+        }
+
+        return transformedPoints;
+    }
+
+    /**
+     * This method calculates the HeightWidthRatio between the MaxYpoint (from the points between StartPoint and EndPoint)
+     * and the X-distance from StartPoint to EndPoint.
+     * @param endX
+     * @param points
+     */
+    private calculateHeightWidthRatio(endX: number, points: PointF2D[]): number {
+        if (points.length === 0) {
+            return 0;
+        }
+
+        // in case of negative points
+        const max: number = Math.max(0, this.getPointListMaxY(points));
+
+        return max / endX;
+    }
+
+    /**
+     * This method calculates the 2 ControlPoints of the SlurCurve.
+     * @param endX
+     * @param startAngle
+     * @param endAngle
+     * @param points
+     */
+    private calculateControlPoints(endX: number, startAngle: number, endAngle: number,
+                                   points: PointF2D[], heightWidthRatio: number): { startControlPoint: PointF2D, endControlPoint: PointF2D } {
+        // calculate HeightWidthRatio between the MaxYpoint (from the points between StartPoint and EndPoint)
+        // and the X-distance from StartPoint to EndPoint
+        // use this HeightWidthRatio to get a "normalized" Factor (based on tested parameters)
+        // this Factor denotes the Length of the TangentLine of the Curve (a proportion of the X-distance from StartPoint to EndPoint)
+        // finally from this Length and the calculated Angles we get the coordinates of the Control Points
+        const factorStart: number = Math.min(0.5, Math.max(0.1, 1.7 * (startAngle / 80) * Math.pow(Math.max(heightWidthRatio, 0.05), 0.4)));
+        const factorEnd: number = Math.min(0.5, Math.max(0.1, 1.7 * (-endAngle / 80) * Math.pow(Math.max(heightWidthRatio, 0.05), 0.4)));
+
+        const startControlPoint: PointF2D = new PointF2D();
+        startControlPoint.x = endX * factorStart * Math.cos(startAngle * GraphicalSlur.degreesToRadiansFactor);
+        startControlPoint.y = endX * factorStart * Math.sin(startAngle * GraphicalSlur.degreesToRadiansFactor);
+
+        const endControlPoint: PointF2D = new PointF2D();
+        endControlPoint.x = endX - (endX * factorEnd * Math.cos(endAngle * GraphicalSlur.degreesToRadiansFactor));
+        endControlPoint.y = -(endX * factorEnd * Math.sin(endAngle * GraphicalSlur.degreesToRadiansFactor));
+        return {startControlPoint: startControlPoint, endControlPoint: endControlPoint};
+    }
+
+    /**
+     * This method calculates the angles for the Curve's Tangent Lines.
+     * @param leftAngle
+     * @param rightAngle
+     * @param startLineSlope
+     * @param endLineSlope
+     * @param maxAngle
+     */
+    private calculateAngles(minAngle: number, startLineSlope: number, endLineSlope: number, maxAngle: number):
+    {startAngle: number, endAngle: number} {
+        // calculate Angles from the calculated Slopes, adding also a given angle
+        const angle: number = 20;
+
+        let calculatedStartAngle: number = Math.atan(startLineSlope) / GraphicalSlur.degreesToRadiansFactor;
+        if (startLineSlope > 0) {
+            calculatedStartAngle += angle;
+        } else {
+            calculatedStartAngle -= angle;
+        }
+
+        let calculatedEndAngle: number = Math.atan(endLineSlope) / GraphicalSlur.degreesToRadiansFactor;
+        if (endLineSlope < 0) {
+            calculatedEndAngle -= angle;
+        } else {
+            calculatedEndAngle += angle;
+        }
+
+        // +/- 80 is the max/min allowed Angle
+        const leftAngle: number = Math.min(Math.max(minAngle, calculatedStartAngle), maxAngle);
+        const rightAngle: number = Math.max(Math.min(-minAngle, calculatedEndAngle), -maxAngle);
+        return {"startAngle": leftAngle, "endAngle": rightAngle};
+    }
+
+    private static degreesToRadiansFactor: number = Math.PI / 180;
+}

+ 313 - 0
src/MusicalScore/Graphical/GraphicalStaffEntry.ts

@@ -0,0 +1,313 @@
+import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
+import {BoundingBox} from "./BoundingBox";
+import {Fraction} from "../../Common/DataObjects/Fraction";
+import {VerticalGraphicalStaffEntryContainer} from "./VerticalGraphicalStaffEntryContainer";
+import {Note} from "../VoiceData/Note";
+import {Slur} from "../VoiceData/Expressions/ContinuousExpressions/Slur";
+import {Voice} from "../VoiceData/Voice";
+import {VoiceEntry} from "../VoiceData/VoiceEntry";
+import {GraphicalTie} from "./GraphicalTie";
+import {GraphicalObject} from "./GraphicalObject";
+import {GraphicalMeasure} from "./GraphicalMeasure";
+import {GraphicalNote} from "./GraphicalNote";
+import {GraphicalChordSymbolContainer} from "./GraphicalChordSymbolContainer";
+import {GraphicalLyricEntry} from "./GraphicalLyricEntry";
+import {AbstractGraphicalInstruction} from "./AbstractGraphicalInstruction";
+import {GraphicalStaffEntryLink} from "./GraphicalStaffEntryLink";
+import {CollectionUtil} from "../../Util/CollectionUtil";
+import { GraphicalVoiceEntry } from "./GraphicalVoiceEntry";
+import { MusicSheetCalculator } from "./MusicSheetCalculator";
+
+/**
+ * The graphical counterpart of a [[SourceStaffEntry]].
+ */
+export abstract class GraphicalStaffEntry extends GraphicalObject {
+    constructor(parentMeasure: GraphicalMeasure, sourceStaffEntry: SourceStaffEntry = undefined, staffEntryParent: GraphicalStaffEntry = undefined) {
+        super();
+        this.parentMeasure = parentMeasure;
+        this.graphicalVoiceEntries = [];
+        this.sourceStaffEntry = sourceStaffEntry;
+        if (staffEntryParent) {
+            this.staffEntryParent = staffEntryParent;
+            this.parentVerticalContainer = staffEntryParent.parentVerticalContainer;
+            this.PositionAndShape = new BoundingBox(this, staffEntryParent.PositionAndShape);
+        } else {
+            this.PositionAndShape = new BoundingBox(this, parentMeasure.PositionAndShape);
+        }
+        if (sourceStaffEntry) {
+            this.relInMeasureTimestamp = sourceStaffEntry.Timestamp;
+        }
+    }
+
+    public graphicalChordContainers: GraphicalChordSymbolContainer[] = [];
+    public graphicalLink: GraphicalStaffEntryLink;
+
+    // Extra member needed, as tie notes have no direct source entry with the right time stamp.
+    public relInMeasureTimestamp: Fraction;
+    public sourceStaffEntry: SourceStaffEntry;
+    public parentMeasure: GraphicalMeasure;
+    public graphicalVoiceEntries: GraphicalVoiceEntry[];
+    public staffEntryParent: GraphicalStaffEntry;
+    public parentVerticalContainer: VerticalGraphicalStaffEntryContainer;
+    public tabStaffEntry: GraphicalStaffEntry = undefined;
+    public MaxAccidentals: number = 0;
+
+    private graphicalInstructions: AbstractGraphicalInstruction[] = [];
+    private graphicalTies: GraphicalTie[] = [];
+    private lyricsEntries: GraphicalLyricEntry[] = [];
+
+    public get GraphicalInstructions(): AbstractGraphicalInstruction[] {
+        return this.graphicalInstructions;
+    }
+
+    public get GraphicalTies(): GraphicalTie[] {
+        return this.graphicalTies;
+    }
+
+    public get LyricsEntries(): GraphicalLyricEntry[] {
+        return this.lyricsEntries;
+    }
+
+    public set LyricsEntries(value: GraphicalLyricEntry[]) {
+        this.lyricsEntries = value;
+    }
+
+    /**
+     * Calculate the absolute Timestamp.
+     * @returns {Fraction}
+     */
+    public getAbsoluteTimestamp(): Fraction {
+        const result: Fraction = this.parentMeasure.parentSourceMeasure.AbsoluteTimestamp.clone();
+        if (this.relInMeasureTimestamp) {
+            result.Add(this.relInMeasureTimestamp);
+        }
+        return result;
+    }
+
+    /**
+     * Search through all the GraphicalNotes to find the suitable one for a TieEndNote.
+     * @param tieNote
+     * @returns {any}
+     */
+    public findTieGraphicalNoteFromNote(tieNote: Note): GraphicalNote {
+        for (const gve of this.graphicalVoiceEntries) {
+            for (const graphicalNote of gve.notes) {
+                const note: Note = graphicalNote.sourceNote;
+                if (!note.isRest()
+                    && note.Pitch.FundamentalNote === tieNote.Pitch.FundamentalNote
+                    && note.Pitch.Octave === tieNote.Pitch.Octave
+                    && note.getAbsoluteTimestamp().Equals(tieNote.getAbsoluteTimestamp())) {
+                    return graphicalNote;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * Search through all [[GraphicalNote]]s to find the suitable one for an StartSlurNote (that 's also an EndTieNote).
+     * @param tieNote
+     * @param slur
+     * @returns {any}
+     */
+    public findEndTieGraphicalNoteFromNoteWithStartingSlur(tieNote: Note, slur: Slur): GraphicalNote {
+        if (!tieNote) {
+            return undefined;
+        }
+        for (const gve of this.graphicalVoiceEntries) {
+            if (gve.parentVoiceEntry !== tieNote.ParentVoiceEntry) {
+                continue;
+            }
+            for (const graphicalNote of gve.notes) {
+                const note: Note = graphicalNote.sourceNote;
+                if (note.NoteTie && note.NoteSlurs.indexOf(slur) !== -1) {
+                    return graphicalNote;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    public findGraphicalNoteFromGraceNote(graceNote: Note): GraphicalNote {
+        if (!graceNote) {
+            return undefined;
+        }
+        for (const gve of this.graphicalVoiceEntries) {
+            if (gve.parentVoiceEntry !== graceNote.ParentVoiceEntry) {
+                continue;
+            }
+            for (const graphicalNote of gve.notes) {
+                if (graphicalNote.sourceNote === graceNote) {
+                    return graphicalNote;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    public findGraphicalNoteFromNote(note: Note): GraphicalNote {
+        if (!note) {
+            return undefined;
+        }
+        for (const gve of this.graphicalVoiceEntries) {
+            if (gve.parentVoiceEntry !== note.ParentVoiceEntry) {
+                continue;
+            }
+            for (const graphicalNote of gve.notes) {
+                if (graphicalNote.sourceNote === note && this.getAbsoluteTimestamp().Equals(note.getAbsoluteTimestamp())) {
+                    return graphicalNote;
+                }
+            }
+        }
+        return undefined;
+    }
+
+    public getGraphicalNoteDurationFromVoice(voice: Voice): Fraction {
+        for (const gve of this.graphicalVoiceEntries) {
+            if (gve.parentVoiceEntry.ParentVoice !== voice) {
+                continue;
+            }
+            return gve.notes[0].graphicalNoteLength;
+        }
+        return new Fraction(0, 1);
+    }
+
+    /**
+     * Find the [[StaffEntry]]'s [[GraphicalNote]]s that correspond to the given [[VoiceEntry]]'s [[Note]]s.
+     * @param voiceEntry
+     * @returns {any}
+     */
+    public findVoiceEntryGraphicalNotes(voiceEntry: VoiceEntry): GraphicalNote[] {
+        for (const gve of this.graphicalVoiceEntries) {
+            if (gve.parentVoiceEntry === voiceEntry) {
+                return gve.notes;
+            }
+        }
+        return undefined;
+    }
+
+    /**
+     * Check if the given [[VoiceEntry]] is part of the [[StaffEntry]]'s Linked [[VoiceEntry]].
+     * @param voiceEntry
+     * @returns {boolean}
+     */
+    public isVoiceEntryPartOfLinkedVoiceEntry(voiceEntry: VoiceEntry): boolean {
+        if (this.sourceStaffEntry.Link) {
+            for (let idx: number = 0, len: number = this.sourceStaffEntry.Link.LinkStaffEntries.length; idx < len; ++idx) {
+                const sEntry: SourceStaffEntry = this.sourceStaffEntry.Link.LinkStaffEntries[idx];
+                if (sEntry.VoiceEntries.indexOf(voiceEntry) !== -1 && sEntry !== this.sourceStaffEntry) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return the [[StaffEntry]]'s Minimum NoteLength.
+     * @returns {Fraction}
+     */
+    public findStaffEntryMinNoteLength(): Fraction {
+        let minLength: Fraction = new Fraction(Number.MAX_VALUE, 1);
+        for (const gve of this.graphicalVoiceEntries) {
+            for (const graphicalNote of gve.notes) {
+                const calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
+                if (calNoteLen.lt(minLength) && calNoteLen.GetExpandedNumerator() > 0) {
+                    minLength = calNoteLen;
+                }
+            }
+        }
+        return minLength;
+    }
+
+    public findStaffEntryMaxNoteLength(): Fraction {
+        let maxLength: Fraction = new Fraction(0, 1);
+        for (const gve of this.graphicalVoiceEntries) {
+            for (const graphicalNote of gve.notes) {
+                const calNoteLen: Fraction = graphicalNote.graphicalNoteLength;
+                if (maxLength.lt(calNoteLen)  && calNoteLen.GetExpandedNumerator() > 0) {
+                    maxLength = calNoteLen;
+                }
+            }
+        }
+        return maxLength;
+    }
+
+    /**
+     * Find or creates the list of [[GraphicalNote]]s in case of a [[VoiceEntry]] (not from TiedNote).
+     * @param voiceEntry
+     * @returns {GraphicalNote[]}
+     */
+    public findOrCreateGraphicalVoiceEntry(voiceEntry: VoiceEntry): GraphicalVoiceEntry {
+        for (const gve of this.graphicalVoiceEntries) {
+            if (gve.parentVoiceEntry === voiceEntry) {
+                return gve;
+            }
+        }
+        // if not found in list, create new one and add to list:
+        const graphicalVoiceEntry: GraphicalVoiceEntry = MusicSheetCalculator.symbolFactory.createVoiceEntry(voiceEntry, this);
+        this.graphicalVoiceEntries.push(graphicalVoiceEntry);
+
+        return graphicalVoiceEntry;
+    }
+
+    /**
+     * Find or creates the list of [[GraphicalNote]]s in case of a TiedNote.
+     * @param graphicalNote
+     * @returns {GraphicalNote[]}
+     */
+    public findOrCreateGraphicalVoiceEntryFromGraphicalNote(graphicalNote: GraphicalNote): GraphicalVoiceEntry {
+        for (const gve of this.graphicalVoiceEntries) {
+            if (gve === graphicalNote.parentVoiceEntry) {
+                return gve;
+            }
+        }
+        // if not found in list, create new one and add to list:
+        const graphicalVoiceEntry: GraphicalVoiceEntry = MusicSheetCalculator.symbolFactory.createVoiceEntry(graphicalNote.sourceNote.ParentVoiceEntry, this);
+        this.graphicalVoiceEntries.push(graphicalVoiceEntry);
+
+        return graphicalVoiceEntry;
+    }
+
+    /**
+     * Insert the [[GraphicalNote]] to the correct index of the [[GraphicalNote]]s list,
+     * so that the order of the [[GraphicalNote]]'s in the list corresponds to the [[VoiceEntry]]'s [[Note]]s order.
+     * (needed when adding Tie-EndNotes).
+     * @param graphicalNotes
+     * @param graphicalNote
+     */
+    public addGraphicalNoteToListAtCorrectYPosition(gve: GraphicalVoiceEntry, graphicalNote: GraphicalNote): void {
+        const graphicalNotes: GraphicalNote[] = gve.notes;
+        if (graphicalNotes.length === 0 ||
+            graphicalNote.PositionAndShape.RelativePosition.y < CollectionUtil.last(graphicalNotes).PositionAndShape.RelativePosition.y) {
+            graphicalNotes.push(graphicalNote);
+        } else {
+            for (let i: number = graphicalNotes.length - 1; i >= 0; i--) {
+                if (graphicalNotes[i].PositionAndShape.RelativePosition.y > graphicalNote.PositionAndShape.RelativePosition.y) {
+                    graphicalNotes.splice(i + 1, 0, graphicalNote);
+                    break;
+                }
+                if (i === 0) {
+                    graphicalNotes.splice(0, 0, graphicalNote);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns true if this staff entry has only rests
+     */
+    public hasOnlyRests(): boolean {
+        const hasOnlyRests: boolean = true;
+        for (const gve of this.graphicalVoiceEntries) {
+            for (const graphicalNote of gve.notes) {
+                const note: Note = graphicalNote.sourceNote;
+                if (!note.isRest()) {
+                    return false;
+                }
+            }
+        }
+        return hasOnlyRests;
+    }
+}

Some files were not shown because too many files changed in this diff