Explorar o código

feat(Added instantanious expressions): Added new class, implemented drawing methods

Benjamin Giesinger %!s(int64=7) %!d(string=hai) anos
pai
achega
9d5a98c1cb

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

@@ -78,6 +78,14 @@ declare namespace Vex {
 
 
         }
         }
 
 
+        export class TextNote extends Note {
+            constructor(note_struct: any);
+            
+            public setContext(ctx: RenderContext): TextBracket;
+
+            public draw(): void;
+        }
+
         export class Stem {
         export class Stem {
             public static UP: number;
             public static UP: number;
             public static DOWN: number;
             public static DOWN: number;

+ 7 - 0
src/MusicalScore/Graphical/GraphicalInstantaniousDynamicExpression.ts

@@ -0,0 +1,7 @@
+import { GraphicalObject } from "./GraphicalObject";
+
+export class GraphicalInstantaniousDynamicExpression extends GraphicalObject {
+    constructor() {
+        super();
+    }
+}

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

@@ -10,6 +10,7 @@ import {MusicSheetCalculator} from "./MusicSheetCalculator";
  */
  */
 export class GraphicalLabel extends Clickable {
 export class GraphicalLabel extends Clickable {
     private label: Label;
     private label: Label;
+
     constructor(label: Label, textHeight: number, alignment: TextAlignment, parent: BoundingBox = undefined) {
     constructor(label: Label, textHeight: number, alignment: TextAlignment, parent: BoundingBox = undefined) {
         super();
         super();
         this.label = label;
         this.label = label;

+ 10 - 7
src/MusicalScore/Graphical/MusicSheetDrawer.ts

@@ -23,6 +23,7 @@ import {GraphicalMusicPage} from "./GraphicalMusicPage";
 import {Instrument} from "../Instrument";
 import {Instrument} from "../Instrument";
 import {MusicSymbolDrawingStyle, PhonicScoreModes} from "./DrawingMode";
 import {MusicSymbolDrawingStyle, PhonicScoreModes} from "./DrawingMode";
 import {GraphicalObject} from "./GraphicalObject";
 import {GraphicalObject} from "./GraphicalObject";
+import { GraphicalInstantaniousDynamicExpression } from "./GraphicalInstantaniousDynamicExpression";
 
 
 /**
 /**
  * Draw a [[GraphicalMusicSheet]] (through the .drawSheet method)
  * Draw a [[GraphicalMusicSheet]] (through the .drawSheet method)
@@ -339,6 +340,8 @@ export abstract class MusicSheetDrawer {
         }
         }
 
 
         this.drawOctaveShifts(staffLine);
         this.drawOctaveShifts(staffLine);
+
+        this.drawInstantaniousDynamic(staffLine);
     }
     }
 
 
     /**
     /**
@@ -375,13 +378,13 @@ export abstract class MusicSheetDrawer {
     //         drawLineAsVerticalRectangle(ending.Right, absolutePosition, <number>GraphicalLayers.Notes);
     //         drawLineAsVerticalRectangle(ending.Right, absolutePosition, <number>GraphicalLayers.Notes);
     //     this.drawLabel(ending.Label, <number>GraphicalLayers.Notes);
     //     this.drawLabel(ending.Label, <number>GraphicalLayers.Notes);
     // }
     // }
-    // protected drawInstantaniousDynamic(expression: GraphicalInstantaniousDynamicExpression): void {
-    //     expression.ExpressionSymbols.forEach(function (expressionSymbol) {
-    //         let position: PointF2D = expressionSymbol.PositionAndShape.AbsolutePosition;
-    //         let symbol: MusicSymbol = expressionSymbol.GetSymbol;
-    //         drawSymbol(symbol, MusicSymbolDrawingStyle.Normal, position);
-    //     });
-    // }
+    protected drawInstantaniousDynamic(staffline: StaffLine): void {
+        // expression.ExpressionSymbols.forEach(function (expressionSymbol) {
+        //     let position: PointF2D = expressionSymbol.PositionAndShape.AbsolutePosition;
+        //     let symbol: MusicSymbol = expressionSymbol.GetSymbol;
+        //     drawSymbol(symbol, MusicSymbolDrawingStyle.Normal, position);
+        // });
+    }
     // protected drawContinuousDynamic(expression: GraphicalContinuousDynamicExpression,
     // protected drawContinuousDynamic(expression: GraphicalContinuousDynamicExpression,
     //     absolute: PointF2D): void {
     //     absolute: PointF2D): void {
     //     throw new Error("not implemented");
     //     throw new Error("not implemented");

+ 36 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowInstantaniousDynamicExpression.ts

@@ -0,0 +1,36 @@
+import { GraphicalInstantaniousDynamicExpression } from "../GraphicalInstantaniousDynamicExpression";
+import { InstantaniousDynamicExpression, DynamicEnum } from "../../VoiceData/Expressions/InstantaniousDynamicExpression";
+import { GraphicalStaffEntry } from "../GraphicalStaffEntry";
+import { GraphicalLabel } from "../GraphicalLabel";
+import { Label } from "../../Label";
+import { TextAlignment } from "../../../Common/Enums/TextAlignment";
+import { EngravingRules } from "../EngravingRules";
+import { Fonts } from "../../../Common/Enums/Fonts";
+import { FontStyles } from "../../../Common/Enums/FontStyles";
+
+export class VexFlowInstantaniousDynamicExpression extends GraphicalInstantaniousDynamicExpression {
+    private mInstantaniousDynamicExpression: InstantaniousDynamicExpression;
+    private mLabel: GraphicalLabel;
+
+    constructor(instantaniousDynamicExpression: InstantaniousDynamicExpression, staffEntry: GraphicalStaffEntry) {
+        super();
+        this.mInstantaniousDynamicExpression = instantaniousDynamicExpression;
+        this.mLabel = new GraphicalLabel(new Label(this.Expression),
+                                         EngravingRules.Rules.ContinuousDynamicTextHeight,
+                                         TextAlignment.LeftTop,
+                                         staffEntry.PositionAndShape);
+        // FIXME: Add offset when skyline available
+        // const offset: number = staffEntry.parentMeasure.ParentStaffLine.SkyBottomCalculator ...
+        const offset: number = 5.5;
+        this.mLabel.PositionAndShape.RelativePosition.y += offset;
+        this.mLabel.Label.fontStyle = FontStyles.BoldItalic;
+    }
+
+    get Expression(): string {
+        return DynamicEnum[this.mInstantaniousDynamicExpression.DynEnum];
+    }
+
+    get Label(): GraphicalLabel {
+        return this.mLabel;
+    }
+}

+ 21 - 12
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -24,6 +24,7 @@ import {GraphicalVoiceEntry} from "../GraphicalVoiceEntry";
 import {VexFlowVoiceEntry} from "./VexFlowVoiceEntry";
 import {VexFlowVoiceEntry} from "./VexFlowVoiceEntry";
 import {Fraction} from "../../../Common/DataObjects/Fraction";
 import {Fraction} from "../../../Common/DataObjects/Fraction";
 import { Voice } from "../../VoiceData/Voice";
 import { Voice } from "../../VoiceData/Voice";
+import { VexFlowInstantaniousDynamicExpression } from "./VexFlowInstantaniousDynamicExpression";
 
 
 export class VexFlowMeasure extends StaffMeasure {
 export class VexFlowMeasure extends StaffMeasure {
     constructor(staff: Staff, staffLine: StaffLine = undefined, sourceMeasure: SourceMeasure = undefined) {
     constructor(staff: Staff, staffLine: StaffLine = undefined, sourceMeasure: SourceMeasure = undefined) {
@@ -32,28 +33,29 @@ export class VexFlowMeasure extends StaffMeasure {
         this.resetLayout();
         this.resetLayout();
     }
     }
 
 
-    // octaveOffset according to active clef
+    /** octaveOffset according to active clef */
     public octaveOffset: number = 3;
     public octaveOffset: number = 3;
-    // The VexFlow Voices in the measure
+    /** The VexFlow Voices in the measure */
     public vfVoices: { [voiceID: number]: Vex.Flow.Voice; } = {};
     public vfVoices: { [voiceID: number]: Vex.Flow.Voice; } = {};
-    // Call this function (if present) to x-format all the voices in the measure
+    /** Call this function (if present) to x-format all the voices in the measure */
     public formatVoices: (width: number) => void;
     public formatVoices: (width: number) => void;
-    // The VexFlow Ties in the measure
+    /** The VexFlow Ties in the measure */
     public vfTies: Vex.Flow.StaveTie[] = [];
     public vfTies: Vex.Flow.StaveTie[] = [];
-    // The repetition instructions given as words or symbols (coda, dal segno..)
+    /** The repetition instructions given as words or symbols (coda, dal segno..) */
     public vfRepetitionWords: Vex.Flow.Repetition[] = [];
     public vfRepetitionWords: Vex.Flow.Repetition[] = [];
-
-    // The VexFlow Stave (= one measure in a staffline)
+    /** Instant dynamics */
+    public instantaniousDynamics: VexFlowInstantaniousDynamicExpression[] = [];
+    /** The VexFlow Stave (= one measure in a staffline) */
     private stave: Vex.Flow.Stave;
     private stave: Vex.Flow.Stave;
-    // VexFlow StaveConnectors (vertical lines)
+    /** VexFlow StaveConnectors (vertical lines) */
     private connectors: Vex.Flow.StaveConnector[] = [];
     private connectors: Vex.Flow.StaveConnector[] = [];
-    // Intermediate object to construct beams
+    /** Intermediate object to construct beams */
     private beams: { [voiceID: number]: [Beam, VexFlowVoiceEntry[]][]; } = {};
     private beams: { [voiceID: number]: [Beam, VexFlowVoiceEntry[]][]; } = {};
-    // VexFlow Beams
+    /** VexFlow Beams */
     private vfbeams: { [voiceID: number]: Vex.Flow.Beam[]; };
     private vfbeams: { [voiceID: number]: Vex.Flow.Beam[]; };
-    // Intermediate object to construct tuplets
+    /** Intermediate object to construct tuplets */
     private tuplets: { [voiceID: number]: [Tuplet, VexFlowVoiceEntry[]][]; } = {};
     private tuplets: { [voiceID: number]: [Tuplet, VexFlowVoiceEntry[]][]; } = {};
-    // VexFlow Tuplets
+    /** VexFlow Tuplets */
     private vftuplets: { [voiceID: number]: Vex.Flow.Tuplet[]; } = {};
     private vftuplets: { [voiceID: number]: Vex.Flow.Tuplet[]; } = {};
 
 
     // Sets the absolute coordinates of the VFStave on the canvas
     // Sets the absolute coordinates of the VFStave on the canvas
@@ -602,6 +604,13 @@ export class VexFlowMeasure extends StaffMeasure {
             }
             }
         }
         }
         this.createArticulations();
         this.createArticulations();
+        if (this.instantaniousDynamics.length > 0) {
+            this.createInstantDynamics();
+        }
+    }
+
+    private createInstantDynamics(): void {
+
     }
     }
 
 
     private createArticulations(): void {
     private createArticulations(): void {

+ 19 - 7
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -33,6 +33,7 @@ import {LyricsEntry} from "../../VoiceData/Lyrics/LyricsEntry";
 import {GraphicalLyricWord} from "../GraphicalLyricWord";
 import {GraphicalLyricWord} from "../GraphicalLyricWord";
 import {VexFlowStaffEntry} from "./VexFlowStaffEntry";
 import {VexFlowStaffEntry} from "./VexFlowStaffEntry";
 import { VexFlowOctaveShift } from "./VexFlowOctaveShift";
 import { VexFlowOctaveShift } from "./VexFlowOctaveShift";
+import { VexFlowInstantaniousDynamicExpression } from "./VexFlowInstantaniousDynamicExpression";
 
 
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
 
 
@@ -264,13 +265,24 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     }
     }
   }
   }
 
 
