Browse Source

Implemented reading and rendering repetition instructions from words (dal segno, fine..)

Matthias Uiberacker 7 years ago
parent
commit
0d00fff8b6

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

@@ -133,6 +133,10 @@ declare namespace Vex {
         export class StaveModifier extends Modifier {
         export class StaveModifier extends Modifier {
         }
         }
 
 
+        export class Repetition extends StaveModifier {
+            constructor(type: any, x: number, y_shift: number);
+        }
+
         export class Clef extends StaveModifier {
         export class Clef extends StaveModifier {
             constructor(type: string, size: number, annotation: string);
             constructor(type: string, size: number, annotation: string);
 
 

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

@@ -435,3 +435,19 @@ export class VexFlowConverter {
         return ret;
         return ret;
     }
     }
 }
 }
+
+export enum VexFlowRepetitionType {
+    NONE = 1,         // no coda or segno
+    CODA_LEFT = 2,    // coda at beginning of stave
+    CODA_RIGHT = 3,   // coda at end of stave
+    SEGNO_LEFT = 4,   // segno at beginning of stave
+    SEGNO_RIGHT = 5,  // segno at end of stave
+    DC = 6,           // D.C. at end of stave
+    DC_AL_CODA = 7,   // D.C. al coda at end of stave
+    DC_AL_FINE = 8,   // D.C. al Fine end of stave
+    DS = 9,           // D.S. at end of stave
+    DS_AL_CODA = 10,  // D.S. al coda at end of stave
+    DS_AL_FINE = 11,  // D.S. al Fine at end of stave
+    FINE = 12,        // Fine at end of stave
+}
+

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

@@ -7,7 +7,7 @@ import {SystemLinesEnum} from "../SystemLinesEnum";
 import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
 import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
 import {KeyInstruction} from "../../VoiceData/Instructions/KeyInstruction";
 import {KeyInstruction} from "../../VoiceData/Instructions/KeyInstruction";
 import {RhythmInstruction} from "../../VoiceData/Instructions/RhythmInstruction";
 import {RhythmInstruction} from "../../VoiceData/Instructions/RhythmInstruction";
-import {VexFlowConverter} from "./VexFlowConverter";
+import {VexFlowConverter, VexFlowRepetitionType} from "./VexFlowConverter";
 import {VexFlowStaffEntry} from "./VexFlowStaffEntry";
 import {VexFlowStaffEntry} from "./VexFlowStaffEntry";
 import {Beam} from "../../VoiceData/Beam";
 import {Beam} from "../../VoiceData/Beam";
 import {GraphicalNote} from "../GraphicalNote";
 import {GraphicalNote} from "../GraphicalNote";
@@ -17,6 +17,7 @@ import StaveNote = Vex.Flow.StaveNote;
 import {Logging} from "../../../Common/Logging";
 import {Logging} from "../../../Common/Logging";
 import {unitInPixels} from "./VexFlowMusicSheetDrawer";
 import {unitInPixels} from "./VexFlowMusicSheetDrawer";
 import {Tuplet} from "../../VoiceData/Tuplet";
 import {Tuplet} from "../../VoiceData/Tuplet";
+import { RepetitionInstructionEnum } from "../../VoiceData/Instructions/RepetitionInstruction";
 
 
 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) {
@@ -33,8 +34,10 @@ export class VexFlowMeasure extends StaffMeasure {
     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..)
+    public vfRepetitionWords: Vex.Flow.Repetition[] = [];
 
 
-    // The VexFlow Stave (one measure in one line)
+    // 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[] = [];
@@ -149,6 +152,52 @@ export class VexFlowMeasure extends StaffMeasure {
         this.updateInstructionWidth();
         this.updateInstructionWidth();
     }
     }
 
 
