Browse Source

added and implemented code for chord symbols

Matthias Uiberacker 8 năm trước cách đây
mục cha
commit
66f3217d20

+ 25 - 0
src/MusicalScore/Graphical/BoundingBox.ts

@@ -205,6 +205,20 @@ export class BoundingBox {
     }
 
     /**
+     * Calculate the the absolute position by adding up all relative positions of all parents (including the own rel. pos.)
+     */
+    public calculateAbsolutePosition(): void {
+      this.absolutePosition.x = this.relativePosition.x;
+      this.absolutePosition.y = this.relativePosition.y;
+      let parent: BoundingBox = this.parent;
+      while (parent !== undefined) {
+        this.absolutePosition.x += parent.relativePosition.x;
+        this.absolutePosition.y += parent.relativePosition.y;
+        parent = parent.parent;
+      }
+    }
+
+    /**
      * This method calculates the Absolute Positions recursively
      */
     public calculateAbsolutePositionsRecursiveWithoutTopelement(): void {
@@ -218,6 +232,7 @@ export class BoundingBox {
 
     /**
      * This method calculates the Absolute Positions recursively
+     * from the root element down to the leaf elements
      * @param x
      * @param y
      */
@@ -231,6 +246,16 @@ export class BoundingBox {
     }
 
     /**
+     * calculates the absolute positions of all children of this boundingBox
+     */
+    public calculateAbsolutePositionsOfChildren(): void {
+      for (let idx: number = 0, len: number = this.ChildElements.length; idx < len; ++idx) {
+        let child: BoundingBox = this.ChildElements[idx];
+        child.calculateAbsolutePositionsRecursive(this.absolutePosition.x, this.absolutePosition.y);
+      }
+    }
+
+    /**
      * This method calculates the BoundingBoxes
      */
     public calculateBoundingBox(): void {

+ 13 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowGraphicalSymbolFactory.ts

@@ -19,6 +19,9 @@ import {Pitch} from "../../../Common/DataObjects/Pitch";
 import {TechnicalInstruction} from "../../VoiceData/Instructions/TechnicalInstruction";
 import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
 import {Fraction} from "../../../Common/DataObjects/Fraction";
+import {GraphicalChordSymbolContainer} from "../GraphicalChordSymbolContainer";
+import {GraphicalLabel} from "../GraphicalLabel";
+import {EngravingRules} from "../EngravingRules";
 
 export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
     /**
@@ -172,6 +175,15 @@ export class VexFlowGraphicalSymbolFactory implements IGraphicalSymbolFactory {
      * @param transposeHalftones
      */
     public createChordSymbol(sourceStaffEntry: SourceStaffEntry, graphicalStaffEntry: GraphicalStaffEntry, transposeHalftones: number): void {
-        return;
+      let graphicalChordSymbolContainer: GraphicalChordSymbolContainer =
+        new GraphicalChordSymbolContainer(sourceStaffEntry.ChordContainer,
+                                          graphicalStaffEntry.PositionAndShape,
+                                          EngravingRules.Rules.ChordSymbolTextHeight,
+                                          transposeHalftones);
+      let graphicalLabel: GraphicalLabel = graphicalChordSymbolContainer.GetGraphicalLabel;
+      graphicalLabel.setLabelPositionAndShapeBorders();
+      graphicalChordSymbolContainer.PositionAndShape.calculateBoundingBox();
+      graphicalStaffEntry.graphicalChordContainer = graphicalChordSymbolContainer;
+      graphicalStaffEntry.PositionAndShape.ChildElements.push(graphicalChordSymbolContainer.PositionAndShape);
     }
 }

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

@@ -444,6 +444,8 @@ export class VexFlowMeasure extends StaffMeasure {
                 measure.ParentStaffLine.PositionAndShape.RelativePosition.x -
                 measure.parentMusicSystem.PositionAndShape.RelativePosition.x;
             gse.PositionAndShape.RelativePosition.x = x;
+            gse.PositionAndShape.calculateAbsolutePosition();
+            gse.PositionAndShape.calculateAbsolutePositionsOfChildren();
         }
     }
 }

+ 15 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetDrawer.ts

@@ -8,6 +8,8 @@ import {VexFlowConverter} from "./VexFlowConverter";
 import {VexFlowTextMeasurer} from "./VexFlowTextMeasurer";
 import {MusicSystem} from "../MusicSystem";
 import {GraphicalObject} from "../GraphicalObject";
