瀏覽代碼

merge osmd-public/develop (0.9.5)

sschmid 4 年之前
父節點
當前提交
cac5afa9b3

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "opensheetmusicdisplay-private",
-  "version": "0.9.3",
+  "version": "0.9.5",
   "description": "Private OSMD mirror/audio player.",
   "main": "build/opensheetmusicdisplay.min.js",
   "typings": "build/dist/src/",

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

@@ -182,6 +182,11 @@ export class EngravingRules {
     public SlurSlopeMaxAngle: number;
     public SlurTangentMinAngle: number;
     public SlurTangentMaxAngle: number;
+    public SlurHeightFactor: number;
+    public SlurHeightFlattenLongSlursFactorByWidth: number;
+    public SlurHeightFlattenLongSlursFactorByAngle: number;
+    public SlurHeightFlattenLongSlursCutoffAngle: number;
+    public SlurHeightFlattenLongSlursCutoffWidth: number;
     public SlursStartingAtSameStaffEntryYOffset: number;
     public InstantaneousTempoTextHeight: number;
     public ContinuousDynamicTextHeight: number;
@@ -473,6 +478,11 @@ export class EngravingRules {
         this.SlurSlopeMaxAngle = 15.0;
         this.SlurTangentMinAngle = 30.0;
         this.SlurTangentMaxAngle = 80.0;
+        this.SlurHeightFactor = 1; // 1 = 100% (standard height). 2 = 100% flattening of all slurs.
+        this.SlurHeightFlattenLongSlursFactorByWidth = 0.24; // additional flattening for long slurs the longer they are.
+        this.SlurHeightFlattenLongSlursFactorByAngle = 0.36; // when one of these factors is high, increasing the other has a very strong effect.
+        this.SlurHeightFlattenLongSlursCutoffAngle = 47;
+        this.SlurHeightFlattenLongSlursCutoffWidth = 16; // 15 ~ slur between measure's first notes in 4/4. 14 -> problem with test_slurs_highNotes
         this.SlursStartingAtSameStaffEntryYOffset = 0.8;
 
         // Repetitions

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

@@ -23,7 +23,7 @@ import {SelectionStartSymbol} from "./SelectionStartSymbol";
 import {SelectionEndSymbol} from "./SelectionEndSymbol";
 import {OutlineAndFillStyleEnum} from "./DrawingEnums";
 import { Clickable } from "./Clickable";
-import { StaffLine } from ".";
+import { StaffLine } from "./StaffLine";
 import { MusicSheetDrawer } from "./MusicSheetDrawer";
 import { GraphicalVoiceEntry } from "./GraphicalVoiceEntry";
 import { GraphicalObject } from "./GraphicalObject";

+ 30 - 3
src/MusicalScore/Graphical/GraphicalSlur.ts

@@ -233,6 +233,8 @@ export class GraphicalSlur extends GraphicalCurve {
             endControlPoint = transposeMatrix.vectorMultiplication(endControlPoint);
             endControlPoint.x += startX;
             endControlPoint.y = -endControlPoint.y + startY;
+            // middleControlPoint.x = (startControlPoint.x + endControlPoint.x) / 2;
+            // middleControlPoint.y = (startControlPoint.y + endControlPoint.y) / 2 + 1.0;
 
             /* for DEBUG only */
             // this.intersection = transposeMatrix.vectorMultiplication(intersectionPoint);
@@ -868,14 +870,39 @@ export class GraphicalSlur extends GraphicalCurve {
      * @param points
      */
     private calculateControlPoints(endX: number, startAngle: number, endAngle: number,
-                                   points: PointF2D[], heightWidthRatio: number): { startControlPoint: PointF2D, endControlPoint: PointF2D } {
+                                   points: PointF2D[], heightWidthRatio: number
+    ): { startControlPoint: PointF2D, endControlPoint: PointF2D } {
+        let heightFactor: number = this.rules.SlurHeightFactor;
+        let widthFlattenFactor: number = 1;
+        const cutoffAngle: number = this.rules.SlurHeightFlattenLongSlursCutoffAngle;
+        const cutoffWidth: number = this.rules.SlurHeightFlattenLongSlursCutoffWidth;
+        // console.log("width: " + endX);
+        if (startAngle > cutoffAngle && endX > cutoffWidth) { // steep and wide slurs
+            // console.log("steep angle: " + startAngle);
+            widthFlattenFactor += endX / 70 * this.rules.SlurHeightFlattenLongSlursFactorByWidth; // double flattening for width = 70, factorByWidth = 1
+            widthFlattenFactor *= 1 + (startAngle / 30 * this.rules.SlurHeightFlattenLongSlursFactorByAngle); // flatten more for higher angles.
+            // TODO use sin or cos instead of startAngle directly
+            heightFactor /= widthFlattenFactor; // flatten long slurs more
+        }
+        // TODO also offer a widthFlattenFactor for smaller slurs?
+
+        // debug:
+        // const measureNumber: number = this.staffEntries[0].parentMeasure.MeasureNumber; // debug
+        // if (measureNumber === 10) {
+        //     console.log("endX: " + endX);
+        //     console.log("widthFlattenFactor: " + widthFlattenFactor);
+        //     console.log("heightFactor: " + heightFactor);
+        //     console.log("startAngle: " + startAngle);
+        //     console.log("heightWidthRatio: " + heightWidthRatio);
+        // }
+
         // 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 factorStart: number = Math.min(0.5, Math.max(0.1, 1.7 * startAngle / 80 * heightFactor * Math.pow(Math.max(heightWidthRatio, 0.05), 0.4)));
+        const factorEnd: number = Math.min(0.5, Math.max(0.1, 1.7 * (-endAngle) / 80 * heightFactor * Math.pow(Math.max(heightWidthRatio, 0.05), 0.4)));
 
         const startControlPoint: PointF2D = new PointF2D();
         startControlPoint.x = endX * factorStart * Math.cos(startAngle * GraphicalSlur.degreesToRadiansFactor);

+ 1 - 0
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -197,6 +197,7 @@ export abstract class MusicSheetCalculator {
             //go through all source measures again. Need to calc auto-multi-rests
             for (let idx: number = 0, len: number = musicSheet.SourceMeasures.length; idx < len; ++idx) {
                 const sourceMeasure: SourceMeasure = musicSheet.SourceMeasures[idx];
+                // console.log(sourceMeasure.MeasureNumber + " can be reduced: " + sourceMeasure.canBeReducedToMultiRest());
                 if (!sourceMeasure.isReducedToMultiRest && sourceMeasure.canBeReducedToMultiRest()) {
                     //we've already been initialized, we are in the midst of a multirest sequence
                     if (multiRestCount > 0) {

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

@@ -145,13 +145,13 @@ export abstract class MusicSheetDrawer {
 
     public abstract calculatePixelDistance(unitDistance: number): number;
 
-    public drawLabel(graphicalLabel: GraphicalLabel, layer: number): Node[] {
+    public drawLabel(graphicalLabel: GraphicalLabel, layer: number): Node {
         if (!this.isVisible(graphicalLabel.PositionAndShape)) {
-            return [];
+            return undefined;
         }
         const label: Label = graphicalLabel.Label;
         if (label.text.trim() === "") {
-            return [];
+            return undefined;
         }
         const calcResults: LabelRenderSpecs = this.calculateLabel(graphicalLabel);
 
@@ -240,7 +240,7 @@ export abstract class MusicSheetDrawer {
         // empty
     }
 
-    protected renderLabel(graphicalLabel: GraphicalLabel, layer: GraphicalLayers, specs: LabelRenderSpecs): Node[] {
+    protected renderLabel(graphicalLabel: GraphicalLabel, layer: GraphicalLayers, specs: LabelRenderSpecs): Node {
         throw new Error("not implemented");
     }
 

+ 3 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -650,6 +650,9 @@ export class VexFlowMeasure extends GraphicalMeasure {
             for (const ve of voice.VoiceEntries) {
                 for (const note of ve.Notes) {
                     const gNote: VexFlowGraphicalNote = this.rules.GNote(note) as VexFlowGraphicalNote;
+                    if (!gNote.vfnote) { // can happen were invisible, then multi rest measure. TODO fix multi rest measure not removed
+                        return;
+                    }
                     const vfnote: Vex.Flow.StemmableNote = gNote.vfnote[0];
                     // if (note.isRest()) // TODO somehow there are never rest notes in ve.Notes
                     // TODO also, grace notes are not included here, need to be fixed as well. (and a few triple beamed notes in Bach Air)

+ 2 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -773,7 +773,8 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     if (!rehearsalExpression) {
       return;
     }
-    const measureNumber: number = Math.max(measure.MeasureNumber - 1, 0);
+    const firstMeasureNumber: number = this.graphicalMusicSheet.MeasureList[0][0].MeasureNumber; // 0 for pickup, 1 otherwise
+    const measureNumber: number = Math.max(measure.MeasureNumber - firstMeasureNumber, 0);
     const staffNumber: number = 0;
     const vfStave: Vex.Flow.Stave = (this.graphicalMusicSheet.MeasureList[measureNumber][staffNumber] as VexFlowMeasure).getVFStave();
     const yOffset: number = -this.rules.RehearsalMarkYOffsetDefault - this.rules.RehearsalMarkYOffset;

+ 12 - 8
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -409,15 +409,14 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
      * @param heightInPixel the height of the text in screen coordinates
      * @param screenPosition the position of the lower left corner of the text in screen coordinates
      */
-    protected renderLabel(graphicalLabel: GraphicalLabel, layer: GraphicalLayers, specs: LabelRenderSpecs): Node[] {
+    protected renderLabel(graphicalLabel: GraphicalLabel, layer: GraphicalLayers, specs: LabelRenderSpecs): Node {
         return this._renderLabel(graphicalLabel, specs);
     }
 
-    private _renderLabel(graphicalLabel: GraphicalLabel, specs: LabelRenderSpecs): Node[] {
+    private _renderLabel(graphicalLabel: GraphicalLabel, specs: LabelRenderSpecs): Node {
         if (!graphicalLabel.Label.print) {
-            return [];
+            return undefined;
         }
-        const nodes: Node[] = [];
         const height: number = graphicalLabel.Label.fontHeight * unitInPixels;
         const { font } = graphicalLabel.Label;
         let color: string;
@@ -438,20 +437,25 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
             fontFamily = this.rules.DefaultFontFamily;
         }
 
+        let node: Node;
         for (let i: number = 0; i < graphicalLabel.TextLines?.length; i++) {
             const currLine: {text: string, xOffset: number, width: number} = graphicalLabel.TextLines[i];
             const xOffsetInPixel: number = this.calculatePixelDistance(currLine.xOffset);
             const linePosition: PointF2D = new PointF2D(specs.ScreenPosition.x + xOffsetInPixel, specs.ScreenPosition.y);
-            nodes.push(
-                this.backend.renderText(height, fontStyle, font, currLine.text, specs.FontHeightInPixel, linePosition, color, graphicalLabel.Label.fontFamily)
-            );
+            const newNode: Node =
+                this.backend.renderText(height, fontStyle, font, currLine.text, specs.FontHeightInPixel, linePosition, color, graphicalLabel.Label.fontFamily);
+            if (!node) {
+                node = newNode;
+            } else {
+                node.appendChild(newNode);
+            }
             specs.ScreenPosition.y = specs.ScreenPosition.y + specs.FontHeightInPixel;
             if (graphicalLabel.TextLines.length > 1) {
                 specs.ScreenPosition.y += this.rules.SpacingBetweenTextLines;
             }
         }
         // font currently unused, replaced by fontFamily
-        return nodes; // this will be a merge conflict with annotations, refactor there to handle node array instead of single node
+        return node; // this will be a merge conflict with annotations, refactor there to handle node array instead of single node
     }
 
     /**

+ 9 - 9
src/MusicalScore/MusicSheet.ts

@@ -441,15 +441,15 @@ export class MusicSheet /*implements ISettableMusicSheet, IComparable<MusicSheet
     //
     //}
     public getExpressionsStartTempoInBPM(): number {
-       if (this.TimestampSortedTempoExpressionsList.length > 0) {
-           const me: MultiTempoExpression = this.TimestampSortedTempoExpressionsList[0];
-           if (me.InstantaneousTempo) {
-               return me.InstantaneousTempo.TempoInBpm;
-           } else if (me.ContinuousTempo) {
-               return me.ContinuousTempo.StartTempo;
-           }
-       }
-       return this.userStartTempoInBPM;
+        if (this.TimestampSortedTempoExpressionsList.length > 0) {
+            const me: MultiTempoExpression = this.TimestampSortedTempoExpressionsList[0];
+            if (me.InstantaneousTempo) {
+                return me.InstantaneousTempo.TempoInBpm;
+            } else if (me.ContinuousTempo) {
+                return me.ContinuousTempo.StartTempo;
+            }
+        }
+        return this.userStartTempoInBPM;
     }
     public get Errors(): { [n: number]: string[] } {
         return this.musicSheetErrors.measureErrors;

+ 1 - 0
src/MusicalScore/ScoreIO/MusicSymbolModules/LyricsReader.ts

@@ -134,6 +134,7 @@ export class LyricsReader {
                                     currentVoiceEntry.LyricsEntries.setValue(currentLyricVerseNumber, lyricsEntry);
                                     if (currentVoiceEntry.ParentSourceStaffEntry?.VerticalContainerParent?.ParentMeasure) {
                                         currentVoiceEntry.ParentSourceStaffEntry.VerticalContainerParent.ParentMeasure.hasLyrics = true;
+                                        // currentVoiceEntry.ParentSourceStaffEntry.ParentStaff.hasLyrics = true; // TODO enable, though rarely lyrics on rests
                                     }
                                 }
                                 // save in currentInstrument the verseNumber (only once)

+ 27 - 1
src/MusicalScore/VoiceData/SourceMeasure.ts

@@ -600,7 +600,33 @@ export class SourceMeasure {
     }
 
     public canBeReducedToMultiRest(): boolean {
-        if (!this.allRests || this.hasLyrics || this.hasMoodExpressions || this.tempoExpressions.length > 0) {
+        let allRestsOrInvisible: boolean = true;
+        let visibleLyrics: boolean = false;
+        for (const container of this.verticalSourceStaffEntryContainers) {
+            if (!container) {
+                continue;
+            }
+            for (const staffEntry of container.StaffEntries) {
+                if (!staffEntry || !staffEntry.ParentStaff.ParentInstrument.Visible) {
+                    continue; // ignore notes in invisible instruments (instruments not shown)
+                }
+                if (staffEntry.ParentStaff.hasLyrics) {
+                    visibleLyrics = true;
+                }
+                for (const voiceEntry of staffEntry.VoiceEntries) {
+                    for (const note of voiceEntry.Notes) {
+                        if (!note.isRest()) {
+                            allRestsOrInvisible = false;
+                            break;
+                        }
+                    }
+                    if (!allRestsOrInvisible) {
+                        break;
+                    }
+                }
+            }
+        }
+        if (!allRestsOrInvisible || visibleLyrics || this.hasMoodExpressions || this.tempoExpressions.length > 0) {
             return false;
         }
         // check for StaffLinkedExpressions (e.g. MultiExpression, StaffText) (per staff)

+ 1 - 0
src/MusicalScore/VoiceData/Staff.ts

@@ -21,6 +21,7 @@ export class Staff {
     private id: number;
     private stafflineCount: number = 5;
     private solo: boolean;
+    public hasLyrics: boolean = false;
 
     public get ParentInstrument(): Instrument {
         return this.parentInstrument;

+ 1 - 0
src/MusicalScore/index.ts

@@ -8,6 +8,7 @@ export * from "./MusicSheet";
 export * from "./SubInstrument";
 export * from "./VoiceData";
 export * from "./MusicSource";
+export * from "./MusicParts";
 export * from "./ScoreIO";
 export * from "./Graphical";
 export * from "./Interfaces";

+ 2 - 0
src/OpenSheetMusicDisplay/OSMDOptions.ts

@@ -172,6 +172,8 @@ export interface IOSMDOptions {
      * So this option may result in a page break after a single measure on a page.
      */
     newPageFromXML?: boolean;
+    /** A custom function that is executed when the xml is read, modifies it, and returns a new xml string that OSMD then parses. */
+    onXMLRead?(xml: string): string;
     /** The cutoff number for rendering percussion clef stafflines as a single line. Default is 4.
      *  This is number of instruments specified, e.g. a drumset:
      *     <score-part id="P1">

+ 10 - 3
src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts

@@ -34,7 +34,7 @@ import { DynamicsCalculator } from "../MusicalScore/ScoreIO/MusicSymbolModules/D
  * After the constructor, use load() and render() to load and render a MusicXML file.
  */
 export class OpenSheetMusicDisplay {
-    private version: string = "0.9.3-audio-release-1"; // getter: this.Version
+    private version: string = "0.9.5-audio-extended"; // getter: this.Version
     // at release, bump version and change to -release, afterwards to -dev again
 
     /**
@@ -141,12 +141,14 @@ export class OpenSheetMusicDisplay {
             return parser.parseFromString(xmlString.substr(3), "application/xml");
         }
         if (xmlString.substr(0, 6).includes("<?xml")) {
-            log.debug("[OSMD] Finally parsing XML content, length: " + xmlString.length);
+            const modifiedXml: string = this.OnXMLRead(xmlString); // by default just returns trimmedStr unless a function options.OnXMLRead was set.
+            log.debug("[OSMD] Finally parsing XML content, length: " + modifiedXml.length);
             // Parse the string representing an xml file
-            return parser.parseFromString(xmlString, "application/xml");
+            return parser.parseFromString(modifiedXml, "application/xml");
         }
     }
 
+    private OnXMLRead: Function;
 
     /**
      * Load a MusicXML file
@@ -432,6 +434,11 @@ export class OpenSheetMusicDisplay {
                 + "\n" + "example usage: osmd.setOptions({drawCredits: false, drawPartNames: false})");
             return;
         }
+        this.OnXMLRead = function(xml): string {return xml;};
+        if (options.onXMLRead)
+        {
+            this.OnXMLRead = options.onXMLRead;
+        }
         if (options.drawingParameters) {
             this.drawingParameters.DrawingParametersEnum =
                 (<any>DrawingParametersEnum)[options.drawingParameters.toLowerCase()];

+ 19 - 10
src/Util/CollectionUtil.ts

@@ -12,21 +12,31 @@ declare global {
 }
 
 if (!Array.prototype.last) {
-    Array.prototype.last = function<T>(): T {
-        return this[this.length - 1];
-    };
+    // using Object.defineProperty instead of assigning Array.prototype.x directly prevents prototype pollution, see #980
+    Object.defineProperty(Array.prototype, "last", {
+        enumerable: false,
+        value: function<T>(): T {
+            return this[this.length - 1];
+        }
+    });
 }
 
 if (!Array.prototype.clear) {
-    Array.prototype.clear = function<T>(): void {
-        this.length = 0;
-    };
+    Object.defineProperty(Array.prototype, "clear", {
+        enumerable: false,
+        value: function<T>(): void {
+            this.length = 0;
+        }
+    });
 }
 
 if (!Array.prototype.contains) {
-    Array.prototype.contains = function<T>(elem: T): boolean {
-        return this.indexOf(elem) !== -1;
-    };
+    Object.defineProperty(Array.prototype, "contains", {
+        enumerable: false,
+        value: function<T>(elem: T): boolean {
+            return this.indexOf(elem) !== -1;
+        }
+    });
 }
 
 /**
@@ -40,7 +50,6 @@ export class CollectionUtil {
                 return true;
             }
         }
-
         return false;
     }
 

+ 4 - 0
test/data/test_rehearsal_marks_bolivia.musicxml

@@ -1,7 +1,11 @@
 <?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>
+<<<<<<< HEAD
   <movement-title>Bolivia</movement-title>
+=======
+  <movement-title>Test - Rehearsal Marks Bolivia</movement-title>
+>>>>>>> osmd-public/develop
   <identification>
     <creator type="composer">Cedar Extra Name Walton</creator>
     <creator type="lyricist">Up Tempo Swing</creator>

+ 674 - 0
test/data/test_slurs_long_steep_arc_flattening_chopin.musicxml

@@ -0,0 +1,674 @@
+<?xml version="1.0" encoding='UTF-8' standalone='no' ?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 3.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="3.0">
+ <work>
+  <work-title>Test - Slurs Steep Arc Flattening Chopin</work-title>
+ </work>
+ <identification>
+  <encoding>
+   <encoding-date>2021-02-10</encoding-date>
+   <encoder>Jack Keough</encoder>
+   <software>Sibelius 19.5.0</software>
+   <software>Direct export, not from Dolet</software>
+   <encoding-description>Sibelius / MusicXML 3.0</encoding-description>
+   <supports element="print" type="yes" value="yes" attribute="new-system" />
+   <supports element="print" type="yes" value="yes" attribute="new-page" />
+   <supports element="accidental" type="yes" />
+   <supports element="beam" type="yes" />
+   <supports element="stem" type="yes" />
+  </encoding>
+ </identification>
+ <defaults>
+  <scaling>
+   <millimeters>215.9</millimeters>
+   <tenths>1233</tenths>
+  </scaling>
+  <page-layout>
+   <page-height>1596</page-height>
+   <page-width>1233</page-width>
+   <page-margins type="both">
+    <left-margin>85</left-margin>
+    <right-margin>85</right-margin>
+    <top-margin>85</top-margin>
+    <bottom-margin>85</bottom-margin>
+   </page-margins>
+  </page-layout>
+  <system-layout>
+   <system-margins>
+    <left-margin>63</left-margin>
+    <right-margin>0</right-margin>
+   </system-margins>
+   <system-distance>92</system-distance>
+  </system-layout>
+  <appearance>
+   <line-width type="stem">0.9375</line-width>
+   <line-width type="beam">5</line-width>
+   <line-width type="staff">0.9375</line-width>
+   <line-width type="light barline">1.5625</line-width>
+   <line-width type="heavy barline">5</line-width>
+   <line-width type="leger">1.5625</line-width>
+   <line-width type="ending">1.5625</line-width>
+   <line-width type="wedge">1.25</line-width>
+   <line-width type="enclosure">0.9375</line-width>
+   <line-width type="tuplet bracket">1.25</line-width>
+   <line-width type="bracket">5</line-width>
+   <line-width type="dashes">1.5625</line-width>
+   <line-width type="extend">0.9375</line-width>
+   <line-width type="octave shift">1.5625</line-width>
+   <line-width type="pedal">1.5625</line-width>
+   <line-width type="slur middle">1.5625</line-width>
+   <line-width type="slur tip">0.625</line-width>
+   <line-width type="tie middle">1.5625</line-width>
+   <line-width type="tie tip">0.625</line-width>
+   <note-size type="cue">75</note-size>
+   <note-size type="grace">60</note-size>
+  </appearance>
+  <music-font font-family="Opus Std" font-size="19.8425" />
+  <lyric-font font-family="Times New Roman" font-size="11.4715" />
+  <lyric-language xml:lang="en" />
+ </defaults>
+ <part-list>
+  <part-group type="start" number="1">
+   <group-symbol>brace</group-symbol>
+  </part-group>
+  <score-part id="P1">
+   <part-name>Piano</part-name>
+   <part-name-display>
+    <display-text>Piano</display-text>
+   </part-name-display>
+   <part-abbreviation>Pno.</part-abbreviation>
+   <part-abbreviation-display>
+    <display-text>Pno.</display-text>
+   </part-abbreviation-display>
+   <score-instrument id="P1-I1">
+    <instrument-name>Piano (2)</instrument-name>
+    <instrument-sound>keyboard.piano.grand</instrument-sound>
+    <solo />
+    <virtual-instrument>
+     <virtual-library>General MIDI</virtual-library>
+     <virtual-name>Acoustic Piano</virtual-name>
+    </virtual-instrument>
+   </score-instrument>
+  </score-part>
+  <part-group type="stop" number="1" />
+ </part-list>
+ <part id="P1">
+  <!--============== Part: P1, Measure: 1 ==============-->
+  <measure number="1" width="402">
+   <print new-page="yes">
+    <system-layout>
+     <system-margins>
+      <left-margin>76</left-margin>
+      <right-margin>0</right-margin>
+     </system-margins>
+     <top-system-distance>181</top-system-distance>
+    </system-layout>
+   </print>
+   <attributes>
+    <divisions>256</divisions>
+    <key color="#000000">
+     <fifths>-4</fifths>
+     <mode>minor</mode>
+    </key>
+    <time color="#000000">
+     <beats>2</beats>
+     <beat-type>2</beat-type>
+    </time>
+    <staves>1</staves>
+    <clef number="1" color="#000000">
+     <sign>G</sign>
+     <line>2</line>
+    </clef>
+    <staff-details number="1" print-object="yes" />
+   </attributes>
+   <note default-x="125">
+    <rest />
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="start" bracket="no" number="1" default-y="17" placement="above" />
+    </notations>
+   </note>
+   <direction>
+    <direction-type>
+     <dynamics default-x="165" default-y="-72" color="#000000" font-family="Opus Text Std" font-style="normal" font-size="11.9365" font-weight="normal">
+      <p />
+     </dynamics>
+    </direction-type>
+    <voice>1</voice>
+    <staff>1</staff>
+   </direction>
+   <note color="#000000" default-x="171" default-y="-15">
+    <pitch>
+     <step>C</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>flat</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <slur color="#000000" type="start" orientation="over" />
+    </notations>
+   </note>
+   <note color="#000000" default-x="217" default-y="-15">
+    <pitch>
+     <step>C</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>natural</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="263" default-y="-10">
+    <pitch>
+     <step>D</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="310" default-y="-20">
+    <pitch>
+     <step>B</step>
+     <alter>-1</alter>
+     <octave>3</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="355">
+    <pitch>
+     <step>F</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="stop" bracket="no" number="1" default-y="17" placement="above" />
+    </notations>
+   </note>
+  </measure>
+  <!--============== Part: P1, Measure: 2 ==============-->
+  <measure number="2" width="292">
+   <note color="#000000" default-x="15" default-y="-5">
+    <pitch>
+     <step>E</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>natural</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="start" bracket="no" number="1" default-y="12" placement="above" />
+    </notations>
+   </note>
+   <note color="#000000" default-x="61" default-y="-15">
+    <pitch>
+     <step>C</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>flat</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="107" default-y="-15">
+    <pitch>
+     <step>C</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>natural</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="153" default-y="-10">
+    <pitch>
+     <step>D</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="200" default-y="-20">
+    <pitch>
+     <step>B</step>
+     <alter>-1</alter>
+     <octave>3</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="246">
+    <pitch>
+     <step>F</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="stop" bracket="no" number="1" default-y="12" placement="above" />
+    </notations>
+   </note>
+  </measure>
+  <!--============== Part: P1, Measure: 3 ==============-->
+  <measure number="3" width="292">
+   <note color="#000000" default-x="15" default-y="-5">
+    <pitch>
+     <step>E</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>natural</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="start" bracket="no" number="1" default-y="12" placement="above" />
+    </notations>
+   </note>
+   <note color="#000000" default-x="61" default-y="-15">
+    <pitch>
+     <step>C</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>flat</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="107" default-y="-15">
+    <pitch>
+     <step>C</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>natural</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="153" default-y="-10">
+    <pitch>
+     <step>D</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="199" default-y="-15">
+    <pitch>
+     <step>C</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="245" default-y="-10">
+    <pitch>
+     <step>D</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>natural</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="stop" bracket="no" number="1" default-y="12" placement="above" />
+    </notations>
+   </note>
+  </measure>
+  <!--============== Part: P1, Measure: 4 ==============-->
+  <measure number="4" width="595">
+   <print new-system="yes">
+    <system-layout>
+     <system-margins>
+      <left-margin>64</left-margin>
+      <right-margin>0</right-margin>
+     </system-margins>
+     <system-distance>119</system-distance>
+    </system-layout>
+   </print>
+   <attributes>
+    <staff-details number="1" print-object="yes" />
+   </attributes>
+   <direction>
+    <direction-type>
+     <wedge default-x="11" default-y="-65" color="#000000" type="crescendo" />
+    </direction-type>
+    <voice>1</voice>
+    <staff>1</staff>
+   </direction>
+   <note color="#000000" default-x="107">
+    <pitch>
+     <step>F</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="start" bracket="no" number="1" default-y="12" placement="above" />
+    </notations>
+   </note>
+   <note color="#000000" default-x="188" default-y="-5">
+    <pitch>
+     <step>E</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <accidental>natural</accidental>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="270">
+    <pitch>
+     <step>F</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <note color="#000000" default-x="351" default-y="10">
+    <pitch>
+     <step>A</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>170</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <direction>
+    <direction-type>
+     <wedge default-x="-8" default-y="-65" color="#000000" type="stop" />
+    </direction-type>
+    <offset sound="no">-1</offset>
+    <voice>1</voice>
+    <staff>1</staff>
+   </direction>
+   <direction>
+    <direction-type>
+     <wedge default-x="11" default-y="-65" color="#000000" type="diminuendo" number="2" />
+    </direction-type>
+    <voice>1</voice>
+    <staff>1</staff>
+   </direction>
+   <note color="#000000" default-x="432" default-y="5">
+    <pitch>
+     <step>G</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+   </note>
+   <direction>
+    <direction-type>
+     <wedge default-x="-8" default-y="-65" color="#000000" type="stop" number="2" />
+    </direction-type>
+    <offset sound="no">170</offset>
+    <voice>1</voice>
+    <staff>1</staff>
+   </direction>
+   <note color="#000000" default-x="513" default-y="10">
+    <pitch>
+     <step>A</step>
+     <alter>-1</alter>
+     <octave>4</octave>
+    </pitch>
+    <duration>171</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <time-modification>
+     <actual-notes>6</actual-notes>
+     <normal-notes>4</normal-notes>
+     <normal-type>quarter</normal-type>
+    </time-modification>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <tuplet type="stop" bracket="no" number="1" default-y="12" placement="above" />
+    </notations>
+   </note>
+  </measure>
+  <!--============== Part: P1, Measure: 5 ==============-->
+  <measure number="5" width="404">
+   <note color="#000000" default-x="15">
+    <pitch>
+     <step>F</step>
+     <octave>4</octave>
+    </pitch>
+    <duration>256</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <stem>up</stem>
+    <staff>1</staff>
+    <notations>
+     <slur color="#000000" type="stop" orientation="over" />
+    </notations>
+   </note>
+   <note default-x="116">
+    <rest />
+    <duration>256</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>quarter</type>
+    <staff>1</staff>
+   </note>
+   <note default-x="217">
+    <rest />
+    <duration>512</duration>
+    <instrument id="P1-I1" />
+    <voice>1</voice>
+    <type>half</type>
+    <staff>1</staff>
+   </note>
+   <barline>
+    <bar-style>light-heavy</bar-style>
+   </barline>
+  </measure>
+ </part>
+</score-partwise>