Bladeren bron

Added method for creating word repetition instructions.
Added comments.

Matthias 8 jaren geleden
bovenliggende
commit
854d3227f8

+ 1 - 1
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -340,7 +340,7 @@ export abstract class MusicSheetCalculator {
     }
 
     /**
-     * Calculate all the [[RepetitionInstruction]]s for a single [[SourceMeasure]].
+     * Calculate all the textual [[RepetitionInstruction]]s (e.g. dal segno) for a single [[SourceMeasure]].
      * @param repetitionInstruction
      * @param measureIndex
      */

+ 86 - 1
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -11,7 +11,7 @@ import {GraphicalTie} from "../GraphicalTie";
 import {Tie} from "../../VoiceData/Tie";
 import {SourceMeasure} from "../../VoiceData/SourceMeasure";
 import {MultiExpression} from "../../VoiceData/Expressions/MultiExpression";
-import {RepetitionInstruction} from "../../VoiceData/Instructions/RepetitionInstruction";
+import {RepetitionInstruction, RepetitionInstructionEnum} from "../../VoiceData/Instructions/RepetitionInstruction";
 import {Beam} from "../../VoiceData/Beam";
 import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
 import {OctaveEnum} from "../../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
@@ -29,6 +29,7 @@ import Vex = require("vexflow");
 import {Logging} from "../../../Common/Logging";
 import {unitInPixels} from "./VexFlowMusicSheetDrawer";
 import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
+import {VexFlowStaffLine} from "./VexFlowStaffLine";
 
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     constructor() {
@@ -184,6 +185,11 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
         return;
     }
 
+    /**
+     * Calculate the shape (Bézier curve) for this tie.
+     * @param tie
+     * @param tieIsAtSystemBreak
+     */
     protected layoutGraphicalTie(tie: GraphicalTie, tieIsAtSystemBreak: boolean): void {
         let startNote: VexFlowGraphicalNote = (tie.StartNote as VexFlowGraphicalNote);
         let vfStartNote: Vex.Flow.StaveNote = undefined;
@@ -221,22 +227,101 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
         }
     }
 
+    /**
+     * Calculate the Lyrics YPositions for a single [[StaffLine]].
+     * @param staffLine
+     * @param lyricVersesNumber
+     */
     protected calculateSingleStaffLineLyricsPosition(staffLine: StaffLine, lyricVersesNumber: number[]): void {
         return;
     }
 
+    /**
+     * 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 {
         return;
     }
 
+    /**
+     * Calculate all the textual and symbolic [[RepetitionInstruction]]s (e.g. dal segno) for a single [[SourceMeasure]].
+     * @param repetitionInstruction
+     * @param measureIndex
+     */
     protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void {
+      // find first visible StaffLine
+      let staffLine: VexFlowStaffLine = undefined;
+      let measures: VexFlowMeasure[]  = <VexFlowMeasure[]>this.graphicalMusicSheet.MeasureList[measureIndex];
+      let topMeasure: VexFlowMeasure = undefined;
+      for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
+        let graphicalMeasure: VexFlowMeasure = measures[idx];
+        if (graphicalMeasure.ParentStaffLine !== undefined && graphicalMeasure.ParentStaff.ParentInstrument.Visible) {
+          staffLine = <VexFlowStaffLine>graphicalMeasure.ParentStaffLine;
+          topMeasure = graphicalMeasure;
+          break;
+        }
+      }
+      // now create graphical symbol or Text in VexFlow:
+      if (staffLine !== undefined) {
+        let instruction: string = "";
+        switch (repetitionInstruction.type) {
+          case RepetitionInstructionEnum.Segno:
+
+            // create Segno Symbol:
+            break;
+          case RepetitionInstructionEnum.Coda:
+            // create Coda Symbol:
+            break;
+          case RepetitionInstructionEnum.DaCapo:
+            instruction = "D.C.";
+            break;
+          case RepetitionInstructionEnum.DalSegno:
+            instruction = "D.S.";
+            break;
+          case RepetitionInstructionEnum.Fine:
+            instruction = "Fine";
+            break;
+          case RepetitionInstructionEnum.ToCoda:
+            instruction = "To Coda";
+            break;
+          case RepetitionInstructionEnum.DaCapoAlFine:
+            instruction = "D.C. al Fine";
+            break;
+          case RepetitionInstructionEnum.DaCapoAlCoda:
+            instruction = "D.C. al Coda";
+            break;
+          case RepetitionInstructionEnum.DalSegnoAlFine:
+            instruction = "D.S. al Fine";
+            break;
+          case RepetitionInstructionEnum.DalSegnoAlCoda:
+            instruction = "D.S. al Coda";
+            break;
+          default:
+            break;
+        }
         return;
+      }
     }
 
     protected calculateMoodAndUnknownExpression(multiExpression: MultiExpression, measureIndex: number, staffIndex: number): void {
         return;
     }
 
