Browse Source

Merge osmd-public: labels have SVGNode, fix chordsymbol collisions, etc.

this is a large part of what is going to be the upcoming OSMD 1.3.0 release,
i just wanted to merge this ahead of time, to be faster, and to make the next merge easier.

InstrumentReader conflict: osmd-extended uses a newer method to process wavy-line,
so we have to keep that and not just accept all incoming changes.

* osmd-public/develop-copy:
refactor: fix slashflat twice in switch statement
feat(Accidentals): Support remaining microtonal accidentals available in MusicXML and Vexflow (#1084)
fix(Tuplets): Fix dots not corresponding to XML (#1082)
fix(Infinite Loop): Fix rare infinite loop with certain rhythms (#1073)
fix(OctaveShift): fix ExtraGraphicalMeasure used as last measure, no endnote (#1080)
feat(ChordSymbols): Fix collision with notes, add staffline/measure alignment (#1087, #934)
feat(Labels): Always save SVG Node as a reference for GraphicalLabel, allowing manipulation
fix <words>p etc. detected as instantaneous dynamic (#858)
test: fingering: add articulation collision sample (#994)

# Conflicts:
# src/MusicalScore/Graphical/MusicSheetDrawer.ts
# src/MusicalScore/ScoreIO/InstrumentReader.ts
# src/MusicalScore/ScoreIO/MusicSymbolModules/ExpressionReader.ts
# src/MusicalScore/ScoreIO/VoiceGenerator.ts
sschmid 3 years ago
parent
commit
84a0c7be9b

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

@@ -28,6 +28,11 @@ export enum AccidentalEnum {
     SLASHFLAT,
     THREEQUARTERSSHARP,
     THREEQUARTERSFLAT,
+    SLASHQUARTERSHARP,
+    SLASHSHARP,
+    DOUBLESLASHFLAT,
+    SORI,
+    KORON
 }
 
 // This class represents a musical note. The middle A (440 Hz) lies in the octave with the value 1.
@@ -232,6 +237,16 @@ export class Pitch {
                 return 1.5;
             case AccidentalEnum.THREEQUARTERSFLAT:
                 return -1.5;
+            case AccidentalEnum.SLASHQUARTERSHARP:
+                return 0.0013; // tmp for identification
+            case AccidentalEnum.SLASHSHARP:
+                return 0.0014; // tmp for identification
+            case AccidentalEnum.DOUBLESLASHFLAT:
+                return -0.0015; // tmp for identification
+            case AccidentalEnum.SORI:
+                return 0.0016; // tmp for identification
+            case AccidentalEnum.KORON:
+                return 0.0017; // tmp for identification
             default:
                 throw new Error("Unhandled AccidentalEnum value");
                 // return 0;
@@ -319,6 +334,21 @@ export class Pitch {
             case AccidentalEnum.THREEQUARTERSFLAT:
                 acc = "db";
                 break;
+            case AccidentalEnum.SLASHQUARTERSHARP:
+                acc = "+-";
+                break;
+            case AccidentalEnum.SLASHSHARP:
+                acc = "++-";
+                break;
+            case AccidentalEnum.DOUBLESLASHFLAT:
+                acc = "bss";
+                break;
+            case AccidentalEnum.SORI:
+                acc = "o";
+                break;
+            case AccidentalEnum.KORON:
+                acc = "k";
+                break;
             default:
         }
         return acc;

+ 7 - 1
src/MusicalScore/Graphical/EngravingRules.ts

@@ -115,6 +115,9 @@ export class EngravingRules {
     public ChordSymbolXSpacing: number;
     public ChordOverlapAllowedIntoNextMeasure: number;
     public ChordSymbolYOffset: number;
+    public ChordSymbolYPadding: number;
+    public ChordSymbolYAlignment: boolean;
+    public ChordSymbolYAlignmentScope: string;
     public ChordSymbolLabelTexts: Dictionary<ChordSymbolEnum, string>;
     public CustomChords: CustomChord[];
     public RepetitionSymbolsYOffset: number;
@@ -449,7 +452,10 @@ export class EngravingRules {
         this.ChordSymbolRelativeXOffset = -1.0;
         this.ChordSymbolXSpacing = 1.0;
         this.ChordOverlapAllowedIntoNextMeasure = 0;
-        this.ChordSymbolYOffset = 2.0;
+        this.ChordSymbolYOffset = 0.1;
+        this.ChordSymbolYPadding = 0.0;
+        this.ChordSymbolYAlignment = true;
+        this.ChordSymbolYAlignmentScope = "staffline"; // "measure" or "staffline"
         this.ChordSymbolLabelTexts = new Dictionary<ChordSymbolEnum, string>();
         this.resetChordSymbolLabelTexts(this.ChordSymbolLabelTexts);
         this.CustomChords = [];

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

@@ -12,6 +12,11 @@ export class GraphicalLabel extends Clickable {
     private label: Label;
     private rules: EngravingRules;
     public TextLines: {text: string, xOffset: number, width: number}[];
+    /** A reference to the Node in the SVG, if SVGBackend, otherwise undefined.
+     *  Allows manipulation without re-rendering, e.g. for dynamics, lyrics, etc.
+     *  For the Canvas backend, this is unfortunately not possible.
+     */
+    public SVGNode: Node;
 
     /**
      * Creates a new GraphicalLabel from a Label

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

@@ -69,6 +69,9 @@ export abstract class GraphicalMeasure extends GraphicalObject {
     private parentMusicSystem: MusicSystem;
     private measureNumber: number = -1;
     private parentStaffLine: StaffLine;
+    /** Used to show key, rhythm changes at the end of the system, has MeasureNumber < 0, because never set. */
+    public IsExtraGraphicalMeasure: boolean;
+    public ExtraGraphicalMeasurePreviousMeasure: GraphicalMeasure;
 
     public get ParentStaff(): Staff {
         return this.parentStaff;

+ 47 - 3
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -70,6 +70,7 @@ import { FillEmptyMeasuresWithWholeRests } from "../../OpenSheetMusicDisplay/OSM
 import { JustifiedMusicSystemBuilder } from "./JustifiedMusicSystemBuilder";
 import { IStafflineNoteCalculator } from "../Interfaces/IStafflineNoteCalculator";
 import { GraphicalUnknownExpression } from "./GraphicalUnknownExpression";
+import { GraphicalChordSymbolContainer } from ".";
 
 /**
  * Class used to do all the calculations in a MusicSheet, which in the end populates a GraphicalMusicSheet.
@@ -977,18 +978,47 @@ export abstract class MusicSheetCalculator {
     protected calculateChordSymbols(): void {
         for (const musicSystem of this.musicSystems) {
             for (const staffLine of musicSystem.StaffLines) {
-                const sbc: SkyBottomLineCalculator = staffLine.SkyBottomLineCalculator;
+                const skybottomcalculator: SkyBottomLineCalculator = staffLine.SkyBottomLineCalculator;
+                let minimumOffset: number = Number.MAX_SAFE_INTEGER; // only calculated if option set
+                if (this.rules.ChordSymbolYAlignment && this.rules.ChordSymbolYAlignmentScope === "staffline") {
+                    // get the max y position of all chord symbols in the staffline in advance
+                    const alignmentScopedStaffEntries: GraphicalStaffEntry[] = [];
+                    for (const measure of staffLine.Measures) {
+                        alignmentScopedStaffEntries.push(...measure.staffEntries);
+                    }
+                    minimumOffset = this.calculateAlignedChordSymbolsOffset(alignmentScopedStaffEntries, skybottomcalculator);
+                }
                 for (const measure of staffLine.Measures) {
+                    if (this.rules.ChordSymbolYAlignment && this.rules.ChordSymbolYAlignmentScope === "measure") {
+                        minimumOffset = this.calculateAlignedChordSymbolsOffset(measure.staffEntries, skybottomcalculator);
+                    }
                     for (const staffEntry of measure.staffEntries) {
                         if (!staffEntry.graphicalChordContainers || staffEntry.graphicalChordContainers.length === 0) {
                             continue;
                         }
-                        for (const graphicalChordContainer of staffEntry.graphicalChordContainers) {
+                        for (let i: number = 0; i < staffEntry.graphicalChordContainers.length; i++) {
+                            const graphicalChordContainer: GraphicalChordSymbolContainer = staffEntry.graphicalChordContainers[i];
                             const sps: BoundingBox = staffEntry.PositionAndShape;
                             const gps: BoundingBox = graphicalChordContainer.PositionAndShape;
                             const start: number = gps.BorderMarginLeft + sps.AbsolutePosition.x;
                             const end: number = gps.BorderMarginRight + sps.AbsolutePosition.x;
-                            sbc.updateSkyLineInRange(start, end, sps.BorderMarginTop);
+                            if (!this.rules.ChordSymbolYAlignment || minimumOffset > 0) {
+                                //minimumOffset = this.calculateAlignedChordSymbolsOffset([staffEntry], skybottomcalculator);
+                                minimumOffset = skybottomcalculator.getSkyLineMinInRange(start, end); // same as above, less code executed
+                            }
+                            let yShift: number = 0;
+                            if (i === 0) {
+                                yShift += this.rules.ChordSymbolYOffset;
+                                yShift += 0.1; // above is a bit closer to the notes than below ones for some reason
+                            } else {
+                                yShift += this.rules.ChordSymbolYPadding;
+                            }
+                            yShift *= -1;
+                            const gLabel: GraphicalLabel = graphicalChordContainer.GraphicalLabel;
+                            gLabel.PositionAndShape.RelativePosition.y = minimumOffset + yShift;
+                            gLabel.setLabelPositionAndShapeBorders();
+                            gLabel.PositionAndShape.calculateBoundingBox();
+                            skybottomcalculator.updateSkyLineInRange(start, end, minimumOffset + gLabel.PositionAndShape.BorderMarginTop);
                         }
                     }
                 }
@@ -996,6 +1026,20 @@ export abstract class MusicSheetCalculator {
         }
     }
 
+    protected calculateAlignedChordSymbolsOffset(staffEntries: GraphicalStaffEntry[], sbc: SkyBottomLineCalculator): number {
+        let minimumOffset: number = Number.MAX_SAFE_INTEGER;
+        for (const staffEntry of staffEntries) {
+            for (const graphicalChordContainer of staffEntry.graphicalChordContainers) {
+                const sps: BoundingBox = staffEntry.PositionAndShape;
+                const gps: BoundingBox = graphicalChordContainer.PositionAndShape;
+                const start: number = gps.BorderMarginLeft + sps.AbsolutePosition.x;
+                const end: number = gps.BorderMarginRight + sps.AbsolutePosition.x;
+                minimumOffset = Math.min(minimumOffset, sbc.getSkyLineMinInRange(start, end));
+            }
+        }
+        return minimumOffset;
+    }
+
     /**
      * Do layout on staff measures which only consist of a full rest.
      * @param rest

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

@@ -328,7 +328,7 @@ export abstract class MusicSheetDrawer {
         }
         if (musicSystem.Parent === musicSystem.Parent.Parent.MusicPages[0]) {
             for (const label of musicSystem.Labels) {
-                this.drawLabel(label, <number>GraphicalLayers.Notes);
+                label.SVGNode = this.drawLabel(label, <number>GraphicalLayers.Notes);
             }
         }
         for (const bracket of musicSystem.InstrumentBrackets) {
@@ -339,7 +339,7 @@ export abstract class MusicSheetDrawer {
         }
         if (!this.leadSheet) {
             for (const measureNumberLabel of musicSystem.MeasureNumberLabels) {
-                this.drawLabel(measureNumberLabel, <number>GraphicalLayers.Notes);
+                measureNumberLabel.SVGNode = this.drawLabel(measureNumberLabel, <number>GraphicalLayers.Notes);
             }
         }
         for (const staffLine of musicSystem.StaffLines) {
@@ -423,7 +423,7 @@ export abstract class MusicSheetDrawer {
      * @param layer Number of the layer that the lyrics should be drawn in
      */
     protected drawDashes(lyricsDashes: GraphicalLabel[]): void {
-        lyricsDashes.forEach(dash => this.drawLabel(dash, <number>GraphicalLayers.Notes));
+        lyricsDashes.forEach(dash => dash.SVGNode = this.drawLabel(dash, <number>GraphicalLayers.Notes));
     }
 
     // protected drawSlur(slur: GraphicalSlur, abs: PointF2D): void {
@@ -493,7 +493,7 @@ export abstract class MusicSheetDrawer {
         }
         if (page === page.Parent.MusicPages[0]) {
             for (const label of page.Labels) {
-                this.drawLabel(label, <number>GraphicalLayers.Notes);
+                label.SVGNode = this.drawLabel(label, <number>GraphicalLayers.Notes);
             }
         }
         // Draw bounding boxes for debug purposes. This has to be at the end because only
@@ -591,13 +591,13 @@ export abstract class MusicSheetDrawer {
                     this.drawRectangle(markedArea.systemRectangle, <number>GraphicalLayers.Background);
                 }
                 if (markedArea.settings) {
-                    this.drawLabel(markedArea.settings, <number>GraphicalLayers.Comment);
+                    markedArea.settings.SVGNode = this.drawLabel(markedArea.settings, <number>GraphicalLayers.Comment);
                 }
                 if (markedArea.labelRectangle) {
                     this.drawRectangle(markedArea.labelRectangle, <number>GraphicalLayers.Background);
                 }
                 if (markedArea.label) {
-                    this.drawLabel(markedArea.label, <number>GraphicalLayers.Comment);
+                    markedArea.label.SVGNode = this.drawLabel(markedArea.label, <number>GraphicalLayers.Comment);
                 }
             }
         }

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

@@ -49,7 +49,7 @@ export class SkyBottomLineCalculator {
             // Pre initialize and get stuff for more performance
             const vsStaff: any = measure.getVFStave();
             let width: number = vsStaff.getWidth();
-            if (!(width > 0)) {
+            if (!(width > 0) && !measure.IsExtraGraphicalMeasure) {
                 log.warn("SkyBottomLineCalculator: width not > 0 in measure " + measure.MeasureNumber);
                 width = 50;
             }

+ 1 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowConverter.ts

@@ -261,6 +261,7 @@ export class VexFlowConverter {
             baseNote.sourceNote.TypeLength !== baseNoteLength &&
             baseNote.sourceNote.TypeLength.RealValue !== 0) {
             duration = VexFlowConverter.durations(baseNote.sourceNote.TypeLength, isTuplet)[0];
+            baseNote.numberOfDots = baseNote.sourceNote.DotsXml;
         }
         let vfClefType: string = undefined;
         let numDots: number = baseNote.numberOfDots;

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

@@ -113,7 +113,10 @@ export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
      * @returns {VexFlowMeasure}
      */
     public createExtraGraphicalMeasure(staffLine: StaffLine): GraphicalMeasure {
-        return new VexFlowMeasure(staffLine.ParentStaff, undefined, staffLine);
+        const extraGraphicalMeasure: GraphicalMeasure = new VexFlowMeasure(staffLine.ParentStaff, undefined, staffLine);
+        extraGraphicalMeasure.IsExtraGraphicalMeasure = true; // this also means that MeasureNumber < 0 because unchanged
+        extraGraphicalMeasure.ExtraGraphicalMeasurePreviousMeasure = staffLine.Measures.last();
+        return extraGraphicalMeasure;
     }
 
     /**

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

@@ -1242,6 +1242,10 @@ export class VexFlowMeasure extends GraphicalMeasure {
                 }
 
                 const vexFlowVoiceEntry: VexFlowVoiceEntry = voiceEntry as VexFlowVoiceEntry;
+                if ((vexFlowVoiceEntry.vfStaveNote as any).ticks.denominator === 0) {
+                    continue; // TODO not sure why the ticks aren't calculated correctly, see #1073
+                    // if denominator === 0, addTickable() below goes into an infinite loop.
+                }
                 if (voiceEntry.notes.length === 0 || !voiceEntry.notes[0] || !voiceEntry.notes[0].sourceNote.PrintObject) {
                     // GhostNote, don't add modifiers like in-measure clefs
                     this.vfVoices[voice.VoiceId].addTickable(vexFlowVoiceEntry.vfStaveNote);

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

@@ -947,6 +947,9 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
             }
 
             let nextShiftLastMeasure: GraphicalMeasure = nextShiftStaffline.Measures[nextShiftStaffline.Measures.length - 1];
+            if (nextShiftLastMeasure.IsExtraGraphicalMeasure) { // key/rhythm change measure
+              nextShiftLastMeasure = nextShiftStaffline.Measures[nextShiftStaffline.Measures.length - 2];
+            }
             const firstNote: GraphicalStaffEntry = nextShiftFirstMeasure.staffEntries[0];
             let lastNote: GraphicalStaffEntry = nextShiftLastMeasure.staffEntries[nextShiftLastMeasure.staffEntries.length - 1];
 
@@ -956,6 +959,13 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
               lastNote = endStaffEntry;
             }
 
+            const logPrefix: string = "VexFlowMusicSheetCalculator.calculateSingleOctaveShift: ";
+            if (!firstNote) {
+              log.warn(logPrefix + "no firstNote found");
+            }
+            if (!lastNote) {
+              log.warn(logPrefix + "no lastNote found");
+            }
             nextOctaveShift.setStartNote(firstNote);
             nextOctaveShift.setEndNote(lastNote);
             nextShiftStaffline.OctaveShifts.push(nextOctaveShift);
@@ -1457,7 +1467,10 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
 
   private calculateOctaveShiftSkyBottomLine(startStaffEntry: GraphicalStaffEntry, endStaffEntry: GraphicalStaffEntry,
                                             vfOctaveShift: VexFlowOctaveShift, parentStaffline: StaffLine): void {
-
+    if (!endStaffEntry) {
+      log.warn("octaveshift: no endStaffEntry");
+      return;
+    }
     let startXOffset: number = startStaffEntry.PositionAndShape.Size.width;
     let endXOffset: number = endStaffEntry.PositionAndShape.Size.width;
 

+ 20 - 10
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -318,18 +318,17 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
         }
     }
 
-
-
     private drawStaffEntry(staffEntry: GraphicalStaffEntry): void {
         if (staffEntry.FingeringEntries.length > 0) {
             for (const fingeringEntry of staffEntry.FingeringEntries) {
-                this.drawLabel(fingeringEntry, GraphicalLayers.Notes);
+                fingeringEntry.SVGNode = this.drawLabel(fingeringEntry, GraphicalLayers.Notes);
             }
         }
         // Draw ChordSymbols
         if (staffEntry.graphicalChordContainers !== undefined && staffEntry.graphicalChordContainers.length > 0) {
             for (const graphicalChordContainer of staffEntry.graphicalChordContainers) {
-                this.drawLabel(graphicalChordContainer.GraphicalLabel, <number>GraphicalLayers.Notes);
+                const label: GraphicalLabel = graphicalChordContainer.GraphicalLabel;
+                label.SVGNode = this.drawLabel(label, <number>GraphicalLayers.Notes);
             }
         }
         if (this.rules.RenderLyrics) {
@@ -345,7 +344,10 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
      * @param layer Number of the layer that the lyrics should be drawn in
      */
     private drawLyrics(lyricEntries: GraphicalLyricEntry[], layer: number): void {
-        lyricEntries.forEach(lyricsEntry => this.drawLabel(lyricsEntry.GraphicalLabel, layer));
+        lyricEntries.forEach(lyricsEntry => {
+            const label: GraphicalLabel = lyricsEntry.GraphicalLabel;
+            label.SVGNode = this.drawLabel(label, layer);
+        });
     }
 
     protected drawInstrumentBrace(brace: GraphicalObject, system: MusicSystem): void {
@@ -367,7 +369,11 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
                 const ctx: Vex.IRenderContext = this.backend.getContext();
                 const textBracket: Vex.Flow.TextBracket = vexFlowOctaveShift.getTextBracket();
                 textBracket.setContext(ctx);
-                textBracket.draw();
+                try {
+                    textBracket.draw();
+                } catch (ex) {
+                    log.warn(ex);
+                }
             }
         }
     }
@@ -404,7 +410,8 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
                 this.drawInstantaneousDynamic((abstractGraphicalExpression as VexFlowInstantaneousDynamicExpression));
                 // Draw InstantaniousTempo
             } else if (abstractGraphicalExpression instanceof GraphicalInstantaneousTempoExpression) {
-                this.drawLabel((abstractGraphicalExpression as GraphicalInstantaneousTempoExpression).GraphicalLabel, GraphicalLayers.Notes);
+                const label: GraphicalLabel = (abstractGraphicalExpression as GraphicalInstantaneousTempoExpression).GraphicalLabel;
+                label.SVGNode = this.drawLabel(label, GraphicalLayers.Notes);
                 // Draw ContinuousDynamics
             } else if (abstractGraphicalExpression instanceof GraphicalContinuousDynamicExpression) {
                 this.drawContinuousDynamic((abstractGraphicalExpression as VexFlowContinuousDynamicExpression));
@@ -417,7 +424,8 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
                 //     drawLabel(graphicalMood.GetGraphicalLabel, <number>GraphicalLayers.Notes);
             // Draw Unknown
             } else if (abstractGraphicalExpression instanceof GraphicalUnknownExpression) {
-                this.drawLabel(abstractGraphicalExpression.Label, <number>GraphicalLayers.Notes);
+                const label: GraphicalLabel = abstractGraphicalExpression.Label;
+                label.SVGNode = this.drawLabel(label, <number>GraphicalLayers.Notes);
             } else {
                 log.warn("Unkown type of expression!");
             }
@@ -425,12 +433,14 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
     }
 
     protected drawInstantaneousDynamic(instantaneousDynamic: GraphicalInstantaneousDynamicExpression): void {
-        this.drawLabel((instantaneousDynamic as VexFlowInstantaneousDynamicExpression).Label, <number>GraphicalLayers.Notes);
+        const label: GraphicalLabel = (instantaneousDynamic as VexFlowInstantaneousDynamicExpression).Label;
+        label.SVGNode = this.drawLabel(label, <number>GraphicalLayers.Notes);
     }
 
     protected drawContinuousDynamic(graphicalExpression: VexFlowContinuousDynamicExpression): void {
         if (graphicalExpression.IsVerbal) {
-            this.drawLabel(graphicalExpression.Label, <number>GraphicalLayers.Notes);
+            const label: GraphicalLabel = graphicalExpression.Label;
+            label.SVGNode = this.drawLabel(label, <number>GraphicalLayers.Notes);
         } else {
             for (const line of graphicalExpression.Lines) {
                 const start: PointF2D = new PointF2D(graphicalExpression.ParentStaffLine.PositionAndShape.AbsolutePosition.x + line.Start.x,

+ 3 - 1
src/MusicalScore/ScoreIO/InstrumentReader.ts

@@ -406,12 +406,14 @@ export class InstrumentReader {
           if (!isTuplet && !isGraceNote) {
             noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
           }
+          const dots: number = xmlNode.elements("dot").length;
           this.currentVoiceGenerator.read(
             xmlNode, noteDuration, typeDuration, noteTypeXml, normalNotes, restNote,
             this.currentStaffEntry, this.currentMeasure,
             measureStartAbsoluteTimestamp,
             this.maxTieNoteFraction, isChord, octavePlusOne,
-            printObject, isCueNote, isGraceNote, stemDirectionXml, tremoloStrokes, stemColorXml, noteheadColorXml
+            printObject, isCueNote, isGraceNote, stemDirectionXml, tremoloStrokes, stemColorXml, noteheadColorXml,
+            dots
           );
 
           // notationsNode created further up for multiple checks

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

@@ -383,6 +383,9 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
             sourceMeasureCounter++;
         }
         this.currentMeasure.Duration = maxInstrumentDuration; // can be 1/1 in a 4/4 time signature
+        // if (this.currentMeasure.Duration.Numerator === 0) {
+        //     this.currentMeasure.Duration = activeRhythm; // might be related to #1073
+        // }
         this.currentMeasure.ActiveTimeSignature = activeRhythm;
         this.currentMeasure.MeasureNumber = sourceMeasureCounter;
         for (let i: number = 0; i < instrumentsDurations.length; i++) {

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

@@ -41,6 +41,16 @@ export class ArticulationReader {
         return AccidentalEnum.THREEQUARTERSSHARP;
       case "three-quarters-flat":
         return AccidentalEnum.THREEQUARTERSFLAT;
+      case "slash-quarter-sharp":
+        return AccidentalEnum.SLASHQUARTERSHARP;
+      case "slash-sharp":
+        return AccidentalEnum.SLASHSHARP;
+      case "double-slash-flat":
+        return AccidentalEnum.DOUBLESLASHFLAT;
+      case "sori":
+        return AccidentalEnum.SORI;
+      case "koron":
+        return AccidentalEnum.KORON;
       default:
         return AccidentalEnum.NONE;
     }

+ 34 - 34
src/MusicalScore/ScoreIO/MusicSymbolModules/ExpressionReader.ts

@@ -646,43 +646,43 @@ export class ExpressionReader {
                 return true;
             }
         }
-        if (InstantaneousDynamicExpression.isInputStringInstantaneousDynamic(stringTrimmed) ||
-            ContinuousDynamicExpression.isInputStringContinuousDynamic(stringTrimmed)) {
+        if (ContinuousDynamicExpression.isInputStringContinuousDynamic(stringTrimmed)) {
+            // || InstantaneousDynamicExpression.isInputStringInstantaneousDynamic(stringTrimmed)
+            //   looks like <words> never has instantaneous dynamics like p or sf, those are in <dynamics>.
             this.createNewMultiExpressionIfNeeded(currentMeasure);
-            if (InstantaneousDynamicExpression.isInputStringInstantaneousDynamic(stringTrimmed)) {
-                if (this.openContinuousDynamicExpression !== undefined && !this.openContinuousDynamicExpression.EndMultiExpression) {
-                    this.closeOpenContinuousDynamic();
-                }
-                const instantaneousDynamicExpression: InstantaneousDynamicExpression =
-                    new InstantaneousDynamicExpression(
-                        stringTrimmed,
-                        this.soundDynamic,
-                        this.placement,
-                        this.staffNumber,
-                        currentMeasure);
-                this.getMultiExpression.addExpression(instantaneousDynamicExpression, prefix);
-                return true;
+            // if (InstantaneousDynamicExpression.isInputStringInstantaneousDynamic(stringTrimmed)) {
+            //     if (this.openContinuousDynamicExpression !== undefined && !this.openContinuousDynamicExpression.EndMultiExpression) {
+            //         this.closeOpenContinuousDynamic();
+            //     }
+            //     const instantaneousDynamicExpression: InstantaneousDynamicExpression =
+            //         new InstantaneousDynamicExpression(
+            //             stringTrimmed,
+            //             this.soundDynamic,
+            //             this.placement,
+            //             this.staffNumber,
+            //             currentMeasure);
+            //     this.getMultiExpression.addExpression(instantaneousDynamicExpression, prefix);
+            //     return true;
+            // }
+            // if (ContinuousDynamicExpression.isInputStringContinuousDynamic(stringTrimmed)) {
+            const continuousDynamicExpression: ContinuousDynamicExpression =
+                new ContinuousDynamicExpression(
+                    undefined,
+                    this.placement,
+                    this.staffNumber,
+                    currentMeasure,
+                    this.activeInstantaneousDynamic,
+                    stringTrimmed);
+            if (this.openContinuousDynamicExpression !== undefined && !this.openContinuousDynamicExpression.EndMultiExpression) {
+                this.closeOpenContinuousDynamic();
             }
-            if (ContinuousDynamicExpression.isInputStringContinuousDynamic(stringTrimmed)) {
-                const continuousDynamicExpression: ContinuousDynamicExpression =
-                    new ContinuousDynamicExpression(
-                        undefined,
-                        this.placement,
-                        this.staffNumber,
-                        currentMeasure,
-                        this.activeInstantaneousDynamic,
-                        stringTrimmed);
-                if (this.openContinuousDynamicExpression !== undefined && !this.openContinuousDynamicExpression.EndMultiExpression) {
-                    this.closeOpenContinuousDynamic();
-                }
-                if (this.activeInstantaneousDynamic !== undefined && this.activeInstantaneousDynamic.StaffNumber === continuousDynamicExpression.StaffNumber) {
-                    this.activeInstantaneousDynamic = undefined;
-                }
-                this.openContinuousDynamicExpression = continuousDynamicExpression;
-                continuousDynamicExpression.StartMultiExpression = this.getMultiExpression;
-                this.getMultiExpression.addExpression(continuousDynamicExpression, prefix);
-                return true;
+            if (this.activeInstantaneousDynamic !== undefined && this.activeInstantaneousDynamic.StaffNumber === continuousDynamicExpression.StaffNumber) {
+                this.activeInstantaneousDynamic = undefined;
             }
+            this.openContinuousDynamicExpression = continuousDynamicExpression;
+            continuousDynamicExpression.StartMultiExpression = this.getMultiExpression;
+            this.getMultiExpression.addExpression(continuousDynamicExpression, prefix);
+            return true;
         }
         if (MoodExpression.isInputStringMood(stringTrimmed)) {
             this.createNewMultiExpressionIfNeeded(currentMeasure);

+ 16 - 1
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -154,7 +154,8 @@ export class VoiceGenerator {
               parentStaffEntry: SourceStaffEntry, parentMeasure: SourceMeasure,
               measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction, chord: boolean, octavePlusOne: boolean,
               printObject: boolean, isCueNote: boolean, isGraceNote: boolean, stemDirectionXml: StemDirectionType, tremoloStrokes: number,
-              stemColorXml: string, noteheadColorXml: string): Note {
+              stemColorXml: string, noteheadColorXml: string,
+              dotsXml: number): Note {
     this.currentStaffEntry = parentStaffEntry;
     this.currentMeasure = parentMeasure;
     //log.debug("read called:", restNote);
@@ -164,6 +165,7 @@ export class VoiceGenerator {
         ? this.addRestNote(noteNode.element("rest"), noteDuration, noteTypeXml, normalNotes, printObject, isCueNote, noteheadColorXml)
         : this.addSingleNote(noteNode, noteDuration, noteTypeXml, typeDuration, normalNotes, chord, octavePlusOne,
                              printObject, isCueNote, isGraceNote, stemDirectionXml, tremoloStrokes, stemColorXml, noteheadColorXml);
+      this.currentNote.DotsXml = dotsXml;
       // read lyrics
       const lyricElements: IXmlElement[] = noteNode.elements("lyric");
       if (this.lyricsReader !== undefined && lyricElements) {
@@ -273,10 +275,12 @@ export class VoiceGenerator {
         this.handleTimeModificationNode(noteNode);
       }
     } catch (err) {
+      log.warn(err);
       const errorMsg: string = ITextTranslation.translateText(
         "ReaderErrorMessages/NoteError", "Ignored erroneous Note."
       );
       this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
+      this.musicSheet.SheetErrors.pushMeasureError(err);
     }
 
     return this.currentNote;
@@ -427,8 +431,19 @@ export class VoiceGenerator {
           accidentalValue = noteElement.value;
           if (accidentalValue === "natural") {
             noteAccidental = AccidentalEnum.NATURAL;
+            // following accidentals: ambiguous in alter value
           } else if (accidentalValue === "slash-flat") {
             noteAccidental = AccidentalEnum.SLASHFLAT;
+          } else if (accidentalValue === "slash-quarter-sharp") {
+            noteAccidental = AccidentalEnum.SLASHQUARTERSHARP;
+          } else if (accidentalValue === "slash-sharp") {
+            noteAccidental = AccidentalEnum.SLASHSHARP;
+          } else if (accidentalValue === "double-slash-flat") {
+            noteAccidental = AccidentalEnum.DOUBLESLASHFLAT;
+          } else if (accidentalValue === "sori") {
+            noteAccidental = AccidentalEnum.SORI;
+          } else if (accidentalValue === "koron") {
+            noteAccidental = AccidentalEnum.KORON;
           }
         } else if (noteElement.name === "unpitched") {
           const displayStepElement: IXmlElement = noteElement.element("display-step");

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

@@ -49,6 +49,7 @@ export class Note {
     private typeLength: Fraction;
     /** The NoteType given in the XML, e.g. quarter, which can be a normal quarter or tuplet quarter -> can have different length/fraction */
     private noteTypeXml: NoteType;
+    public DotsXml: number;
     /** The amount of notes the tuplet of this note (if there is one) replaces. */
     private normalNotes: number;
     private isRestFlag: boolean;

+ 174 - 0
test/data/test_chord_symbols_collision_high_notes_alignment.musicxml

@@ -0,0 +1,174 @@
+<?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">
+  <work>
+    <work-title>Title</work-title>
+    </work>
+  <identification>
+    <creator type="composer">Composer</creator>
+    <encoding>
+      <software>MuseScore 3.6.2</software>
+      <encoding-date>2021-11-11</encoding-date>
+      <supports element="accidental" type="yes"/>
+      <supports element="beam" type="yes"/>
+      <supports element="print" attribute="new-page" type="yes" value="yes"/>
+      <supports element="print" attribute="new-system" type="yes" value="yes"/>
+      <supports element="stem" type="yes"/>
+      </encoding>
+    </identification>
+  <defaults>
+    <scaling>
+      <millimeters>6.99911</millimeters>
+      <tenths>40</tenths>
+      </scaling>
+    <page-layout>
+      <page-height>1696.94</page-height>
+      <page-width>1200.48</page-width>
+      <page-margins type="even">
+        <left-margin>85.7252</left-margin>
+        <right-margin>85.7252</right-margin>
+        <top-margin>85.7252</top-margin>
+        <bottom-margin>85.7252</bottom-margin>
+        </page-margins>
+      <page-margins type="odd">
+        <left-margin>85.7252</left-margin>
+        <right-margin>85.7252</right-margin>
+        <top-margin>85.7252</top-margin>
+        <bottom-margin>85.7252</bottom-margin>
+        </page-margins>
+      </page-layout>
+    <word-font font-family="Edwin" font-size="10"/>
+    <lyric-font font-family="Edwin" font-size="10"/>
+    </defaults>
+  <part-list>
+    <score-part id="P1">
+      <part-name>Piano</part-name>
+      <part-abbreviation>Pno.</part-abbreviation>
+      <score-instrument id="P1-I1">
+        <instrument-name>Piano</instrument-name>
+        </score-instrument>
+      <midi-device id="P1-I1" port="1"></midi-device>
+      <midi-instrument id="P1-I1">
+        <midi-channel>1</midi-channel>
+        <midi-program>1</midi-program>
+        <volume>78.7402</volume>
+        <pan>0</pan>
+        </midi-instrument>
+      </score-part>
+    </part-list>
+  <part id="P1">
+    <measure number="1" width="317.05">
+      <print>
+        <system-layout>
+          <system-margins>
+            <left-margin>50.00</left-margin>
+            <right-margin>0.00</right-margin>
+            </system-margins>
+          <top-system-distance>170.00</top-system-distance>
+          </system-layout>
+        </print>
+      <attributes>
+        <divisions>1</divisions>
+        <key>
+          <fifths>0</fifths>
+          </key>
+        <time>
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+          </time>
+        <clef>
+          <sign>G</sign>
+          <line>2</line>
+          </clef>
+        </attributes>
+      <harmony print-frame="no">
+        <root>
+          <root-step>A</root-step>
+          </root>
+        <kind text="7">dominant</kind>
+        </harmony>
+      <note default-x="80.72" default-y="10.00">
+        <pitch>
+          <step>A</step>
+          <octave>5</octave>
+          </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem>down</stem>
+        </note>
+      <harmony print-frame="no">
+        <root>
+          <root-step>B</root-step>
+          </root>
+        <kind text="7">dominant</kind>
+        </harmony>
+      <note default-x="197.99" default-y="30.00">
+        <pitch>
+          <step>E</step>
+          <octave>6</octave>
+          </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <stem>down</stem>
+        </note>
+      </measure>
+    <measure number="2" width="222.63">
+      <harmony print-frame="no">
+        <root>
+          <root-step>A</root-step>
+          </root>
+        <kind text="7">dominant</kind>
+        </harmony>
+      <note default-x="25.42" default-y="20.00">
+        <pitch>
+          <step>C</step>
+          <alter>1</alter>
+          <octave>6</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+        <accidental>sharp</accidental>
+        </note>
+      </measure>
+    <measure number="3" width="216.46">
+      <harmony print-frame="no">
+        <root>
+          <root-step>A</root-step>
+          </root>
+        <kind text="7">dominant</kind>
+        </harmony>
+      <note default-x="16.50" default-y="30.00">
+        <pitch>
+          <step>E</step>
+          <octave>6</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+        </note>
+      </measure>
+    <measure number="4" width="222.56">
+      <harmony print-frame="no">
+        <root>
+          <root-step>A</root-step>
+          </root>
+        <kind text="7">dominant</kind>
+        </harmony>
+      <note default-x="16.50" default-y="40.00">
+        <pitch>
+          <step>G</step>
+          <octave>6</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+        </note>
+      <barline location="right">
+        <bar-style>light-heavy</bar-style>
+        </barline>
+      </measure>
+    </part>
+  </score-partwise>

+ 197 - 0
test/data/test_fingering_Simple_Chords_Treble_Bass.musicxml

@@ -0,0 +1,197 @@
+<?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">
+  <work>
+    <work-title>Fingerings_Simple_Chords_Treble_Bass</work-title>
+    </work>
+  <identification>
+    <encoding>
+      <software>MuseScore 3.6.2</software>
+      <encoding-date>2021-11-10</encoding-date>
+      <supports element="accidental" type="yes"/>
+      <supports element="beam" type="yes"/>
+      <supports element="print" attribute="new-page" type="yes" value="yes"/>
+      <supports element="print" attribute="new-system" type="yes" value="yes"/>
+      <supports element="stem" type="yes"/>
+      </encoding>
+    </identification>
+  <defaults>
+    <scaling>
+      <millimeters>7</millimeters>
+      <tenths>40</tenths>
+      </scaling>
+    <page-layout>
+      <page-height>1697.14</page-height>
+      <page-width>1200</page-width>
+      <page-margins type="even">
+        <left-margin>85.7143</left-margin>
+        <right-margin>85.7143</right-margin>
+        <top-margin>85.7143</top-margin>
+        <bottom-margin>85.7143</bottom-margin>
+        </page-margins>
+      <page-margins type="odd">
+        <left-margin>85.7143</left-margin>
+        <right-margin>85.7143</right-margin>
+        <top-margin>85.7143</top-margin>
+        <bottom-margin>85.7143</bottom-margin>
+        </page-margins>
+      </page-layout>
+    <word-font font-family="Edwin" font-size="10"/>
+    <lyric-font font-family="Edwin" font-size="10"/>
+    </defaults>
+  <credit page="1">
+    <credit-type>title</credit-type>
+    <credit-words default-x="600" default-y="1611.43" justify="center" valign="top" font-size="22">Fingerings_Simple_Chords_Treble_Bass</credit-words>
+    </credit>
+  <part-list>
+    <score-part id="P1">
+      <part-name>Piano</part-name>
+      <part-abbreviation>Pno.</part-abbreviation>
+      <score-instrument id="P1-I1">
+        <instrument-name>Piano</instrument-name>
+        </score-instrument>
+      <midi-device id="P1-I1" port="1"></midi-device>
+      <midi-instrument id="P1-I1">
+        <midi-channel>1</midi-channel>
+        <midi-program>1</midi-program>
+        <volume>78.7402</volume>
+        <pan>0</pan>
+        </midi-instrument>
+      </score-part>
+    </part-list>
+  <part id="P1">
+    <measure number="1" width="334.90">
+      <print>
+        <system-layout>
+          <system-margins>
+            <left-margin>65.90</left-margin>
+            <right-margin>627.77</right-margin>
+            </system-margins>
+          <top-system-distance>172.37</top-system-distance>
+          </system-layout>
+        <staff-layout number="2">
+          <staff-distance>65.00</staff-distance>
+          </staff-layout>
+        </print>
+      <attributes>
+        <divisions>1</divisions>
+        <key>
+          <fifths>0</fifths>
+          </key>
+        <time>
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+          </time>
+        <staves>2</staves>
+        <clef number="1">
+          <sign>G</sign>
+          <line>2</line>
+          </clef>
+        <clef number="2">
+          <sign>F</sign>
+          <line>4</line>
+          </clef>
+        </attributes>
+      <note default-x="86.99" default-y="-5.00">
+        <pitch>
+          <step>E</step>
+          <octave>5</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+        <staff>1</staff>
+        <notations>
+          <technical>
+            <fingering>1</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note default-x="86.99" default-y="5.00">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <octave>5</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+        <staff>1</staff>
+        <notations>
+          <technical>
+            <fingering>3</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note default-x="86.99" default-y="20.00">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <octave>6</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>1</voice>
+        <type>whole</type>
+        <staff>1</staff>
+        <notations>
+          <technical>
+            <fingering>5</fingering>
+            </technical>
+          </notations>
+        </note>
+      <backup>
+        <duration>4</duration>
+        </backup>
+      <note default-x="86.99" default-y="-165.00">
+        <pitch>
+          <step>C</step>
+          <octave>2</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>5</voice>
+        <type>whole</type>
+        <staff>2</staff>
+        <notations>
+          <technical>
+            <fingering placement="below">4</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note default-x="86.99" default-y="-155.00">
+        <chord/>
+        <pitch>
+          <step>E</step>
+          <octave>2</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>5</voice>
+        <type>whole</type>
+        <staff>2</staff>
+        <notations>
+          <technical>
+            <fingering placement="below">2</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note default-x="86.99" default-y="-145.00">
+        <chord/>
+        <pitch>
+          <step>G</step>
+          <octave>2</octave>
+          </pitch>
+        <duration>4</duration>
+        <voice>5</voice>
+        <type>whole</type>
+        <staff>2</staff>
+        <notations>
+          <technical>
+            <fingering placement="below">1</fingering>
+            </technical>
+          </notations>
+        </note>
+      <barline location="right">
+        <bar-style>light-heavy</bar-style>
+        </barline>
+      </measure>
+    </part>
+  </score-partwise>

+ 203 - 0
test/data/test_fingering_articulation_collision.musicxml

@@ -0,0 +1,203 @@
+<?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">
+  <work>
+    <work-title>test_fingering_articulation_collision</work-title>
+    </work>
+  <identification>
+    <encoding>
+      <software>MuseScore 3.6.2</software>
+      <encoding-date>2021-11-11</encoding-date>
+      <supports element="accidental" type="yes"/>
+      <supports element="beam" type="yes"/>
+      <supports element="print" attribute="new-page" type="yes" value="yes"/>
+      <supports element="print" attribute="new-system" type="yes" value="yes"/>
+      <supports element="stem" type="yes"/>
+      </encoding>
+    </identification>
+  <defaults>
+    <scaling>
+      <millimeters>7</millimeters>
+      <tenths>40</tenths>
+      </scaling>
+    <page-layout>
+      <page-height>1697.14</page-height>
+      <page-width>1200</page-width>
+      <page-margins type="even">
+        <left-margin>85.7143</left-margin>
+        <right-margin>85.7143</right-margin>
+        <top-margin>85.7143</top-margin>
+        <bottom-margin>85.7143</bottom-margin>
+        </page-margins>
+      <page-margins type="odd">
+        <left-margin>85.7143</left-margin>
+        <right-margin>85.7143</right-margin>
+        <top-margin>85.7143</top-margin>
+        <bottom-margin>85.7143</bottom-margin>
+        </page-margins>
+      </page-layout>
+    <word-font font-family="Edwin" font-size="10"/>
+    <lyric-font font-family="Edwin" font-size="10"/>
+    </defaults>
+  <credit page="1">
+    <credit-type>title</credit-type>
+    <credit-words default-x="600" default-y="1611.43" justify="center" valign="top" font-size="22">test_fingering_articulation_collision</credit-words>
+    </credit>
+  <part-list>
+    <score-part id="P1">
+      <part-name>Piano</part-name>
+      <part-abbreviation>Pno.</part-abbreviation>
+      <score-instrument id="P1-I1">
+        <instrument-name>Piano</instrument-name>
+        </score-instrument>
+      <midi-device id="P1-I1" port="1"></midi-device>
+      <midi-instrument id="P1-I1">
+        <midi-channel>1</midi-channel>
+        <midi-program>1</midi-program>
+        <volume>78.7402</volume>
+        <pan>0</pan>
+        </midi-instrument>
+      </score-part>
+    </part-list>
+  <part id="P1">
+    <measure number="1" width="400.35">
+      <print>
+        <system-layout>
+          <system-margins>
+            <left-margin>65.90</left-margin>
+            <right-margin>562.32</right-margin>
+            </system-margins>
+          <top-system-distance>170.00</top-system-distance>
+          </system-layout>
+        <staff-layout number="2">
+          <staff-distance>65.00</staff-distance>
+          </staff-layout>
+        </print>
+      <attributes>
+        <divisions>1</divisions>
+        <key>
+          <fifths>0</fifths>
+          </key>
+        <time>
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+          </time>
+        <staves>2</staves>
+        <clef number="1">
+          <sign>G</sign>
+          <line>2</line>
+          </clef>
+        <clef number="2">
+          <sign>F</sign>
+          <line>4</line>
+          </clef>
+        </attributes>
+      <note default-x="86.99" default-y="-25.00">
+        <pitch>
+          <step>A</step>
+          <octave>4</octave>
+          </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>down</stem>
+        <staff>1</staff>
+        <notations>
+          <articulations>
+            <accent/>
+            </articulations>
+          <technical>
+            <fingering>1</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note default-x="86.99" default-y="10.00">
+        <chord/>
+        <pitch>
+          <step>A</step>
+          <octave>5</octave>
+          </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <stem>down</stem>
+        <staff>1</staff>
+        <notations>
+          <technical>
+            <fingering>5</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note>
+        <rest/>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+        <staff>1</staff>
+        </note>
+      <note>
+        <rest/>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>half</type>
+        <staff>1</staff>
+        </note>
+      <backup>
+        <duration>4</duration>
+        </backup>
+      <note default-x="86.99" default-y="-165.00">
+        <pitch>
+          <step>C</step>
+          <octave>2</octave>
+          </pitch>
+        <duration>1</duration>
+        <voice>5</voice>
+        <type>quarter</type>
+        <stem>up</stem>
+        <staff>2</staff>
+        <notations>
+          <articulations>
+            <accent/>
+            </articulations>
+          <technical>
+            <fingering placement="below">5</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note default-x="86.99" default-y="-130.00">
+        <chord/>
+        <pitch>
+          <step>C</step>
+          <octave>3</octave>
+          </pitch>
+        <duration>1</duration>
+        <voice>5</voice>
+        <type>quarter</type>
+        <stem>up</stem>
+        <staff>2</staff>
+        <notations>
+          <technical>
+            <fingering placement="below">1</fingering>
+            </technical>
+          </notations>
+        </note>
+      <note>
+        <rest/>
+        <duration>1</duration>
+        <voice>5</voice>
+        <type>quarter</type>
+        <staff>2</staff>
+        </note>
+      <note>
+        <rest/>
+        <duration>2</duration>
+        <voice>5</voice>
+        <type>half</type>
+        <staff>2</staff>
+        </note>
+      <barline location="right">
+        <bar-style>light-heavy</bar-style>
+        </barline>
+      </measure>
+    </part>
+  </score-partwise>