Browse Source

feat(GraceNotes): grace notes display w/o layouting, add function tests to demo

start of grace notes implementation
multiple grace notes still get squashed into a chord
because of missing x-layouting. could be closer to next notes as well

demo now has OSMD function test xmls (ornaments, grace notes, slurs, etc)

part of #293
sschmidTU 7 năm trước cách đây
mục cha
commit
3412e9a49d

+ 8 - 0
external/vexflow/vexflow.d.ts

@@ -107,6 +107,14 @@ declare namespace Vex {
             public addDotToAll(): void;
         }
 
+        export class GraceNote extends StaveNote {
+            constructor(note_struct: any);
+        }
+
+        export class GraceNoteGroup extends Modifier {
+            constructor(grace_notes: [GraceNote], show_slur: boolean);
+        }
+
         export class StaveTie {
             constructor(notes_struct: any);
 

+ 8 - 2
src/MusicalScore/Graphical/VexFlow/VexFlowConverter.ts

@@ -201,13 +201,19 @@ export class VexFlowConverter {
             duration += "d";
         }
 
-        const vfnote: Vex.Flow.StaveNote = new Vex.Flow.StaveNote({
+        let vfnote: Vex.Flow.StaveNote;
+        const vfnoteStruct: Object = {
             align_center: alignCenter,
             auto_stem: true,
             clef: vfClefType,
             duration: duration,
             keys: keys
-        });
+        };
+        if (!gve.parentVoiceEntry.IsGrace) {
+            vfnote = new Vex.Flow.StaveNote(vfnoteStruct);
+        } else {
+            vfnote = new Vex.Flow.GraceNote(vfnoteStruct);
+        }
 
         vfnote.x_shift = xShift;
 

+ 12 - 14
src/MusicalScore/ScoreIO/InstrumentReader.ts

@@ -192,6 +192,8 @@ export class InstrumentReader {
                 }
               }
             }
+
+            noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
           }
 
           let musicTimestamp: Fraction = currentFraction.clone();
@@ -208,6 +210,7 @@ export class InstrumentReader {
           if (!this.currentVoiceGenerator.hasVoiceEntry()
             || (!isChord && !isGraceNote && !lastNoteWasGrace)
             || (isGraceNote && !lastNoteWasGrace)
+            || (!isGraceNote && lastNoteWasGrace)
           ) {
             this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote, isGraceNote, graceNoteSlash);
           }
@@ -237,21 +240,16 @@ export class InstrumentReader {
           if (this.activeRhythm !== undefined) {
             // (*) this.musicSheet.SheetPlaybackSetting.Rhythm = this.activeRhythm.Rhythm;
           }
-          if (isTuplet) {
-            this.currentVoiceGenerator.read(
-              xmlNode, noteDuration, restNote,
-              this.currentStaffEntry, this.currentMeasure,
-              measureStartAbsoluteTimestamp,
-              this.maxTieNoteFraction, isChord, guitarPro
-            );
-          } else {
-            this.currentVoiceGenerator.read(
-              xmlNode, new Fraction(noteDivisions, 4 * this.divisions),
-              restNote, this.currentStaffEntry,
-              this.currentMeasure, measureStartAbsoluteTimestamp,
-              this.maxTieNoteFraction, isChord, guitarPro
-            );
+          if (!isTuplet && !isGraceNote) {
+            noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
           }
+          this.currentVoiceGenerator.read(
+            xmlNode, noteDuration, restNote,
+            this.currentStaffEntry, this.currentMeasure,
+            measureStartAbsoluteTimestamp,
+            this.maxTieNoteFraction, isChord, guitarPro
+          );
+
           const notationsNode: IXmlElement = xmlNode.element("notations");
           if (notationsNode !== undefined && notationsNode.element("dynamics") !== undefined) {
             // (*) let expressionReader: ExpressionReader = this.expressionReaders[this.readExpressionStaffNumber(xmlNode) - 1];

BIN
test/data/OSMD_function_test_GraceNotes.mxl


BIN
test/data/OSMD_function_test_all.mxl