+    /**
+     * Check if the tied graphical note belongs to any beams or tuplets and react accordingly.
+     * @param tiedGraphicalNote
+     * @param beams
+     * @param activeClef
+     * @param octaveShiftValue
+     * @param graphicalStaffEntry
+     * @param duration
+     * @param openTie
+     * @param isLastTieNote
+     */
     protected handleTiedGraphicalNote(  tiedGraphicalNote: GraphicalNote, beams: Beam[], activeClef: ClefInstruction,
                                         octaveShiftValue: OctaveEnum, graphicalStaffEntry: GraphicalStaffEntry, duration: Fraction,
                                         openTie: Tie, isLastTieNote: boolean): void {

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

@@ -37,7 +37,6 @@ export class VexFlowMusicSystem extends MusicSystem {
      */
     protected createSystemLine(xPosition: number, lineWidth: number, lineType: SystemLinesEnum, linePosition: SystemLinePosition,
                                musicSystem: MusicSystem, topMeasure: StaffMeasure, bottomMeasure: StaffMeasure = undefined): SystemLine {
-        // ToDo: create line in Vexflow
         if (bottomMeasure) {
             (bottomMeasure as VexFlowMeasure).lineTo(topMeasure as VexFlowMeasure, VexFlowConverter.line(lineType));
         }

+ 13 - 2
src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionCalculator.ts

@@ -10,6 +10,13 @@ export class RepetitionCalculator {
   private currentMeasure: SourceMeasure;
   private currentMeasureIndex: number;
 
+  /**
+   * Is called when all repetition symbols have been read from xml.
+   * Creates the repetition instructions and adds them to the corresponding measure.
+   * Creates the logical repetition objects for iteration and playback.
+   * @param musicSheet
+   * @param repetitionInstructions
+   */
   public calculateRepetitions(musicSheet: MusicSheet, repetitionInstructions: RepetitionInstruction[]): void {
     this.musicSheet = <MusicSheet>musicSheet;
     this.repetitionInstructions = repetitionInstructions;
@@ -21,6 +28,9 @@ export class RepetitionCalculator {
       this.currentMeasure = sourceMeasures[this.currentMeasureIndex];
       this.handleRepetitionInstructions(instruction);
     }
+
+    // if there are more than one instruction at measure begin or end,
+    // sort them according to the nesting of the repetitions:
     for (let idx: number = 0, len: number = this.musicSheet.SourceMeasures.length; idx < len; ++idx) {
       let measure: SourceMeasure = this.musicSheet.SourceMeasures[idx];
       if (measure.FirstRepetitionInstructions.length > 1) {
@@ -41,9 +51,10 @@ export class RepetitionCalculator {
         this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
         break;
       case RepetitionInstructionEnum.Ending:
-        if (currentRepetitionInstruction.alignment === AlignmentType.Begin) {
+        // set ending start or end
+        if (currentRepetitionInstruction.alignment === AlignmentType.Begin) {  // ending start
           this.currentMeasure.FirstRepetitionInstructions.push(currentRepetitionInstruction);
-        } else {
+        } else { // ending end
           for (let idx: number = 0, len: number = currentRepetitionInstruction.endingIndices.length; idx < len; ++idx) {
             this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
           }

+ 34 - 8
src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionInstructionReader.ts

@@ -4,6 +4,9 @@ import {SourceMeasure} from "../../VoiceData/SourceMeasure";
 import {RepetitionInstruction, RepetitionInstructionEnum, AlignmentType} from "../../VoiceData/Instructions/RepetitionInstruction";
 import {StringUtil} from "../../../Common/Strings/StringUtil";
 export class RepetitionInstructionReader {
+  /**
+   * A global list of all repetition instructions in the musicsheet.
+   */
   public repetitionInstructions: RepetitionInstruction[];
   public xmlMeasureList: IXmlElement[][];
   private musicSheet: MusicSheet;
@@ -15,6 +18,11 @@ export class RepetitionInstructionReader {
     this.repetitionInstructions = [];
   }
 
+  /**
+   * is called when starting reading an xml measure
+   * @param measure
+   * @param currentMeasureIndex
+   */
   public prepareReadingMeasure(measure: SourceMeasure, currentMeasureIndex: number): void {
     this.currentMeasureIndex = currentMeasureIndex;
   }
@@ -28,7 +36,11 @@ export class RepetitionInstructionReader {
       let type: string = "";
       let style: string = "";
       let endingIndices: number[] = [];
+
+      // read barline style
       let styleNode: IXmlElement = barlineNode.element("bar-style");
+
+      // if location is ommited in Xml, right is implied (from documentation)
       if (styleNode !== undefined) {
         style = styleNode.value;
       }
@@ -38,6 +50,8 @@ export class RepetitionInstructionReader {
         location = "right";
       }
       let barlineNodeElements: IXmlElement[] = barlineNode.elements();
+
+      // read repeat- or ending line information
       for (let idx: number = 0, len: number = barlineNodeElements.length; idx < len; ++idx) {
         let childNode: IXmlElement = barlineNodeElements[idx];
         if ("repeat" === childNode.name && childNode.hasAttributes) {
@@ -47,10 +61,15 @@ export class RepetitionInstructionReader {
                     childNode.attribute("type") !== undefined && childNode.attribute("number") !== undefined) {
           type = childNode.attribute("type").value;
           let num: string = childNode.attribute("number").value;
+
+          // Parse the given ending indices:
+          // handle cases like: "1, 2" or "1 + 2" or even "1 - 3, 6"
           let separatedEndingIndices: string[] = num.split("[,+]");
           for (let idx2: number = 0, len2: number = separatedEndingIndices.length; idx2 < len2; ++idx2) {
             let separatedEndingIndex: string = separatedEndingIndices[idx2];
             let indices: string[] = separatedEndingIndex.match("[0-9]");
+
+            // check if possibly something like "1-3" is given..
             if (separatedEndingIndex.search("-") !== -1 && indices.length === 2) {
               let startIndex: number = parseInt(indices[0], 10);
               let endIndex: number = parseInt(indices[1], 10);
@@ -66,6 +85,8 @@ export class RepetitionInstructionReader {
           }
         }
       }
+
+      // reset measure counter if not lastMeasure
       if (style === "light-heavy" && endingIndices.length === 0 && !hasRepeat) {
         pieceEndingDetected = true;
       }
@@ -77,10 +98,11 @@ export class RepetitionInstructionReader {
             this.addInstruction(this.repetitionInstructions, newInstruction);
           }
           if (direction === "forward") {
+            // start new Repetition
             let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.StartLine);
             this.addInstruction(this.repetitionInstructions, newInstruction);
           }
-        } else {
+        } else { // location right
           if (type === "stop" || type === "discontinue") {
             let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.Ending,
                                                                                   AlignmentType.End, undefined, endingIndices);
@@ -98,11 +120,12 @@ export class RepetitionInstructionReader {
   public handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode: IXmlElement, relativeMeasurePosition: number): boolean {
     let wordsNode: IXmlElement = directionTypeNode.element("words");
     if (wordsNode !== undefined) {
+      // must Trim string and ToLower before compare
       let innerText: string = wordsNode.value.trim().toLowerCase();
       if (StringUtil.StringContainsSeparatedWord(innerText, "d.s. al fine") ||
         StringUtil.StringContainsSeparatedWord(innerText, "d. s. al fine")) {
         let measureIndex: number = this.currentMeasureIndex;
-        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) {
+        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
         let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegnoAlFine);
@@ -122,7 +145,7 @@ export class RepetitionInstructionReader {
       if (StringUtil.StringContainsSeparatedWord(innerText, "d.c. al fine") ||
         StringUtil.StringContainsSeparatedWord(innerText, "d. c. al fine")) {
         let measureIndex: number = this.currentMeasureIndex;
-        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) {
+        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
         let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapoAlFine);
@@ -144,7 +167,7 @@ export class RepetitionInstructionReader {
         StringUtil.StringContainsSeparatedWord(innerText, "dacapo") ||
         StringUtil.StringContainsSeparatedWord(innerText, "da capo")) {
         let measureIndex: number = this.currentMeasureIndex;
-        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) {
+        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
         let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapo);
@@ -156,7 +179,7 @@ export class RepetitionInstructionReader {
         StringUtil.StringContainsSeparatedWord(innerText, "dalsegno") ||
         StringUtil.StringContainsSeparatedWord(innerText, "dal segno")) {
         let measureIndex: number = this.currentMeasureIndex;
-        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) {
+        if (relativeMeasurePosition < 0.5 && this.currentMeasureIndex < this.xmlMeasureList[0].length - 1) { // not in last measure
           measureIndex--;
         }
         let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegno);
@@ -244,14 +267,14 @@ export class RepetitionInstructionReader {
           }
           break;
         case RepetitionInstructionEnum.Segno:
-          if (segnoCount - dalSegnaCount > 0) {
+          if (segnoCount - dalSegnaCount > 0) { // two segnos in a row
             let foundInstruction: boolean = false;
             for (let idx: number = 0, len: number = this.repetitionInstructions.length; idx < len; ++idx) {
               let instr: RepetitionInstruction = this.repetitionInstructions[idx];
               if (instruction.measureIndex - instr.measureIndex === 1) {
                 switch (instr.type) {
                   case RepetitionInstructionEnum.BackJumpLine:
-                    if (toCodaCount - codaCount > 0) {
+                    if (toCodaCount - codaCount > 0) { // open toCoda existing
                       instr.type = RepetitionInstructionEnum.DalSegnoAlCoda;
                     } else {
                       instr.type = RepetitionInstructionEnum.DalSegno;
@@ -276,7 +299,8 @@ export class RepetitionInstructionReader {
             if (foundInstruction) {
               break;
             }
-            if (toCodaCount - codaCount > 0) {
+            // convert to dal segno instruction:
+            if (toCodaCount - codaCount > 0) { // open toCoda existing
               instruction.type = RepetitionInstructionEnum.DalSegnoAlCoda;
             } else {
               instruction.type = RepetitionInstructionEnum.DalSegno;
@@ -288,6 +312,8 @@ export class RepetitionInstructionReader {
         default:
           break;
       }
+
+      // check if this  instruction already exists or is otherwise redundant:
       if (this.backwardSearchForPreviousIdenticalInstruction(index, instruction) || instruction.type === RepetitionInstructionEnum.None) {
         this.repetitionInstructions.splice(index, 1);
         index--;