瀏覽代碼

Ported RepetitionInstructionReader, a basic RepetitionCalculator and adapted code for their usage.

Matthias 8 年之前
父節點
當前提交
69839ff6fa

+ 11 - 0
src/Common/Strings/StringUtil.ts

@@ -0,0 +1,11 @@
+export class StringUtil {
+  public static StringContainsSeparatedWord(str: string, word: string): boolean {
+    if (str === word ||
+      str.search(" " + word) !== -1 ||
+      str.search(word + " ") !== -1 ||
+      str.search(word + ".") !== -1) {
+      return true;
+    }
+    return false;
+  }
+}

+ 8 - 0
src/MusicalScore/Interfaces/IAfterSheetReadingModule.ts

@@ -0,0 +1,8 @@
+import {MusicSheet} from "../MusicSheet";
+/**
+ * Created by Matthias on 22.02.2017.
+ */
+
+export interface IAfterSheetReadingModule {
+  calculate(musicSheet: MusicSheet): void;
+}

+ 21 - 26
src/MusicalScore/ScoreIO/MusicSheetReader.ts

@@ -17,31 +17,26 @@ import {SubInstrument} from "../SubInstrument";
 import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
 import {AbstractNotationInstruction} from "../VoiceData/Instructions/AbstractNotationInstruction";
 import {Label} from "../Label";
-
-/**
- * To be implemented
- */
-type RepetitionInstructionReader = any;
-/**
- * To be implemented
- */
-type RepetitionCalculator = any;
+import {MusicSymbolModuleFactory} from "./MusicSymbolModuleFactory";
+import {IAfterSheetReadingModule} from "../Interfaces/IAfterSheetReadingModule";
+import {RepetitionInstructionReader} from "./MusicSymbolModules/RepetitionInstructionReader";
+import {RepetitionCalculator} from "./MusicSymbolModules/RepetitionCalculator";
 
 export class MusicSheetReader /*implements IMusicSheetReader*/ {
 
-    //constructor(afterSheetReadingModules: IAfterSheetReadingModule[]) {
-    //  if (afterSheetReadingModules === undefined) {
-    //    this.afterSheetReadingModules = [];
-    //  } else {
-    //    this.afterSheetReadingModules = afterSheetReadingModules;
-    //  }
-    //  this.repetitionInstructionReader = MusicSymbolModuleFactory.createRepetitionInstructionReader();
-    //  this.repetitionCalculator = MusicSymbolModuleFactory.createRepetitionCalculator();
-    //}
+    constructor(afterSheetReadingModules: IAfterSheetReadingModule[] = undefined) {
+     if (afterSheetReadingModules === undefined) {
+       this.afterSheetReadingModules = [];
+     } else {
+       this.afterSheetReadingModules = afterSheetReadingModules;
+     }
+     this.repetitionInstructionReader = MusicSymbolModuleFactory.createRepetitionInstructionReader();
+     this.repetitionCalculator = MusicSymbolModuleFactory.createRepetitionCalculator();
+    }
 
     private repetitionInstructionReader: RepetitionInstructionReader;
     private repetitionCalculator: RepetitionCalculator;
-    // private afterSheetReadingModules: IAfterSheetReadingModule[];
+    private afterSheetReadingModules: IAfterSheetReadingModule[];
     private musicSheet: MusicSheet;
     private completeNumberOfStaves: number = 0;
     private currentMeasure: SourceMeasure;
@@ -176,16 +171,16 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         if (this.repetitionInstructionReader !== undefined) {
             this.repetitionInstructionReader.removeRedundantInstructions();
             if (this.repetitionCalculator !== undefined) {
-                this.repetitionCalculator.calculateRepetitions(this.musicSheet, this.repetitionInstructionReader.RepetitionInstructions);
+                this.repetitionCalculator.calculateRepetitions(this.musicSheet, this.repetitionInstructionReader.repetitionInstructions);
             }
         }
         this.musicSheet.checkForInstrumentWithNoVoice();
         this.musicSheet.fillStaffList();
         //this.musicSheet.DefaultStartTempoInBpm = this.musicSheet.SheetPlaybackSetting.BeatsPerMinute;
-        //for (let idx: number = 0, len: number = this.afterSheetReadingModules.length; idx < len; ++idx) {
-        //  let afterSheetReadingModule: IAfterSheetReadingModule = this.afterSheetReadingModules[idx];
-        //  afterSheetReadingModule.calculate(this.musicSheet);
-        //}
+        for (let idx: number = 0, len: number = this.afterSheetReadingModules.length; idx < len; ++idx) {
+         let afterSheetReadingModule: IAfterSheetReadingModule = this.afterSheetReadingModules[idx];
+         afterSheetReadingModule.calculate(this.musicSheet);
+        }
 
         return this.musicSheet;
     }