+import {GraphicalLayers} from "../DrawingEnums";
+import {GraphicalStaffEntry} from "../GraphicalStaffEntry";
 
 /**
  * This is a global contant which denotes the height in pixels of the space between two lines of the stave
@@ -68,7 +70,19 @@ export class VexFlowMusicSheetDrawer extends MusicSheetDrawer {
             measure.PositionAndShape.AbsolutePosition.x * unitInPixels,
             measure.PositionAndShape.AbsolutePosition.y * unitInPixels
         );
-        return measure.draw(this.vfctx);
+        measure.draw(this.vfctx);
+
+        // Draw the StaffEntries
+        for (let staffEntry of measure.staffEntries){
+            this.drawStaffEntry(staffEntry);
+        }
+    }
+
+    private drawStaffEntry(staffEntry: GraphicalStaffEntry): void {
+        // Draw ChordSymbol
+        if (staffEntry.graphicalChordContainer !== undefined) {
+            this.drawLabel(staffEntry.graphicalChordContainer.GetGraphicalLabel, <number>GraphicalLayers.Notes);
+        }
     }
 
     protected drawInstrumentBrace(bracket: GraphicalObject, system: MusicSystem): void {

+ 10 - 8
src/MusicalScore/ScoreIO/InstrumentReader.ts

@@ -19,6 +19,7 @@ import {IXmlAttribute} from "../../Common/FileIO/Xml";
 import {ChordSymbolContainer} from "../VoiceData/ChordSymbolContainer";
 import {Logging} from "../../Common/Logging";
 import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
+import {ChordSymbolReader} from "./MusicSymbolModules/ChordSymbolReader";
 //import Dictionary from "typescript-collections/dist/lib/Dictionary";
 
 // FIXME: The following classes are missing
@@ -46,7 +47,7 @@ import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
 /**
  * To be implemented
  */
