Bladeren bron

refactor(GraceNotes): add grace notes as VFModifier instead of extra voices

still layouting issues: grace notes not on beat 1 get x-shifted
(however, skyline shows correct bounding boxes)
add OSMD test grace notes (bounding box) to demo
remove old grace note code (graceVoiceEntries[Before/After])

BREAKING CHANGE: grace notes appear where they shouldn't (x-shifted)

part of #293, #56
sschmidTU 7 jaren geleden
bovenliggende
commit
fc3fd3b360

+ 1 - 0
demo/index.js

@@ -8,6 +8,7 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
     var folder = process.env.STATIC_FILES_SUBFOLDER ? process.env.STATIC_FILES_SUBFOLDER + "/" : "",
     // The available demos
         demos = {
+            "OSMD Function Test - Grace Notes (BB)": "OSMD_function_test_GraceNotes_bb.mxl",
             "Beethoven - An die ferne Geliebte": "Beethoven_AnDieFerneGeliebte.xml",
             "M. Clementi - Sonatina Op.36 No.1 Pt.1": "MuzioClementi_SonatinaOpus36No1_Part1.xml",
             "M. Clementi - Sonatina Op.36 No.1 Pt.2": "MuzioClementi_SonatinaOpus36No1_Part2.xml",

+ 3 - 1
external/vexflow/vexflow.d.ts

@@ -78,6 +78,7 @@ declare namespace Vex {
             public setStemDirection(direction: number): StemmableNote;
             public x_shift: number;
             public getAbsoluteX(): number;
+            public addModifier(index: number, modifier: Modifier): StemmableNote;
         }
 
         export class GhostNote extends StemmableNote {
@@ -112,7 +113,8 @@ declare namespace Vex {
         }
 
         export class GraceNoteGroup extends Modifier {
-            constructor(grace_notes: [GraceNote], show_slur: boolean);
+            constructor(grace_notes: GraceNote[], show_slur: boolean);
+            public beamNotes(): GraceNoteGroup;
         }
 
         export class StaveTie {

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

@@ -977,27 +977,6 @@ export abstract class MusicSheetCalculator {
         return octaveShiftValue;
     }
 
-    protected handleVoiceEntryGraceNotes(graceEntries: VoiceEntry[], graphicalGraceEntries: GraphicalStaffEntry[], graphicalStaffEntry: GraphicalStaffEntry,
-                                         accidentalCalculator: AccidentalCalculator, activeClef: ClefInstruction,
-                                         octaveShiftValue: OctaveEnum, lyricWords: LyricWord[],
-                                         tuplets: Tuplet[], beams: Beam[]): void {
-        if (graceEntries !== undefined) {
-            for (let idx: number = 0, len: number = graceEntries.length; idx < len; ++idx) {
-                const graceVoiceEntry: VoiceEntry = graceEntries[idx];
-                const graceStaffEntry: GraphicalStaffEntry = MusicSheetCalculator.symbolFactory.createGraceStaffEntry(
-                    graphicalStaffEntry,
-                    graphicalStaffEntry.parentMeasure
-                );
-                graphicalGraceEntries.push(graceStaffEntry);
-                this.handleVoiceEntry(
-                    graceVoiceEntry, graceStaffEntry, accidentalCalculator, lyricWords,
-                    activeClef, tuplets,
-                    beams, octaveShiftValue
-                );
-            }
-        }
-    }
-
     protected resetYPositionForLeadSheet(psi: BoundingBox): void {
         if (this.leadSheet) {
             psi.RelativePosition = new PointF2D(psi.RelativePosition.x, 0.0);
@@ -1397,11 +1376,6 @@ export abstract class MusicSheetCalculator {
                 }
                 for (let idx: number = 0, len: number = sourceStaffEntry.VoiceEntries.length; idx < len; ++idx) {
                     const voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[idx];
-                    this.handleVoiceEntryGraceNotes(
-                        voiceEntry.graceVoiceEntriesBefore, graphicalStaffEntry.graceStaffEntriesBefore, graphicalStaffEntry,
-                        accidentalCalculator, activeClefs[staffIndex], octaveShiftValue, openLyricWords,
-                        openTuplets, openBeams
-                    );
                     octaveShiftValue = this.handleVoiceEntry(
                         voiceEntry, graphicalStaffEntry,
                         accidentalCalculator, openLyricWords,
@@ -1409,11 +1383,6 @@ export abstract class MusicSheetCalculator {
                         openBeams, octaveShiftValue, linkedNotes,
                         sourceStaffEntry
                     );
-                    this.handleVoiceEntryGraceNotes(
-                        voiceEntry.graceVoiceEntriesAfter, graphicalStaffEntry.graceStaffEntriesAfter, graphicalStaffEntry,
-                        accidentalCalculator, activeClefs[staffIndex], octaveShiftValue, openLyricWords,
-                        openTuplets, openBeams
-                    );
                 }
                 if (sourceStaffEntry.Instructions.length > 0) {
                     const clefInstruction: ClefInstruction = <ClefInstruction>sourceStaffEntry.Instructions[0];

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

@@ -154,10 +154,6 @@ export class VexFlowConverter {
         // VexFlow needs the notes ordered vertically in the other direction:
         const notes: GraphicalNote[] = gve.notes.reverse();
         const baseNote: GraphicalNote = notes[0];
-        if (baseNote.sourceNote.Pitch === undefined &&
-            new Fraction(1, 2).lt(baseNote.sourceNote.Length)) {
-                // test
-            }
         let keys: string[] = [];
         const accidentals: string[] = [];
         const frac: Fraction = baseNote.graphicalNoteLength;

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

@@ -577,8 +577,26 @@ export class VexFlowMeasure extends GraphicalMeasure {
     public graphicalMeasureCreatedCalculations(): void {
         for (const graphicalStaffEntry of this.staffEntries as VexFlowStaffEntry[]) {
             // create vex flow Stave Notes:
+            let graceNotesSlur: boolean = false;
+            let graceGVoiceEntriesBefore: GraphicalVoiceEntry[] = [];
             for (const gve of graphicalStaffEntry.graphicalVoiceEntries) {
+                if (gve.parentVoiceEntry.IsGrace) {
+                    graceGVoiceEntriesBefore.push(gve);
+                    if (!graceNotesSlur) {
+                        graceNotesSlur = gve.parentVoiceEntry.hasSlur();
+                    }
+                    continue;
+                }
                 (gve as VexFlowVoiceEntry).vfStaveNote = VexFlowConverter.StaveNote(gve);
+                if (graceGVoiceEntriesBefore.length > 0) {
+                    const graceNotes: Vex.Flow.GraceNote[] = [];
+                    for (let i: number = 0; i < graceGVoiceEntriesBefore.length; i++) {
+                        graceNotes.push(VexFlowConverter.StaveNote(graceGVoiceEntriesBefore[i]));
+                    }
+                    const graceNoteGroup: Vex.Flow.GraceNoteGroup = new Vex.Flow.GraceNoteGroup(graceNotes, graceNotesSlur);
+                    (gve as VexFlowVoiceEntry).vfStaveNote.addModifier(0, graceNoteGroup.beamNotes());
+                    graceGVoiceEntriesBefore = [];
+                }
             }
         }
 
@@ -597,7 +615,14 @@ export class VexFlowMeasure extends GraphicalMeasure {
 
             const restFilledEntries: GraphicalVoiceEntry[] =  this.getRestFilledVexFlowStaveNotesPerVoice(voice);
             // create vex flow voices and add tickables to it:
+            //let graceGVoiceEntriesBefore: GraphicalVoiceEntry[] = [];
             for (const voiceEntry of restFilledEntries) {
+                if (!voiceEntry.parentVoiceEntry) {
+                    continue;
+                }
+                if (voiceEntry.parentVoiceEntry.IsGrace) {
+                    continue;
+                }
                 this.vfVoices[voice.VoiceId].addTickable((voiceEntry as VexFlowVoiceEntry).vfStaveNote);
             }
         }
@@ -611,6 +636,9 @@ export class VexFlowMeasure extends GraphicalMeasure {
             // create vex flow articulation:
             const graphicalVoiceEntries: GraphicalVoiceEntry[] = graphicalStaffEntry.graphicalVoiceEntries;
             for (const gve of graphicalVoiceEntries) {
+                if (gve.parentVoiceEntry.IsGrace) {
+                    continue;
+                }
                 const vfStaveNote: StaveNote = ((gve as VexFlowVoiceEntry).vfStaveNote as StaveNote);
                 VexFlowConverter.generateArticulations(vfStaveNote, gve.notes[0].sourceNote.ParentVoiceEntry.Articulations);
             }

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

@@ -19,6 +19,9 @@ export class VexFlowStaffEntry extends GraphicalStaffEntry {
         let tickablePosition: number = 0;
         let numberOfValidTickables: number = 0;
         for (const gve of this.graphicalVoiceEntries) {
+            if (gve.parentVoiceEntry.IsGrace) {
+                continue;
+            }
             const tickable: Vex.Flow.StemmableNote = (gve as VexFlowVoiceEntry).vfStaveNote;
             // This will let the tickable know how to calculate it's bounding box
             tickable.setStave(stave);

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

@@ -210,9 +210,10 @@ export class InstrumentReader {
           if (!this.currentVoiceGenerator.hasVoiceEntry()
             || (!isChord && !isGraceNote && !lastNoteWasGrace)
             || (isGraceNote && !lastNoteWasGrace)
+            || (isGraceNote && !isChord)
             || (!isGraceNote && lastNoteWasGrace)
           ) {
-            this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote, isGraceNote, graceNoteSlash);
+            this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote && !isGraceNote, isGraceNote, graceNoteSlash);
           }
           if (!isGraceNote && !isChord) {
             previousFraction = currentFraction.clone();

+ 0 - 3
src/MusicalScore/VoiceData/VoiceEntry.ts

@@ -32,9 +32,6 @@ export class VoiceEntry {
         this.graceNoteSlash = graceNoteSlash;
     }
 
-    public graceVoiceEntriesBefore: VoiceEntry[];
-    public graceVoiceEntriesAfter: VoiceEntry[];
-
     private parentVoice: Voice;
     private parentSourceStaffEntry: SourceStaffEntry;
     private timestamp: Fraction;

BIN
test/data/OSMD_function_test_GraceNotes_bb.mxl