+    public addWordRepetition(repetitionInstruction: RepetitionInstructionEnum): void {
+        let instruction: VexFlowRepetitionType = undefined;
+        let position: any = Vex.Flow.Modifier.Position.END;
+        switch (repetitionInstruction) {
+          case RepetitionInstructionEnum.Segno:
+            // create Segno Symbol:
+            instruction = VexFlowRepetitionType.SEGNO_LEFT;
+            position = Vex.Flow.Modifier.Position.BEGIN;
+            break;
+          case RepetitionInstructionEnum.Coda:
+            // create Coda Symbol:
+            instruction = VexFlowRepetitionType.CODA_LEFT;
+            position = Vex.Flow.Modifier.Position.BEGIN;
+            break;
+          case RepetitionInstructionEnum.DaCapo:
+            instruction = VexFlowRepetitionType.DC;
+            break;
+          case RepetitionInstructionEnum.DalSegno:
+            instruction = VexFlowRepetitionType.DS;
+            break;
+          case RepetitionInstructionEnum.Fine:
+            instruction = VexFlowRepetitionType.FINE;
+            break;
+          case RepetitionInstructionEnum.ToCoda:
+            //instruction = "To Coda";
+            break;
+          case RepetitionInstructionEnum.DaCapoAlFine:
+            instruction = VexFlowRepetitionType.DC_AL_FINE;
+            break;
+          case RepetitionInstructionEnum.DaCapoAlCoda:
+            instruction = VexFlowRepetitionType.DC_AL_CODA;
+            break;
+          case RepetitionInstructionEnum.DalSegnoAlFine:
+            instruction = VexFlowRepetitionType.DS_AL_FINE;
+            break;
+          case RepetitionInstructionEnum.DalSegnoAlCoda:
+            instruction = VexFlowRepetitionType.DS_AL_CODA;
+            break;
+          default:
+            break;
+        }
+        if (instruction !== undefined) {
+            this.stave.addModifier(new Vex.Flow.Repetition(instruction, 0, 0), position);
+        }
+    }
+
     /**
     /**
      * Sets the overall x-width of the measure.
      * Sets the overall x-width of the measure.
      * @param width
      * @param width

+ 6 - 42
src/MusicalScore/Graphical/VexFlow/VexFlowMusicSheetCalculator.ts

@@ -11,7 +11,7 @@ import {GraphicalTie} from "../GraphicalTie";
 import {Tie} from "../../VoiceData/Tie";
 import {Tie} from "../../VoiceData/Tie";
 import {SourceMeasure} from "../../VoiceData/SourceMeasure";
 import {SourceMeasure} from "../../VoiceData/SourceMeasure";
 import {MultiExpression} from "../../VoiceData/Expressions/MultiExpression";
 import {MultiExpression} from "../../VoiceData/Expressions/MultiExpression";
-import {RepetitionInstruction, RepetitionInstructionEnum} from "../../VoiceData/Instructions/RepetitionInstruction";
+import {RepetitionInstruction} from "../../VoiceData/Instructions/RepetitionInstruction";
 import {Beam} from "../../VoiceData/Beam";
 import {Beam} from "../../VoiceData/Beam";
 import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
 import {ClefInstruction} from "../../VoiceData/Instructions/ClefInstruction";
 import {OctaveEnum} from "../../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
 import {OctaveEnum} from "../../VoiceData/Expressions/ContinuousExpressions/OctaveShift";
@@ -29,7 +29,6 @@ import Vex = require("vexflow");
 import {Logging} from "../../../Common/Logging";
 import {Logging} from "../../../Common/Logging";
 import {unitInPixels} from "./VexFlowMusicSheetDrawer";
 import {unitInPixels} from "./VexFlowMusicSheetDrawer";
 import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
 import {VexFlowGraphicalNote} from "./VexFlowGraphicalNote";
-import {VexFlowStaffLine} from "./VexFlowStaffLine";
 
 
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
 export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
     constructor() {
     constructor() {
@@ -254,55 +253,20 @@ export class VexFlowMusicSheetCalculator extends MusicSheetCalculator {
      */
      */
     protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void {
     protected calculateWordRepetitionInstruction(repetitionInstruction: RepetitionInstruction, measureIndex: number): void {
       // find first visible StaffLine
       // find first visible StaffLine
-      let staffLine: VexFlowStaffLine = undefined;
+      let uppermostMeasure: VexFlowMeasure = undefined;
       const measures: VexFlowMeasure[]  = <VexFlowMeasure[]>this.graphicalMusicSheet.MeasureList[measureIndex];
       const measures: VexFlowMeasure[]  = <VexFlowMeasure[]>this.graphicalMusicSheet.MeasureList[measureIndex];
       for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
       for (let idx: number = 0, len: number = measures.length; idx < len; ++idx) {
         const graphicalMeasure: VexFlowMeasure = measures[idx];
         const graphicalMeasure: VexFlowMeasure = measures[idx];
         if (graphicalMeasure.ParentStaffLine !== undefined && graphicalMeasure.ParentStaff.ParentInstrument.Visible) {
         if (graphicalMeasure.ParentStaffLine !== undefined && graphicalMeasure.ParentStaff.ParentInstrument.Visible) {
-          staffLine = <VexFlowStaffLine>graphicalMeasure.ParentStaffLine;
-          break;
+            uppermostMeasure = <VexFlowMeasure>graphicalMeasure;
+            break;
         }
         }
       }
       }
       // ToDo: feature/Repetitions
       // ToDo: feature/Repetitions
       // now create corresponding graphical symbol or Text in VexFlow:
       // now create corresponding graphical symbol or Text in VexFlow:
       // use top measure and staffline for positioning.
       // use top measure and staffline for positioning.
-      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;
+      if (uppermostMeasure !== undefined) {
+        uppermostMeasure.addWordRepetition(repetitionInstruction.type);
       }
       }
     }
     }
 
 