-export type repetitionInstructionReader = any;
+export type RepetitionInstructionReader = any;
 
 /**
  * An InstrumentReader is used during the reading phase to keep parsing new measures from the MusicXML file
@@ -54,8 +55,8 @@ export type repetitionInstructionReader = any;
  */
 export class InstrumentReader {
 
-    constructor(repetitionInstructionReader: repetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
-        // (*) this.repetitionInstructionReader = repetitionInstructionReader;
+    constructor(repetitionInstructionReader: RepetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
+        this.repetitionInstructionReader = repetitionInstructionReader;
         this.xmlMeasureList = xmlMeasureList;
         this.musicSheet = instrument.GetMusicSheet;
         this.instrument = instrument;
@@ -68,7 +69,7 @@ export class InstrumentReader {
         // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
     }
 
-    // (*) private repetitionInstructionReader: RepetitionInstructionReader;
+    private repetitionInstructionReader: RepetitionInstructionReader;
     private xmlMeasureList: IXmlElement[];
     private musicSheet: MusicSheet;
     private slurReader: any; // (*) SlurReader;
@@ -313,8 +314,9 @@ export class InstrumentReader {
                     if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
                         relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
                     }
-                    // unused: let handeled: boolean = false;
-                    // (*) if (this.repetitionInstructionReader !== undefined) {
+                    // unused:
+                    // let handeled: boolean = false;
+                    // if (this.repetitionInstructionReader !== undefined) {
                     //  handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
                     //                                                                                              relativePositionInMeasure);
                     //}
@@ -338,7 +340,7 @@ export class InstrumentReader {
                     //  }
                     //}
                 } else if (xmlNode.name === "barline") {
-                    // (*)
+
                     //if (this.repetitionInstructionReader !== undefined) {
                     //  let measureEndsSystem: boolean = false;
                     //  this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
@@ -350,7 +352,7 @@ export class InstrumentReader {
                 } else if (xmlNode.name === "sound") {
                     // (*) MetronomeReader.readTempoInstruction(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
                 } else if (xmlNode.name === "harmony") {
-                    // (*) this.openChordSymbolContainer = ChordSymbolReader.readChordSymbol(xmlNode, this.musicSheet, this.activeKey);
+                    this.openChordSymbolContainer = ChordSymbolReader.readChordSymbol(xmlNode, this.musicSheet, this.activeKey);
                 }
             }
             for (let j in this.voiceGeneratorsDict) {

+ 145 - 0
src/MusicalScore/ScoreIO/MusicSymbolModules/ChordSymbolReader.ts

@@ -0,0 +1,145 @@
+import {IXmlElement} from "../../../Common/FileIO/Xml";
+import {MusicSheet} from "../../MusicSheet";
+import {ChordDegreeText, ChordSymbolContainer, ChordSymbolEnum, Degree} from "../../VoiceData/ChordSymbolContainer";
+import {AccidentalEnum, NoteEnum, Pitch} from "../../../Common/DataObjects/Pitch";
+import {KeyInstruction} from "../../VoiceData/Instructions/KeyInstruction";
+import {ITextTranslation} from "../../Interfaces/ITextTranslation";
+import {Logging} from "../../../Common/Logging";
+export class ChordSymbolReader {
+    public static readChordSymbol(xmlNode: IXmlElement, musicSheet: MusicSheet, activeKey: KeyInstruction): ChordSymbolContainer {
+        let root: IXmlElement = xmlNode.element("root");
+        let kind: IXmlElement = xmlNode.element("kind");
+
+        // must be always present
+        if (root === undefined || kind === undefined) {
+          return undefined;
+        }
+
+        let rootStep: IXmlElement = root.element("root-step");
+        let rootAlter: IXmlElement = root.element("root-alter");
+
+        // a valid NoteEnum value should be present
+        if (rootStep === undefined) {
+            return undefined;
+        }
+        let rootNote: NoteEnum;
+        try {
+            rootNote = NoteEnum[rootStep.value.trim()];
+        } catch (ex) {
+            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                  "Invalid chord symbol");
+            musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+            return undefined;
+        }
+
+        // an alteration value isn't necessary
+        let rootAlteration: AccidentalEnum = AccidentalEnum.NONE;
+        if (rootAlter !== undefined) {
+            try {
+                rootAlteration = <AccidentalEnum>parseInt(rootAlter.value, undefined);
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+            }
+
+        }
+        // using default octave value, to be changed later
+        let rootPitch: Pitch = new Pitch(rootNote, 1, rootAlteration);
+        let kindValue: string = kind.value.trim().replace("-", "");
+        let chordKind: ChordSymbolEnum;
+        try {
+            chordKind = ChordSymbolEnum[kindValue];
+        } catch (ex) {
+            let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                  "Invalid chord symbol");
+            musicSheet.SheetErrors.pushMeasureError(errorMsg);
+            Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+            return undefined;
+        }
+
+        // bass is optional
+        let bassPitch: Pitch = undefined;
+        let bass: IXmlElement = xmlNode.element("bass");
+        if (bass !== undefined) {
+            let bassStep: IXmlElement = bass.element("bass-step");
+            let bassAlter: IXmlElement = bass.element("bass-alter");
+            let bassNote: NoteEnum = NoteEnum.C;
+            if (bassStep !== undefined) {
+                try {
+                    bassNote = NoteEnum[bassStep.value.trim()];
+                } catch (ex) {
+                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                          "Invalid chord symbol");
+                    musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                    Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                    return undefined;
+                }
+
+            }
+            let bassAlteration: AccidentalEnum = AccidentalEnum.NONE;
+            if (bassAlter !== undefined) {
+                try {
+                    bassAlteration = <AccidentalEnum>parseInt(bassAlter.value, undefined);
+                } catch (ex) {
+                    let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                          "Invalid chord symbol");
+                    musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                    Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                }
+
+            }
+            bassPitch = new Pitch(bassNote, 1, bassAlteration);
+        }
+
+        // degree is optional
+        let degree: Degree = undefined;
+        let degreeNode: IXmlElement = xmlNode.element("degree");
+        if (degreeNode !== undefined) {
+            let degreeValue: IXmlElement = degreeNode.element("degree-value");
+            let degreeAlter: IXmlElement = degreeNode.element("degree-alter");
+            let degreeType: IXmlElement = degreeNode.element("degree-type");
+            if (degreeValue === undefined || degreeAlter === undefined || degreeType === undefined) {
+              return undefined;
+            }
+
+            let value: number;
+            try {
+                value = parseInt(degreeValue.value.trim(), undefined);
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            let alter: AccidentalEnum;
+            try {
+                alter = <AccidentalEnum>parseInt(degreeAlter.value, undefined);
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            let text: ChordDegreeText;
+            try {
+                text = ChordDegreeText[degreeType.value.trim().toLowerCase()];
+            } catch (ex) {
+                let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ChordSymbolError",
+                                                                      "Invalid chord symbol");
+                musicSheet.SheetErrors.pushMeasureError(errorMsg);
+                Logging.error(LogLevel.DEBUG, "InstrumentReader.readChordSymbol", errorMsg, ex);
+                return undefined;
+            }
+
+            degree = new Degree(value, alter, text);
+        }
+        return new ChordSymbolContainer(rootPitch, chordKind, bassPitch, degree, activeKey);
+    }
+}