Browse Source

WIP: tremolos: read xml type duration, show correct beams.

part of #472.
goal is to display half note tremolos correctly.
sschmid 6 năm trước cách đây
mục cha
commit
fe5de25954

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

@@ -23,6 +23,7 @@ import { OrnamentEnum, OrnamentContainer } from "../../VoiceData/OrnamentContain
 import { Notehead, NoteHeadShape } from "../../VoiceData/Notehead";
 import { unitInPixels } from "./VexFlowMusicSheetDrawer";
 import { EngravingRules } from "../EngravingRules";
+import { Note } from "../..";
 
 /**
  * Helper class, which contains static methods which actually convert
@@ -171,6 +172,9 @@ export class VexFlowConverter {
         const frac: Fraction = baseNote.graphicalNoteLength;
         const isTuplet: boolean = baseNote.sourceNote.NoteTuplet !== undefined;
         let duration: string = VexFlowConverter.duration(frac, isTuplet);
+        if (baseNote.sourceNote.TypeLength !== undefined && baseNote.sourceNote.TypeLength !== frac) {
+            duration = VexFlowConverter.duration(baseNote.sourceNote.TypeLength, isTuplet);
+        }
         let vfClefType: string = undefined;
         let numDots: number = baseNote.numberOfDots;
         let alignCenter: boolean = false;
@@ -240,7 +244,8 @@ export class VexFlowConverter {
             slash: gve.parentVoiceEntry.GraceNoteSlash,
         };
 
-        if (gve.notes[0].sourceNote.IsCueNote) {
+        const firstNote: Note = gve.notes[0].sourceNote;
+        if (firstNote.IsCueNote) {
             (<any>vfnoteStruct).glyph_font_scale = Vex.Flow.DEFAULT_NOTATION_FONT_SCALE * Vex.Flow.GraceNote.SCALE;
             (<any>vfnoteStruct).stroke_px = Vex.Flow.GraceNote.LEDGER_LINE_OFFSET;
         }
@@ -251,6 +256,16 @@ export class VexFlowConverter {
             vfnote = new Vex.Flow.StaveNote(vfnoteStruct);
         }
 
+        console.log("length: " + firstNote.Length.RealValue);
+        if (firstNote.Length.RealValue === 0.25 && firstNote.Notehead && firstNote.Notehead.Filled === false) {
+            /*for (const noteHead in vfnote.note_heads) {
+                (<any>noteHead).glyph_code = 'v81';
+            }*/
+            console.log("here");
+            (<any>vfnote).glyph.code = "v81";
+            //(<any>vfnote).glyph.reset(); // TODO not a function
+        }
+
         if (EngravingRules.Rules.ColoringEnabled) {
             const defaultColorStem: string = EngravingRules.Rules.DefaultColorStem;
             let stemColor: string = gve.parentVoiceEntry.StemColor;

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

@@ -563,7 +563,9 @@ export class VexFlowMeasure extends GraphicalMeasure {
                 for (const beam of this.beams[voiceID]) {
                     let beamHasQuarterNoteOrLonger: boolean = false;
                     for (const note of beam[0].Notes) {
-                        if (note.Length.RealValue >= new Fraction(1, 4).RealValue) {
+                        if (note.Length.RealValue >= new Fraction(1, 4).RealValue
+                            // check whether the note has a TypeLength that's also not suitable for a beam (bigger than an eigth)
+                            && (note.TypeLength === undefined || note.TypeLength.RealValue > 0.125)) {
                             beamHasQuarterNoteOrLonger = true;
                             break;
                         }

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

@@ -164,6 +164,7 @@ export class InstrumentReader {
           }
           let noteDivisions: number = 0;
           let noteDuration: Fraction = new Fraction(0, 1);
+          let typeDuration: Fraction = undefined;
           let isTuplet: boolean = false;
           if (xmlNode.element("duration") !== undefined) {
             noteDivisions = parseInt(xmlNode.element("duration").value, 10);
@@ -171,6 +172,8 @@ export class InstrumentReader {
               noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
               if (noteDivisions === 0) {
                 noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
+              } else {
+                typeDuration = this.getNoteDurationFromTypeNode(xmlNode);
               }
               if (xmlNode.element("time-modification") !== undefined) {
                 noteDuration = this.getNoteDurationForTuplet(xmlNode);
@@ -329,7 +332,7 @@ export class InstrumentReader {
             noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
           }
           this.currentVoiceGenerator.read(
-            xmlNode, noteDuration, restNote,
+            xmlNode, noteDuration, typeDuration, restNote,
             this.currentStaffEntry, this.currentMeasure,
             measureStartAbsoluteTimestamp,
             this.maxTieNoteFraction, isChord, guitarPro,

+ 5 - 4
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -103,7 +103,7 @@ export class VoiceGenerator {
    * @param printObject whether the note should be rendered (true) or invisible (false)
    * @returns {Note}
    */
-  public read(noteNode: IXmlElement, noteDuration: Fraction, restNote: boolean,
+  public read(noteNode: IXmlElement, noteDuration: Fraction, typeDuration: Fraction, restNote: boolean,
               parentStaffEntry: SourceStaffEntry, parentMeasure: SourceMeasure,
               measureStartAbsoluteTimestamp: Fraction, maxTieNoteFraction: Fraction, chord: boolean, guitarPro: boolean,
               printObject: boolean, isCueNote: boolean, stemDirectionXml: StemDirectionType,
@@ -114,7 +114,7 @@ export class VoiceGenerator {
     try {
       this.currentNote = restNote
         ? this.addRestNote(noteDuration, printObject, isCueNote, noteheadColorXml)
-        : this.addSingleNote(noteNode, noteDuration, chord, guitarPro,
+        : this.addSingleNote(noteNode, noteDuration, typeDuration, chord, guitarPro,
                              printObject, isCueNote, stemDirectionXml, stemColorXml, noteheadColorXml);
       // read lyrics
       const lyricElements: IXmlElement[] = noteNode.elements("lyric");
@@ -322,7 +322,7 @@ export class VoiceGenerator {
    * @param guitarPro
    * @returns {Note}
    */
-  private addSingleNote(node: IXmlElement, noteDuration: Fraction, chord: boolean, guitarPro: boolean,
+  private addSingleNote(node: IXmlElement, noteDuration: Fraction, typeDuration: Fraction, chord: boolean, guitarPro: boolean,
                         printObject: boolean, isCueNote: boolean, stemDirectionXml: StemDirectionType,
                         stemColorXml: string, noteheadColorXml: string): Note {
     //log.debug("addSingleNote called");
@@ -416,10 +416,11 @@ export class VoiceGenerator {
     const pitch: Pitch = new Pitch(noteStep, noteOctave, noteAccidental);
     const noteLength: Fraction = Fraction.createFromFraction(noteDuration);
     const note: Note = new Note(this.currentVoiceEntry, this.currentStaffEntry, noteLength, pitch);
+    note.TypeLength = typeDuration;
     note.PrintObject = printObject;
     note.IsCueNote = isCueNote;
     note.StemDirectionXml = stemDirectionXml; // maybe unnecessary, also in VoiceEntry
-    if (noteheadShapeXml !== undefined && noteheadShapeXml !== "normal") {
+    if ((noteheadShapeXml !== undefined && noteheadShapeXml !== "normal") || noteheadFilledXml !== undefined) {
       note.Notehead = new Notehead(note, noteheadShapeXml, noteheadFilledXml);
     } // if normal, leave note head undefined to save processing/runtime
     note.NoteheadColorXml = noteheadColorXml; // color set in Xml, shouldn't be changed.

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

@@ -36,6 +36,8 @@ export class Note {
     private voiceEntry: VoiceEntry;
     private parentStaffEntry: SourceStaffEntry;
     private length: Fraction;
+    /** The length/duration given in the <type> tag. different from length for tuplets/tremolos. */
+    private typeLength: Fraction;
     /**
      * The untransposed (!!!) source data.
      */
@@ -90,6 +92,12 @@ export class Note {
     public set Length(value: Fraction) {
         this.length = value;
     }
+    public get TypeLength(): Fraction {
+        return this.typeLength;
+    }
+    public set TypeLength(value: Fraction) {
+        this.typeLength = value;
+    }
     public get Pitch(): Pitch {
         return this.pitch;
     }