+ 25 - 29
src/MusicalScore/ScoreIO/InstrumentReader.ts

@@ -20,13 +20,12 @@ import {ChordSymbolContainer} from "../VoiceData/ChordSymbolContainer";
 import {Logging} from "../../Common/Logging";
 import {Logging} from "../../Common/Logging";
 import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
 import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
 import {ChordSymbolReader} from "./MusicSymbolModules/ChordSymbolReader";
 import {ChordSymbolReader} from "./MusicSymbolModules/ChordSymbolReader";
+import { RepetitionInstructionReader } from "./MusicSymbolModules/RepetitionInstructionReader";
 //import Dictionary from "typescript-collections/dist/lib/Dictionary";
 //import Dictionary from "typescript-collections/dist/lib/Dictionary";
 
 
 // FIXME: The following classes are missing
 // FIXME: The following classes are missing
-//type repetitionInstructionReader = any;
 //type ChordSymbolContainer = any;
 //type ChordSymbolContainer = any;
 //type SlurReader = any;
 //type SlurReader = any;
-//type RepetitionInstructionReader = any;
 //type ExpressionReader = any;
 //type ExpressionReader = any;
 //declare class MusicSymbolModuleFactory {
 //declare class MusicSymbolModuleFactory {
 //  public static createSlurReader(x: any): any;
 //  public static createSlurReader(x: any): any;
@@ -44,10 +43,6 @@ import {ChordSymbolReader} from "./MusicSymbolModules/ChordSymbolReader";
 //  }
 //  }
 //}
 //}
 
 