@@ -194,7 +189,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
         let instrumentDict: { [_: string]: Instrument; } = this.createInstrumentGroups(partList);
         this.completeNumberOfStaves = this.getCompleteNumberOfStavesFromXml(partInst);
         if (partInst.length !== 0) {
-            // (*) this.repetitionInstructionReader.MusicSheet = this.musicSheet;
+            this.repetitionInstructionReader.MusicSheet = this.musicSheet;
             this.currentFraction = new Fraction(0, 1);
             this.currentMeasure = undefined;
             this.previousMeasure = undefined;
@@ -220,7 +215,7 @@ export class MusicSheetReader /*implements IMusicSheetReader*/ {
                 currentInstrument.createStaves(instrumentNumberOfStaves);
                 instrumentReaders.push(new InstrumentReader(this.repetitionInstructionReader, xmlMeasureList, currentInstrument));
                 if (this.repetitionInstructionReader !== undefined) {
-                    this.repetitionInstructionReader.XmlMeasureList[counter] = xmlMeasureList;
+                    this.repetitionInstructionReader.xmlMeasureList[counter] = xmlMeasureList;
                 }
                 counter++;
             }

+ 31 - 0
src/MusicalScore/ScoreIO/MusicSymbolModuleFactory.ts

@@ -0,0 +1,31 @@
+import {RepetitionInstructionReader} from "./MusicSymbolModules/RepetitionInstructionReader";
+import {RepetitionCalculator} from "./MusicSymbolModules/RepetitionCalculator";
+
+export class MusicSymbolModuleFactory {
+  public static createRepetitionInstructionReader(): RepetitionInstructionReader {
+    return new RepetitionInstructionReader();
+  }
+
+  public static createRepetitionCalculator(): RepetitionCalculator {
+    return new RepetitionCalculator();
+  }
+
+  /*
+   public static createExpressionGenerator(musicSheet: MusicSheet,
+   instrument: Instrument, staffNumber: number): ExpressionReader {
+   return new ExpressionReader(musicSheet, instrument, staffNumber);
+   }
+
+   public static createSlurReader(musicSheet: MusicSheet): SlurReader {
+   return new SlurReader(musicSheet);
+   }
+
+   public static createLyricsReader(musicSheet: MusicSheet): LyricsReader {
+   return new LyricsReader(musicSheet);
+   }
+
+   public static createArticulationReader(): ArticulationReader {
+   return new ArticulationReader();
+   }
+   */
+}

+ 89 - 0
src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionCalculator.ts

@@ -0,0 +1,89 @@
+import {SourceMeasure} from "../../VoiceData/SourceMeasure";
+import {RepetitionInstruction, RepetitionInstructionEnum, AlignmentType} from "../../VoiceData/Instructions/RepetitionInstruction";
+import {ArgumentOutOfRangeException} from "../../Exceptions";
+import {MusicSheet} from "../../MusicSheet";
+
+export class RepetitionCalculator {
+  private musicSheet: MusicSheet;
+  private repetitionInstructions: RepetitionInstruction[] = [];
+  private lastRepetitionCommonPartStartIndex: number = 0;
+  private currentMeasure: SourceMeasure;
+  private currentMeasureIndex: number;
+
+  public calculateRepetitions(musicSheet: MusicSheet, repetitionInstructions: RepetitionInstruction[]): void {
+    this.musicSheet = <MusicSheet>musicSheet;
+    this.repetitionInstructions = repetitionInstructions;
+    this.lastRepetitionCommonPartStartIndex = 0;
+    let sourceMeasures: SourceMeasure[] = this.musicSheet.SourceMeasures;
+    for (let idx: number = 0, len: number = this.repetitionInstructions.length; idx < len; ++idx) {
+      let instruction: RepetitionInstruction = this.repetitionInstructions[idx];
+      this.currentMeasureIndex = instruction.measureIndex;
+      this.currentMeasure = sourceMeasures[this.currentMeasureIndex];
+      this.handleRepetitionInstructions(instruction);
+    }
+    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) {
+        measure.FirstRepetitionInstructions.sort(RepetitionInstruction.compare);
+      }
+      if (measure.LastRepetitionInstructions.length > 1) {
+        measure.LastRepetitionInstructions.sort(RepetitionInstruction.compare);
+      }
+    }
+  }
+
+  private handleRepetitionInstructions(currentRepetitionInstruction: RepetitionInstruction): boolean {
+    switch (currentRepetitionInstruction.type) {
+      case RepetitionInstructionEnum.StartLine:
+        this.currentMeasure.FirstRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.BackJumpLine:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.Ending:
+        if (currentRepetitionInstruction.alignment === AlignmentType.Begin) {
+          this.currentMeasure.FirstRepetitionInstructions.push(currentRepetitionInstruction);
+        } else {
+          for (let idx: number = 0, len: number = currentRepetitionInstruction.endingIndices.length; idx < len; ++idx) {
+            this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+          }
+        }
+        break;
+      case RepetitionInstructionEnum.Segno:
+        this.currentMeasure.FirstRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.Fine:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.ToCoda:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.Coda:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.DaCapo:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.DalSegno:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.DalSegnoAlFine:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.DaCapoAlFine:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.DalSegnoAlCoda:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.DaCapoAlCoda:
+        this.currentMeasure.LastRepetitionInstructions.push(currentRepetitionInstruction);
+        break;
+      case RepetitionInstructionEnum.None:
+        break;
+      default:
+        throw new ArgumentOutOfRangeException("currentRepetitionInstruction");
+    }
+    return true;
+  }
+}

