Преглед изворни кода

fix(MetronomeMark): render correct beat unit (e.g. half instead of quarter). fix #828

sschmid пре 4 година
родитељ
комит
b2fb539f80

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

@@ -49,6 +49,8 @@ import { AlignRestOption } from "../../../OpenSheetMusicDisplay";
 import { VexFlowStaffLine } from "./VexFlowStaffLine";
 import { EngravingRules } from "../EngravingRules";
 import { VexflowStafflineNoteCalculator } from "./VexflowStafflineNoteCalculator";
+import { NoteTypeHandler } from "../../VoiceData/NoteType";
+import { VexFlowConverter } from "./VexFlowConverter";
 
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
   /** space needed for a dash for lyrics spacing, calculated once */
@@ -576,12 +578,17 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
   protected createMetronomeMark(metronomeExpression: InstantaneousTempoExpression): void {
     const vfStave: Vex.Flow.Stave = (this.graphicalMusicSheet.MeasureList[0][0] as VexFlowMeasure).getVFStave();
     //vfStave.addModifier(new Vex.Flow.StaveTempo( // needs Vexflow PR
+    let vexflowDuration: string = "q";
+    if (metronomeExpression.beatUnit) {
+      const duration: Fraction = NoteTypeHandler.getNoteDurationFromType(metronomeExpression.beatUnit);
+      vexflowDuration = VexFlowConverter.duration(duration, false);
+    }
+    // const noteType: NoteType = NoteTypeHandler.StringToNoteType(metronomeExpression.beatUnit);
     vfStave.setTempo(
       {
           bpm: metronomeExpression.TempoInBpm,
           dots: metronomeExpression.dotted,
-          //duration: metronomeExpression.beatUnit
-          duration: "q"
+          duration: vexflowDuration
       },
       this.rules.MetronomeMarkYShift * unitInPixels);
        // -50, -30), 0); //needs Vexflow PR

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

@@ -768,7 +768,7 @@ export class InstrumentReader {
     const typeNode: IXmlElement = xmlNode.element("type");
     if (typeNode) {
       const type: string = typeNode.value;
-      return this.currentVoiceGenerator.getNoteDurationFromType(type);
+      return NoteTypeHandler.getNoteDurationFromType(type);
     }
     return new Fraction(0, 4 * this.divisions);
   }

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

@@ -158,6 +158,7 @@ export class ExpressionReader {
         let dirContentNode: IXmlElement = dirNode.element("metronome");
         if (dirContentNode) {
             const beatUnit: IXmlElement = dirContentNode.element("beat-unit");
+            // TODO check second "beat-unit", e.g. quarter = half
             const dotted: boolean = dirContentNode.element("beat-unit-dot") !== undefined;
             const bpm: IXmlElement = dirContentNode.element("per-minute");
             // TODO check print-object = false -> don't render invisible metronome mark

+ 2 - 47
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -27,7 +27,7 @@ import { ArticulationReader } from "./MusicSymbolModules/ArticulationReader";
 import { SlurReader } from "./MusicSymbolModules/SlurReader";
 import { Notehead } from "../VoiceData/Notehead";
 import { Arpeggio, ArpeggioType } from "../VoiceData/Arpeggio";
-import { NoteType } from "../VoiceData/NoteType";
+import { NoteType, NoteTypeHandler } from "../VoiceData/NoteType";
 import { TabNote } from "../VoiceData/TabNote";
 
 export class VoiceGenerator {
@@ -267,51 +267,6 @@ export class VoiceGenerator {
     return this.currentVoiceEntry !== undefined;
   }
 
-  /**
-   *
-   * @param type
-   * @returns {Fraction} - a Note's Duration from a given type (type must be valid).
-   */
-  public getNoteDurationFromType(type: string): Fraction {
-    switch (type) {
-      case "1024th":
-        return new Fraction(1, 1024);
-      case "512th":
-        return new Fraction(1, 512);
-      case "256th":
-        return new Fraction(1, 256);
-      case "128th":
-        return new Fraction(1, 128);
-      case "64th":
-        return new Fraction(1, 64);
-      case "32th":
-      case "32nd":
-        return new Fraction(1, 32);
-      case "16th":
-        return new Fraction(1, 16);
-      case "eighth":
-        return new Fraction(1, 8);
-      case "quarter":
-        return new Fraction(1, 4);
-      case "half":
-        return new Fraction(1, 2);
-      case "whole":
-        return new Fraction(1, 1);
-      case "breve":
-        return new Fraction(2, 1);
-      case "long":
-        return new Fraction(4, 1);
-      case "maxima":
-        return new Fraction(8, 1);
-      default: {
-        const errorMsg: string = ITextTranslation.translateText(
-          "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
-        );
-        throw new MusicSheetReadingException(errorMsg);
-      }
-    }
-  }
-
   private readArticulations(notationNode: IXmlElement, currentVoiceEntry: VoiceEntry): void {
     const articNode: IXmlElement = notationNode.element("articulations");
     if (articNode) {
@@ -894,7 +849,7 @@ export class VoiceGenerator {
       if (typeNode) {
         const type: string = typeNode.value;
         try {
-          return this.getNoteDurationFromType(type);
+          return NoteTypeHandler.getNoteDurationFromType(type);
         } catch (e) {
           const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid note duration.");
           this.musicSheet.SheetErrors.pushMeasureError(errorMsg);

+ 49 - 0
src/MusicalScore/VoiceData/NoteType.ts

@@ -1,3 +1,7 @@
+import { Fraction } from "../../Common/DataObjects/Fraction";
+import { ITextTranslation } from "../Interfaces/ITextTranslation";
+import { MusicSheetReadingException } from "../Exceptions";
+
 export enum NoteType {
     // xml note types, e.g. given as <note><type>quarter, see:
     //https://usermanuals.musicxml.com/MusicXML/Content/ST-MusicXML-note-type-value.htm
@@ -36,4 +40,49 @@ export class NoteTypeHandler {
         const indexInArray: number = this.NoteTypeXmlValues.indexOf(noteType);
         return indexInArray !== -1 ? indexInArray : NoteType.UNDEFINED;
     }
+
+        /**
+         *
+         * @param type
+         * @returns {Fraction} - a Note's Duration from a given type (type must be valid).
+         */
+    public static getNoteDurationFromType(type: string): Fraction {
+        switch (type) {
+            case "1024th":
+                return new Fraction(1, 1024);
+            case "512th":
+                return new Fraction(1, 512);
+            case "256th":
+                return new Fraction(1, 256);
+            case "128th":
+                return new Fraction(1, 128);
+            case "64th":
+                return new Fraction(1, 64);
+            case "32th":
+            case "32nd":
+                return new Fraction(1, 32);
+            case "16th":
+                return new Fraction(1, 16);
+            case "eighth":
+                return new Fraction(1, 8);
+            case "quarter":
+                return new Fraction(1, 4);
+            case "half":
+                return new Fraction(1, 2);
+            case "whole":
+                return new Fraction(1, 1);
+            case "breve":
+                return new Fraction(2, 1);
+            case "long":
+                return new Fraction(4, 1);
+            case "maxima":
+                return new Fraction(8, 1);
+            default: {
+                const errorMsg: string = ITextTranslation.translateText(
+                "ReaderErrorMessages/NoteDurationError", "Invalid note duration."
+                );
+                throw new MusicSheetReadingException(errorMsg);
+            }
+        }
+    }
 }