-/**
- * To be implemented
- */
-export type RepetitionInstructionReader = any;
 
 
 /**
 /**
  * An InstrumentReader is used during the reading phase to keep parsing new measures from the MusicXML file
  * An InstrumentReader is used during the reading phase to keep parsing new measures from the MusicXML file
@@ -56,7 +51,7 @@ export type RepetitionInstructionReader = any;
 export class InstrumentReader {
 export class InstrumentReader {
 
 
   constructor(repetitionInstructionReader: RepetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
   constructor(repetitionInstructionReader: RepetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
-      // this.repetitionInstructionReader = repetitionInstructionReader;
+      this.repetitionInstructionReader = repetitionInstructionReader;
       this.xmlMeasureList = xmlMeasureList;
       this.xmlMeasureList = xmlMeasureList;
       this.musicSheet = instrument.GetMusicSheet;
       this.musicSheet = instrument.GetMusicSheet;
       this.instrument = instrument;
       this.instrument = instrument;
@@ -69,7 +64,7 @@ export class InstrumentReader {
       // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
       // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
   }
   }
 
 
-  // private repetitionInstructionReader: RepetitionInstructionReader;
+  private repetitionInstructionReader: RepetitionInstructionReader;
   private xmlMeasureList: IXmlElement[];
   private xmlMeasureList: IXmlElement[];
   private musicSheet: MusicSheet;
   private musicSheet: MusicSheet;
   private slurReader: any; // (*) SlurReader;
   private slurReader: any; // (*) SlurReader;
@@ -124,9 +119,9 @@ export class InstrumentReader {
     }
     }
     this.currentMeasure = currentMeasure;
     this.currentMeasure = currentMeasure;
     this.inSourceMeasureInstrumentIndex = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument);
     this.inSourceMeasureInstrumentIndex = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument);
-    // (*) if (this.repetitionInstructionReader !== undefined) {
-    //  this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
-    //}
+    if (this.repetitionInstructionReader !== undefined) {
+     this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
+    }
     let currentFraction: Fraction = new Fraction(0, 1);
     let currentFraction: Fraction = new Fraction(0, 1);
     let previousFraction: Fraction = new Fraction(0, 1);
     let previousFraction: Fraction = new Fraction(0, 1);
     let divisionsException: boolean = false;
     let divisionsException: boolean = false;
@@ -309,15 +304,17 @@ export class InstrumentReader {
         } else if (xmlNode.name === "direction") {
         } else if (xmlNode.name === "direction") {
           // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
           // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
           // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
           // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
-          // let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
-          // if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
-            // relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
-          // }
-                    // unused:
-                    // let handeled: boolean = false;
-                    // if (this.repetitionInstructionReader !== undefined) {
-          //  handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
-          //                                                                                              relativePositionInMeasure);
+          let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
+          if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
+            relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
+          }
+          const directionTypeNode: IXmlElement = xmlNode.element("direction-type");
+          //let handeled: boolean = false;
+          if (this.repetitionInstructionReader !== undefined) {
+            //handeled =
+            this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
+                                                                                            relativePositionInMeasure);
+          }
           //}
           //}
           //if (!handeled) {
           //if (!handeled) {
           //  let expressionReader: ExpressionReader = this.expressionReaders[0];
           //  let expressionReader: ExpressionReader = this.expressionReaders[0];
@@ -339,15 +336,14 @@ export class InstrumentReader {
           //  }
           //  }
           //}
           //}
         } else if (xmlNode.name === "barline") {
         } else if (xmlNode.name === "barline") {
-
-          //if (this.repetitionInstructionReader !== undefined) {
-          //  let measureEndsSystem: boolean = false;
-          //  this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
-          //  if (measureEndsSystem) {
-          //    this.currentMeasure.BreakSystemAfter = true;
-          //    this.currentMeasure.endsPiece = true;
-          //  }
-          //}
+          if (this.repetitionInstructionReader !== undefined) {
+           const measureEndsSystem: boolean = false;
+           this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
+           if (measureEndsSystem) {
+             this.currentMeasure.BreakSystemAfter = true;
+             this.currentMeasure.endsPiece = true;
+           }
+          }
         } else if (xmlNode.name === "sound") {
         } else if (xmlNode.name === "sound") {
           // (*) MetronomeReader.readTempoInstruction(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
           // (*) MetronomeReader.readTempoInstruction(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
         } else if (xmlNode.name === "harmony") {
         } else if (xmlNode.name === "harmony") {

+ 4 - 2
src/MusicalScore/VoiceData/Instructions/RepetitionInstruction.ts

@@ -44,14 +44,16 @@ export class RepetitionInstruction /*implements IComparable*/ {
     constructor(measureIndex: number, type: RepetitionInstructionEnum, alignment: AlignmentType = AlignmentType.End,
     constructor(measureIndex: number, type: RepetitionInstructionEnum, alignment: AlignmentType = AlignmentType.End,
                 parentRepetition: Repetition = undefined, endingIndices: number[] = undefined) {
                 parentRepetition: Repetition = undefined, endingIndices: number[] = undefined) {
         this.measureIndex = measureIndex;
         this.measureIndex = measureIndex;
-        this.endingIndices = endingIndices.slice();
+        if (endingIndices !== undefined) {
+            this.endingIndices = endingIndices.slice();
+        }
         this.type = type;
         this.type = type;
         this.alignment = alignment;
         this.alignment = alignment;
         this.parentRepetition = parentRepetition;
         this.parentRepetition = parentRepetition;
     }
     }
 
 
     public measureIndex: number;
     public measureIndex: number;
-    public endingIndices: number[];
+    public endingIndices: number[] = undefined;
     public type: RepetitionInstructionEnum;
     public type: RepetitionInstructionEnum;
     public alignment: AlignmentType;
     public alignment: AlignmentType;
     public parentRepetition: Repetition;
     public parentRepetition: Repetition;