-    /**
-     * Calculate a single OctaveShift for a [[MultiExpression]].
-     * @param sourceMeasure
-     * @param multiExpression
-     * @param measureIndex
-     * @param staffIndex
-     */
+  protected calculateDynamicExpressionsForSingleMultiExpression(multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
+    if (multiExpression.InstantaniousDynamic) {
+        const timeStamp: Fraction = multiExpression.Timestamp;
+        const staffLine: StaffLine = this.graphicalMusicSheet.MeasureList[measureIndex][staffIndex].ParentStaffLine;
+        const measure: StaffMeasure = this.graphicalMusicSheet.MeasureList[measureIndex][staffIndex];
+        const startStaffEntry: GraphicalStaffEntry = measure.findGraphicalStaffEntryFromTimestamp(timeStamp);
+        const idx: VexFlowInstantaniousDynamicExpression = new VexFlowInstantaniousDynamicExpression(multiExpression.InstantaniousDynamic, startStaffEntry);
+        (measure as VexFlowMeasure).instantaniousDynamics.push(idx);
+    }
+  }
+
+  /**
+   * Calculate a single OctaveShift for a [[MultiExpression]].
+   * @param sourceMeasure
+   * @param multiExpression
+   * @param measureIndex
+   * @param staffIndex
+   */
   protected calculateSingleOctaveShift(sourceMeasure: SourceMeasure, multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
   protected calculateSingleOctaveShift(sourceMeasure: SourceMeasure, multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
     // calculate absolute Timestamp and startStaffLine (and EndStaffLine if needed)
     // calculate absolute Timestamp and startStaffLine (and EndStaffLine if needed)
     const octaveShift: OctaveShift = multiExpression.OctaveShiftStart;
     const octaveShift: OctaveShift = multiExpression.OctaveShiftStart;

+ 11 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -16,6 +16,8 @@ import { GraphicalLyricEntry } from "../GraphicalLyricEntry";
 import { StaffLine } from "../StaffLine";
 import { StaffLine } from "../StaffLine";
 import { GraphicalOctaveShift } from "../GraphicalOctaveShift";
 import { GraphicalOctaveShift } from "../GraphicalOctaveShift";
 import { VexFlowOctaveShift } from "./VexFlowOctaveShift";
 import { VexFlowOctaveShift } from "./VexFlowOctaveShift";
+import { GraphicalInstantaniousDynamicExpression } from "../GraphicalInstantaniousDynamicExpression";
+import { VexFlowInstantaniousDynamicExpression } from "./VexFlowInstantaniousDynamicExpression";
 
 
 /**
 /**
  * This is a global constant which denotes the height in pixels of the space between two lines of the stave
  * This is a global constant which denotes the height in pixels of the space between two lines of the stave
@@ -135,6 +137,15 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
         }
         }
     }
     }
 
 
+    protected drawInstantaniousDynamic(staffline: StaffLine): void {
+        for (const m of staffline.Measures as VexFlowMeasure[]) {
+            for (const idx of m.instantaniousDynamics as VexFlowInstantaniousDynamicExpression[]) {
+                const ctx: Vex.Flow.RenderContext = this.backend.getContext();
+                this.drawLabel(idx.Label, <number>GraphicalLayers.Notes);
+            }
+        }
+    }
+
     /**
     /**
      * Renders a Label to the screen (e.g. Title, composer..)
      * Renders a Label to the screen (e.g. Title, composer..)
      * @param graphicalLabel holds the label string, the text height in units and the font parameters
      * @param graphicalLabel holds the label string, the text height in units and the font parameters

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

@@ -28,7 +28,6 @@ export class VexFlowStaffEntry extends GraphicalStaffEntry {
                 const staveNote: Vex.Flow.StaveNote = tickable as Vex.Flow.StaveNote;
                 const staveNote: Vex.Flow.StaveNote = tickable as Vex.Flow.StaveNote;
                 tickablePosition += staveNote.getNoteHeadEndX() - staveNote.getGlyphWidth() / 2;
                 tickablePosition += staveNote.getNoteHeadEndX() - staveNote.getGlyphWidth() / 2;
             } else {
             } else {
-                console.log(tickable);
                 const ghostNote: Vex.Flow.GhostNote = tickable;
                 const ghostNote: Vex.Flow.GhostNote = tickable;
                 // That's basically the same as the StaveNote does.
                 // That's basically the same as the StaveNote does.
                 tickablePosition = ghostNote.getAbsoluteX() + ghostNote.x_shift;
                 tickablePosition = ghostNote.getAbsoluteX() + ghostNote.x_shift;