+ 353 - 0
src/MusicalScore/ScoreIO/MusicSymbolModules/RepetitionInstructionReader.ts

@@ -0,0 +1,353 @@
+import {MusicSheet} from "../../MusicSheet";
+import {IXmlElement} from "../../../Common/FileIO/Xml";
+import {SourceMeasure} from "../../VoiceData/SourceMeasure";
+import {RepetitionInstruction, RepetitionInstructionEnum, AlignmentType} from "../../VoiceData/Instructions/RepetitionInstruction";
+import {StringUtil} from "../../../Common/Strings/StringUtil";
+export class RepetitionInstructionReader {
+  public repetitionInstructions: RepetitionInstruction[];
+  public xmlMeasureList: IXmlElement[][];
+  private musicSheet: MusicSheet;
+  private currentMeasureIndex: number;
+
+  public set MusicSheet(value: MusicSheet) {
+    this.musicSheet = value;
+    this.xmlMeasureList = new Array(this.musicSheet.Instruments.length);
+    this.repetitionInstructions = [];
+  }
+
+  public prepareReadingMeasure(measure: SourceMeasure, currentMeasureIndex: number): void {
+    this.currentMeasureIndex = currentMeasureIndex;
+  }
+
+  public handleLineRepetitionInstructions(barlineNode: IXmlElement, pieceEndingDetected: boolean): void {
+    pieceEndingDetected = false;
+    if (barlineNode.elements().length > 0) {
+      let location: string = "";
+      let hasRepeat: boolean = false;
+      let direction: string = "";
+      let type: string = "";
+      let style: string = "";
+      let endingIndices: number[] = [];
+      let styleNode: IXmlElement = barlineNode.element("bar-style");
+      if (styleNode !== undefined) {
+        style = styleNode.value;
+      }
+      if (barlineNode.attributes().length > 0 && barlineNode.attribute("location") !== undefined) {
+        location = barlineNode.attribute("location").value;
+      } else {
+        location = "right";
+      }
+      let barlineNodeElements: IXmlElement[] = barlineNode.elements();
+      for (let idx: number = 0, len: number = barlineNodeElements.length; idx < len; ++idx) {
+        let childNode: IXmlElement = barlineNodeElements[idx];
+        if ("repeat" === childNode.name && childNode.hasAttributes) {
+          hasRepeat = true;
+          direction = childNode.attribute("direction").value;
+        } else if ( "ending" === childNode.name && childNode.hasAttributes &&
+                    childNode.attribute("type") !== undefined && childNode.attribute("number") !== undefined) {
+          type = childNode.attribute("type").value;
+          let num: string = childNode.attribute("number").value;
+          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]");
+            if (separatedEndingIndex.search("-") !== -1 && indices.length === 2) {
+              let startIndex: number = parseInt(indices[0], 10);
+              let endIndex: number = parseInt(indices[1], 10);
+              for (let index: number = startIndex; index <= endIndex; index++) {
+                endingIndices.push(index);
+              }
+            } else {
+              for (let idx3: number = 0, len3: number = indices.length; idx3 < len3; ++idx3) {
+                let index: string = indices[idx3];
+                endingIndices.push(parseInt(index, 10));
+              }
+            }
+          }
+        }
+      }
+      if (style === "light-heavy" && endingIndices.length === 0 && !hasRepeat) {
+        pieceEndingDetected = true;
+      }
+      if (hasRepeat || endingIndices.length > 0) {
+        if (location === "left") {
+          if (type === "start") {
+            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.Ending,
+                                                                                  AlignmentType.Begin, undefined, endingIndices);
+            this.addInstruction(this.repetitionInstructions, newInstruction);
+          }
+          if (direction === "forward") {
+            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.StartLine);
+            this.addInstruction(this.repetitionInstructions, newInstruction);
+          }
+        } else {
+          if (type === "stop" || type === "discontinue") {
+            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.Ending,
+                                                                                  AlignmentType.End, undefined, endingIndices);
+            this.addInstruction(this.repetitionInstructions, newInstruction);
+          }
+          if (direction === "backward") {
+            let newInstruction: RepetitionInstruction = new RepetitionInstruction(this.currentMeasureIndex, RepetitionInstructionEnum.BackJumpLine);
+            this.addInstruction(this.repetitionInstructions, newInstruction);
+          }
+        }
+      }
+    }
+  }
+
+  public handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode: IXmlElement, relativeMeasurePosition: number): boolean {
+    let wordsNode: IXmlElement = directionTypeNode.element("words");
+    if (wordsNode !== undefined) {
+      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) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegnoAlFine);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "d.s. al coda") ||
+        StringUtil.StringContainsSeparatedWord(innerText, "d. s. al coda")) {
+        let measureIndex: number = this.currentMeasureIndex;
+        if (relativeMeasurePosition < 0.5) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegnoAlCoda);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      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) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapoAlFine);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "d.c. al coda") ||
+        StringUtil.StringContainsSeparatedWord(innerText, "d. c. al coda")) {
+        let measureIndex: number = this.currentMeasureIndex;
+        if (relativeMeasurePosition < 0.5) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapoAlCoda);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "d.c.") ||
+        StringUtil.StringContainsSeparatedWord(innerText, "d. c.") ||
+        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) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DaCapo);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "d.s.") ||
+        StringUtil.StringContainsSeparatedWord(innerText, "d. s.") ||
+        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) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.DalSegno);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "tocoda") ||
+        StringUtil.StringContainsSeparatedWord(innerText, "to coda") ||
+        StringUtil.StringContainsSeparatedWord(innerText, "a coda") ||
+        StringUtil.StringContainsSeparatedWord(innerText, "a la coda")) {
+        let measureIndex: number = this.currentMeasureIndex;
+        if (relativeMeasurePosition < 0.5) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.ToCoda);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "fine")) {
+        let measureIndex: number = this.currentMeasureIndex;
+        if (relativeMeasurePosition < 0.5) {
+          measureIndex--;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Fine);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "coda")) {
+        let measureIndex: number = this.currentMeasureIndex;
+        if (relativeMeasurePosition > 0.5) {
+          measureIndex++;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Coda);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+      if (StringUtil.StringContainsSeparatedWord(innerText, "segno")) {
+        let measureIndex: number = this.currentMeasureIndex;
+        if (relativeMeasurePosition > 0.5) {
+          measureIndex++;
+        }
+        let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Segno);
+        this.addInstruction(this.repetitionInstructions, newInstruction);
+        return true;
+      }
+    } else if (directionTypeNode.element("segno") !== undefined) {
+      let measureIndex: number = this.currentMeasureIndex;
+      if (relativeMeasurePosition > 0.5) {
+        measureIndex++;
+      }
+      let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Segno);
+      this.addInstruction(this.repetitionInstructions, newInstruction);
+      return true;
+    } else if (directionTypeNode.element("coda") !== undefined) {
+      let measureIndex: number = this.currentMeasureIndex;
+      if (relativeMeasurePosition > 0.5) {
+        measureIndex++;
+      }
+      let newInstruction: RepetitionInstruction = new RepetitionInstruction(measureIndex, RepetitionInstructionEnum.Coda);
+      this.addInstruction(this.repetitionInstructions, newInstruction);
+      return true;
+    }
+    return false;
+  }
+
+  public removeRedundantInstructions(): void {
+    let segnoCount: number = 0;
+    let codaCount: number = 0;
+    let fineCount: number = 0;
+    let toCodaCount: number = 0;
+    let dalSegnaCount: number = 0;
+    for (let index: number = 0; index < this.repetitionInstructions.length; index++) {
+      let instruction: RepetitionInstruction = this.repetitionInstructions[index];
+      switch (instruction.type) {
+        case RepetitionInstructionEnum.Coda:
+          if (toCodaCount > 0) {
+            if (this.findInstructionInPreviousMeasure(index, instruction.measureIndex, RepetitionInstructionEnum.ToCoda)) {
+              instruction.type = RepetitionInstructionEnum.None;
+            }
+          }
+          if (codaCount === 0 && toCodaCount === 0) {
+            instruction.type = RepetitionInstructionEnum.ToCoda;
+            instruction.alignment = AlignmentType.End;
+            instruction.measureIndex--;
+          }
+          break;
+        case RepetitionInstructionEnum.Segno:
+          if (segnoCount - dalSegnaCount > 0) {
+            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) {
+                      instr.type = RepetitionInstructionEnum.DalSegnoAlCoda;
+                    } else {
+                      instr.type = RepetitionInstructionEnum.DalSegno;
+                    }
+                    instruction.type = RepetitionInstructionEnum.None;
+                    foundInstruction = true;
+                    break;
+                  case RepetitionInstructionEnum.DalSegno:
+                  case RepetitionInstructionEnum.DalSegnoAlFine:
+                  case RepetitionInstructionEnum.DalSegnoAlCoda:
+                    instruction.type = RepetitionInstructionEnum.None;
+                    foundInstruction = true;
+                    break;
+                  default:
+                    break;
+                }
+              }
+              if (foundInstruction) {
+                break;
+              }
+            }
+            if (foundInstruction) {
+              break;
+            }
+            if (toCodaCount - codaCount > 0) {
+              instruction.type = RepetitionInstructionEnum.DalSegnoAlCoda;
+            } else {
+              instruction.type = RepetitionInstructionEnum.DalSegno;
+            }
+            instruction.alignment = AlignmentType.End;
+            instruction.measureIndex--;
+          }
+          break;
+        default:
+          break;
+      }
+      if (this.backwardSearchForPreviousIdenticalInstruction(index, instruction) || instruction.type === RepetitionInstructionEnum.None) {
+        this.repetitionInstructions.splice(index, 1);
+        index--;
+      } else {
+        switch (instruction.type) {
+          case RepetitionInstructionEnum.Fine:
+            fineCount++;
+            break;
+          case RepetitionInstructionEnum.ToCoda:
+            toCodaCount++;
+            break;
+          case RepetitionInstructionEnum.Coda:
+            codaCount++;
+            break;
+          case RepetitionInstructionEnum.Segno:
+            segnoCount++;
+            break;
+          case RepetitionInstructionEnum.DalSegnoAlFine:
+          case RepetitionInstructionEnum.DalSegnoAlCoda:
+            dalSegnaCount++;
+            break;
+          default:
+            break;
+        }
+      }
+    }
+    this.repetitionInstructions.sort(RepetitionInstruction.compare);
+  }
+
+  private findInstructionInPreviousMeasure(currentInstructionIndex: number, currentMeasureIndex: number, searchedType: RepetitionInstructionEnum): boolean {
+    for (let index: number = currentInstructionIndex - 1; index >= 0; index--) {
+      let instruction: RepetitionInstruction = this.repetitionInstructions[index];
+      if (currentMeasureIndex - instruction.measureIndex === 1 && instruction.type === searchedType) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private backwardSearchForPreviousIdenticalInstruction(currentInstructionIndex: number, currentInstruction: RepetitionInstruction): boolean {
+    for (let index: number = currentInstructionIndex - 1; index >= 0; index--) {
+      let instruction: RepetitionInstruction = this.repetitionInstructions[index];
+      if (instruction.equals(currentInstruction)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  private addInstruction(currentRepetitionInstructions: RepetitionInstruction[], newInstruction: RepetitionInstruction): void {
+    let addInstruction: boolean = true;
+    for (let idx: number = 0, len: number = currentRepetitionInstructions.length; idx < len; ++idx) {
+      let repetitionInstruction: RepetitionInstruction = currentRepetitionInstructions[idx];
+      if (newInstruction.equals(repetitionInstruction)) {
+        addInstruction = false;
+        break;
+      }
+    }
+    if (addInstruction) {
+      currentRepetitionInstructions.push(newInstruction);
+    }
+  }
+}

+ 9 - 8
src/MusicalScore/VoiceData/Instructions/RepetitionInstruction.ts

@@ -41,7 +41,8 @@ export class RepetitionInstruction /*implements IComparable*/ {
 
      }
      */
-    constructor(measureIndex: number, endingIndices: number[], type: RepetitionInstructionEnum, alignment: AlignmentType, parentRepetition: Repetition) {
+    constructor(measureIndex: number, type: RepetitionInstructionEnum, alignment: AlignmentType = AlignmentType.End,
+                parentRepetition: Repetition = undefined, endingIndices: number[] = undefined) {
         this.measureIndex = measureIndex;
         this.endingIndices = endingIndices.slice();
         this.type = type;
@@ -55,18 +56,18 @@ export class RepetitionInstruction /*implements IComparable*/ {
     public alignment: AlignmentType;
     public parentRepetition: Repetition;
 
-    public CompareTo(obj: Object): number {
-        let other: RepetitionInstruction = <RepetitionInstruction>obj;
-        if (this.measureIndex > other.measureIndex) {
+    public static compare(one: RepetitionInstruction, other: RepetitionInstruction): number {
+
+        if (one.measureIndex > other.measureIndex) {
             return 1;
-        } else if (this.measureIndex < other.measureIndex) {
+        } else if (one.measureIndex < other.measureIndex) {
             return -1;
         }
-        if (this.alignment === AlignmentType.Begin) {
+        if (one.alignment === AlignmentType.Begin) {
             if (other.alignment === AlignmentType.End) {
                 return -1;
             }
-            switch (this.type) {
+            switch (one.type) {
                 case RepetitionInstructionEnum.Ending:
                     return 1;
                 case RepetitionInstructionEnum.StartLine:
@@ -86,7 +87,7 @@ export class RepetitionInstruction /*implements IComparable*/ {
             if (other.alignment === AlignmentType.Begin) {
                 return 1;
             }
-            switch (this.type) {
+            switch (one.type) {
                 case RepetitionInstructionEnum.Ending:
                     return -1;
                 case RepetitionInstructionEnum.Fine: