Oliver 9 лет назад
Родитель
Сommit
da7db36fd9
37 измененных файлов с 5239 добавлено и 0 удалено
  1. 242 0
      src/MusicalScore/Instrument.ts
  2. 31 0
      src/MusicalScore/InstrumentalGroup.ts
  3. 6 0
      src/MusicalScore/Interfaces/IQualityFeedbackTone.ts
  4. 63 0
      src/MusicalScore/Label.ts
  5. 105 0
      src/MusicalScore/MusicParts/MusicPartManager.ts
  6. 477 0
      src/MusicalScore/MusicParts/MusicPartManagerIterator.ts
  7. 465 0
      src/MusicalScore/MusicSheet.ts
  8. 51 0
      src/MusicalScore/MusicSource/MappingSourceMusicPart.ts
  9. 23 0
      src/MusicalScore/MusicSource/PartListEntry.ts
  10. 168 0
      src/MusicalScore/MusicSource/Repetition.ts
  11. 44 0
      src/MusicalScore/MusicSource/SourceMusicPart.ts
  12. 930 0
      src/MusicalScore/ScoreIO/InstrumentReader.ts
  13. 720 0
      src/MusicalScore/ScoreIO/MusicSheetReader.ts
  14. 1 0
      src/MusicalScore/ScoreIO/VoiceGenerator.ts
  15. 110 0
      src/MusicalScore/SubInstrument.ts
  16. 39 0
      src/MusicalScore/VoiceData/Beam.ts
  17. 30 0
      src/MusicalScore/VoiceData/HelperObjects/DynamicsContainer.ts
  18. 14 0
      src/MusicalScore/VoiceData/Instructions/AbstractNotationInstruction.ts
  19. 144 0
      src/MusicalScore/VoiceData/Instructions/ClefInstruction.ts
  20. 108 0
      src/MusicalScore/VoiceData/Instructions/KeyInstruction.ts
  21. 150 0
      src/MusicalScore/VoiceData/Instructions/RepetitionInstruction.ts
  22. 58 0
      src/MusicalScore/VoiceData/Instructions/RhythmInstruction.ts
  23. 7 0
      src/MusicalScore/VoiceData/Instructions/TechnicalInstruction.ts
  24. 10 0
      src/MusicalScore/VoiceData/LinkedVoice.ts
  25. 27 0
      src/MusicalScore/VoiceData/Lyrics/LyricsEntry.ts
  26. 26 0
      src/MusicalScore/VoiceData/Lyrics/LyricsWord.ts
  27. 153 0
      src/MusicalScore/VoiceData/Note.ts
  28. 38 0
      src/MusicalScore/VoiceData/OrnamentContainer.ts
  29. 260 0
      src/MusicalScore/VoiceData/SourceMeasure.ts
  30. 142 0
      src/MusicalScore/VoiceData/SourceStaffEntry.ts
  31. 33 0
      src/MusicalScore/VoiceData/Staff.ts
  32. 16 0
      src/MusicalScore/VoiceData/StaffEntryLink.ts
  33. 83 0
      src/MusicalScore/VoiceData/Tie.ts
  34. 34 0
      src/MusicalScore/VoiceData/Tuplet.ts
  35. 50 0
      src/MusicalScore/VoiceData/VerticalSourceStaffEntryContainer.ts
  36. 49 0
      src/MusicalScore/VoiceData/Voice.ts
  37. 332 0
      src/MusicalScore/VoiceData/VoiceEntry.ts

+ 242 - 0
src/MusicalScore/Instrument.ts

@@ -0,0 +1,242 @@
+export class Instrument extends InstrumentalGroup implements ISettableInstrument, IInstrument {
+    constructor(id: number, idString: string, phonicScoreInterface: IPhonicScoreInterface, musicSheet: MusicSheet, parent: InstrumentalGroup) {
+        super(musicSheet, parent);
+        this.phonicScoreInterface = phonicScoreInterface;
+        this.id = id;
+        this.idString = idString;
+        this.nameLabel = new Label(idString);
+    }
+    private phonicScoreInterface: IPhonicScoreInterface;
+    private voices: List<Voice> = new List<Voice>();
+    private staves: List<Staff> = new List<Staff>();
+    private nameLabel: Label;
+    private range: ToneRange;
+    private idString: string;
+    private id: number;
+    private hasLyrics: boolean = false;
+    private hasChordSymbols: boolean = false;
+    private playbackTranspose: number = 0;
+    private lyricVersesNumbers: List<number> = new List<number>();
+    private subInstruments: List<SubInstrument> = new List<SubInstrument>();
+    public get Voices(): List<Voice> {
+        return this.voices;
+    }
+    public get Staves(): List<Staff> {
+        return this.staves;
+    }
+    public get NameLabel(): Label {
+        return this.nameLabel;
+    }
+    public get HasLyrics(): boolean {
+        return this.hasLyrics;
+    }
+    public set HasLyrics(value: boolean) {
+        this.hasLyrics = value;
+    }
+    public get HasChordSymbols(): boolean {
+        return this.hasChordSymbols;
+    }
+    public set HasChordSymbols(value: boolean) {
+        this.hasChordSymbols = value;
+    }
+    public get LyricVersesNumbers(): List<number> {
+        return this.lyricVersesNumbers;
+    }
+    public set LyricVersesNumbers(value: List<number>) {
+        this.lyricVersesNumbers = value;
+    }
+    public get Name(): string {
+        return this.nameLabel.Text;
+    }
+    public set Name(value: string) {
+        this.nameLabel.Text = value;
+    }
+    public set PhonicScoreInterface(value: IPhonicScoreInterface) {
+        this.phonicScoreInterface = value;
+    }
+    public get IdString(): string {
+        return this.idString;
+    }
+    public get Id(): number {
+        return this.id;
+    }
+    public get MidiInstrumentId(): MidiInstrument {
+        return this.subInstruments[0].MidiInstrumentId;
+    }
+    public set MidiInstrumentId(value: MidiInstrument) {
+        this.subInstruments[0].MidiInstrumentId = value;
+    }
+    public get Volume(): number {
+        return this.subInstruments[0].Volume;
+    }
+    public set Volume(value: number) {
+        for (var idx: number = 0, len = this.subInstruments.Count; idx < len; ++idx) {
+            var subInstrument: SubInstrument = this.subInstruments[idx];
+            subInstrument.Volume = value;
+        }
+    }
+    public get PlaybackTranspose(): number {
+        return this.playbackTranspose;
+    }
+    public set PlaybackTranspose(value: number) {
+        this.playbackTranspose = value;
+    }
+    public Highlight: boolean;
+    public get SubInstruments(): List<SubInstrument> {
+        return this.subInstruments;
+    }
+    public getSubInstrument(subInstrumentIdString: string): SubInstrument {
+        for (var idx: number = 0, len = this.subInstruments.Count; idx < len; ++idx) {
+            var subInstrument: SubInstrument = this.subInstruments[idx];
+            if (subInstrument.IdString == subInstrumentIdString) {
+                return subInstrument;
+            }
+        }
+        return null;
+    }
+    public get Visible(): boolean {
+        if (this.voices.Count > 0)
+            return this.Voices[0].Visible;
+        else return false;
+    }
+    public set Visible(value: boolean) {
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var v: Voice = this.Voices[idx];
+            v.Visible = value;
+        }
+    }
+    public get Audible(): boolean {
+        var result: boolean = false;
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var v: Voice = this.Voices[idx];
+            result = result || v.Audible;
+        }
+        return result;
+    }
+    public set Audible(value: boolean) {
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var v: Voice = this.Voices[idx];
+            v.Audible = value;
+        }
+        for (var idx: number = 0, len = this.staves.Count; idx < len; ++idx) {
+            var staff: Staff = this.staves[idx];
+            staff.Audible = value;
+        }
+    }
+    public get Following(): boolean {
+        var result: boolean = false;
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var v: Voice = this.Voices[idx];
+            result = result || v.Following;
+        }
+        return result;
+    }
+    public set Following(value: boolean) {
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var v: Voice = this.Voices[idx];
+            v.Following = value;
+        }
+        for (var idx: number = 0, len = this.staves.Count; idx < len; ++idx) {
+            var staff: Staff = this.staves[idx];
+            staff.Following = value;
+        }
+    }
+    public SetVoiceAudible(voiceId: number, audible: boolean): void {
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var v: Voice = this.Voices[idx];
+            if (v.VoiceId == voiceId) {
+                v.Audible = audible;
+                break;
+            }
+        }
+    }
+    public SetVoiceFollowing(voiceId: number, following: boolean): void {
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var v: Voice = this.Voices[idx];
+            if (v.VoiceId == voiceId) {
+                v.Following = following;
+                break;
+            }
+        }
+    }
+    public SetStaffAudible(staffId: number, audible: boolean): void {
+        var staff: Staff = this.staves[staffId - 1];
+        staff.Audible = audible;
+        if (audible) {
+            for (var idx: number = 0, len = staff.Voices.Count; idx < len; ++idx) {
+                var v: Voice = staff.Voices[idx];
+                v.Audible = true;
+            }
+        }
+        else {
+            for (var idx: number = 0, len = staff.Voices.Count; idx < len; ++idx) {
+                var voice: Voice = staff.Voices[idx];
+                var isAudibleInOtherStaves: boolean = false;
+                for (var idx2: number = 0, len2 = this.Staves.Count; idx2 < len2; ++idx2) {
+                    var st: Staff = this.Staves[idx2];
+                    if (st.Id == staffId || !st.Audible)
+                        continue;
+                    for (var idx3: number = 0, len3 = st.Voices.Count; idx3 < len3; ++idx3) {
+                        var v: Voice = st.Voices[idx3];
+                        if (v == voice)
+                            isAudibleInOtherStaves = true;
+                    }
+                }
+                if (!isAudibleInOtherStaves)
+                    voice.Audible = false;
+            }
+        }
+    }
+    public SetStaffFollow(staffId: number, follow: boolean): void {
+        var staff: Staff = this.staves[staffId - 1];
+        staff.Following = follow;
+        if (follow) {
+            for (var idx: number = 0, len = staff.Voices.Count; idx < len; ++idx) {
+                var v: Voice = staff.Voices[idx];
+                v.Following = true;
+            }
+        }
+        else {
+            for (var idx: number = 0, len = staff.Voices.Count; idx < len; ++idx) {
+                var voice: Voice = staff.Voices[idx];
+                var isFollowingInOtherStaves: boolean = false;
+                for (var idx2: number = 0, len2 = this.Staves.Count; idx2 < len2; ++idx2) {
+                    var st: Staff = this.Staves[idx2];
+                    if (st.Id == staffId || !st.Following)
+                        continue;
+                    for (var idx3: number = 0, len3 = st.Voices.Count; idx3 < len3; ++idx3) {
+                        var v: Voice = st.Voices[idx3];
+                        if (v == voice)
+                            isFollowingInOtherStaves = true;
+                    }
+                }
+                if (!isFollowingInOtherStaves)
+                    voice.Following = false;
+            }
+        }
+    }
+    public areAllVoiceVisible(): boolean {
+        var counter: number = 0;
+        for (var idx: number = 0, len = this.Voices.Count; idx < len; ++idx) {
+            var voice: Voice = this.Voices[idx];
+            if (voice.Visible)
+                counter++;
+        }
+        if (counter == this.voices.Count)
+            return true;
+        return false;
+    }
+    public createStaves(numberOfStaves: number): void {
+        for (var i: number = 0; i < numberOfStaves; i++) {
+            var staff: Staff = new Staff(this, i + 1);
+            this.staves.Add(staff);
+        }
+    }
+    public SetInstrumentParameter(parameter: InstrumentParameters, value: Object): void {
+        this.phonicScoreInterface.RequestInstrumentParameter(this.Id, parameter, value);
+    }
+    public InstrumentParameterChanged: InstrumentParameterChangedDelegate;
+    public Dispose(): void {
+        this.InstrumentParameterChanged = null;
+    }
+}

+ 31 - 0
src/MusicalScore/InstrumentalGroup.ts

@@ -0,0 +1,31 @@
+export class InstrumentalGroup {
+    constructor(musicSheet: MusicSheet, parent: InstrumentalGroup) {
+        this.musicSheet = musicSheet;
+        this.parent = parent;
+    }
+    constructor(name: string, musicSheet: MusicSheet, parent: InstrumentalGroup) {
+        this.name = name;
+        this.musicSheet = musicSheet;
+        this.parent = parent;
+    }
+    private name: string;
+    private musicSheet: MusicSheet;
+    private parent: InstrumentalGroup;
+    private instrumentalGroups: List<InstrumentalGroup> = new List<InstrumentalGroup>();
+    private instruments: List<Instrument> = new List<Instrument>();
+    public get InstrumentalGroups(): List<InstrumentalGroup> {
+        return this.instrumentalGroups;
+    }
+    public get Parent(): InstrumentalGroup {
+        return this.parent;
+    }
+    public get Name(): string {
+        return this.name;
+    }
+    public set Name(value: string) {
+        this.name = value;
+    }
+    public get GetMusicSheet(): MusicSheet {
+        return this.musicSheet;
+    }
+}

+ 6 - 0
src/MusicalScore/Interfaces/IQualityFeedbackTone.ts

@@ -0,0 +1,6 @@
+export interface IQualityFeedbackTone {
+    ParentNote: Note;
+    TimingScore: number;
+    PitchScore: number;
+    getOverallQualityFeedbackScore(): number;
+}

+ 63 - 0
src/MusicalScore/Label.ts

@@ -0,0 +1,63 @@
+export class Label {
+    constructor() {
+
+    }
+    constructor(text: string) {
+        this.text = text;
+    }
+    constructor(text: string, alignment: PSTextAlignment) {
+        this.text = text;
+        this.textAlignment = alignment;
+    }
+    constructor(symbol: FontInfo.MusicFontSymbol, alignment: PSTextAlignment) {
+        this.font = PSFonts.PhonicScore;
+        var symbolInfo: FontInfo.SymbolInfo = FontInfo.Info.getSymbolInfo(symbol);
+        this.text = symbolInfo.symbol;
+        this.textAlignment = alignment;
+    }
+    private text: string;
+    private color: PSColor = PSColor.Black;
+    private font: PSFonts = PSFonts.TimesNewRoman;
+    private fontStyle: PSFontStyles = PSFontStyles.Regular;
+    private textAlignment: PSTextAlignment = PSTextAlignment.LeftBottom;
+    private fontHeight: number = 2;
+    public get Text(): string {
+        return this.text;
+    }
+    public set Text(value: string) {
+        this.text = value;
+    }
+    public get Color(): PSColor {
+        return this.color;
+    }
+    public set Color(value: PSColor) {
+        this.color = value;
+    }
+    public get Font(): PSFonts {
+        return this.font;
+    }
+    public set Font(value: PSFonts) {
+        this.font = value;
+    }
+    public get FontStyle(): PSFontStyles {
+        return this.fontStyle;
+    }
+    public set FontStyle(value: PSFontStyles) {
+        this.fontStyle = value;
+    }
+    public get FontHeight(): number {
+        return this.fontHeight;
+    }
+    public set FontHeight(value: number) {
+        this.fontHeight = value;
+    }
+    public get TextAlignment(): PSTextAlignment {
+        return this.textAlignment;
+    }
+    public set TextAlignment(value: PSTextAlignment) {
+        this.textAlignment = value;
+    }
+    public ToString(): string {
+        return this.Text;
+    }
+}

+ 105 - 0
src/MusicalScore/MusicParts/MusicPartManager.ts

@@ -0,0 +1,105 @@
+export class MusicPartManager implements ISelectionListener {
+    constructor() {
+
+    }
+    constructor(musicSheet: MusicSheet) {
+        this.musicSheet = musicSheet;
+    }
+    private parts: List<PartListEntry>;
+    private timestamps: List<TimestampTransform>;
+    private musicSheet: MusicSheet;
+    private sheetStart: Fraction;
+    private sheetEnd: Fraction;
+    public reInit(): void {
+        this.init();
+    }
+    public init(): void {
+        this.parts = new List<PartListEntry>(this.musicSheet.Repetitions.ToArray());
+        this.sheetStart = this.musicSheet.SelectionStart = new Fraction(0, 1);
+        this.sheetEnd = this.musicSheet.SelectionEnd = this.musicSheet.SheetEndTimestamp;
+        this.calcMapping();
+    }
+    private calcMapping(): void {
+        this.timestamps = new List<TimestampTransform>();
+        var iterator: MusicPartManagerIterator = this.getIterator();
+        var currentRepetition: Repetition = iterator.CurrentRepetition;
+        var curTimestampTransform: TimestampTransform = new TimestampTransform(new Fraction(iterator.CurrentEnrolledTimestamp),
+            new Fraction(iterator.CurrentSourceTimestamp), null, 0);
+        this.timestamps.Add(curTimestampTransform);
+        while (!iterator.EndReached) {
+            if (iterator.JumpOccurred || currentRepetition != iterator.CurrentRepetition) {
+                currentRepetition = iterator.CurrentRepetition;
+                if (iterator.BackJumpOccurred) {
+                    var jumpRep: Repetition = iterator.JumpResponsibleRepetition;
+                    curTimestampTransform.nextBackJump = iterator.CurrentEnrolledTimestamp;
+                    curTimestampTransform.curRepetition = jumpRep;
+                    curTimestampTransform.curRepetitionIteration = iterator.CurrentJumpResponsibleRepetitionIterationBeforeJump;
+                    for (var i: number = this.timestamps.Count - 2; i >= 0; i--) {
+                        if (jumpRep.AbsoluteTimestamp > this.timestamps[i].to || this.timestamps[i].curRepetition != null)
+                            break;
+                        this.timestamps[i].nextBackJump = curTimestampTransform.nextBackJump;
+                        this.timestamps[i].curRepetition = jumpRep;
+                        this.timestamps[i].curRepetitionIteration = curTimestampTransform.curRepetitionIteration;
+                    }
+                }
+                curTimestampTransform = new TimestampTransform(new Fraction(iterator.CurrentEnrolledTimestamp),
+                    new Fraction(iterator.CurrentSourceTimestamp), null, 0);
+                this.timestamps.Add(curTimestampTransform);
+            }
+            iterator.moveToNext();
+        }
+    }
+    public getCurrentRepetitionTimestampTransform(curEnrolledTimestamp: Fraction): TimestampTransform {
+        var curTransform: TimestampTransform = null;
+        for (var i: number = this.timestamps.Count - 1; i >= 0; i--) {
+            curTransform = this.timestamps[i];
+            if (curEnrolledTimestamp >= curTransform.$from)
+                return curTransform;
+        }
+        return this.timestamps[0];
+    }
+    public absoluteEnrolledToSheetTimestamp(timestamp: Fraction): Fraction {
+        if (this.timestamps.Count == 0)
+            return timestamp;
+        var transform: TimestampTransform = this.getCurrentRepetitionTimestampTransform(timestamp);
+        return timestamp + (transform.to - transform.$from);
+    }
+    public get Parts(): List<PartListEntry> {
+        return this.parts;
+    }
+    public get MusicSheet(): MusicSheet {
+        return this.musicSheet;
+    }
+    public getIterator(): MusicPartManagerIterator {
+        return new MusicPartManagerIterator(this, this.musicSheet.SelectionStart, this.musicSheet.SelectionEnd);
+    }
+    public getIterator(start: Fraction): MusicPartManagerIterator {
+        return new MusicPartManagerIterator(this, start, null);
+    }
+    public setSelectionStart(beginning: Fraction): void {
+        this.musicSheet.SelectionStart = beginning;
+        this.musicSheet.SelectionEnd = null;
+    }
+    public setSelectionRange(start: Fraction, end: Fraction): void {
+        this.musicSheet.SelectionStart = start == null ? this.sheetStart : start;
+        this.musicSheet.SelectionEnd = end == null ? this.sheetEnd : end;
+    }
+}
+export module MusicPartManager {
+    export class TimestampTransform {
+        constructor(sourceTimestamp: Fraction, enrolledTimestamp: Fraction, repetition: Repetition, curRepetitionIteration: number) {
+            this.$from = sourceTimestamp;
+            this.to = enrolledTimestamp;
+            this.curRepetition = repetition;
+            this.curRepetitionIteration = curRepetitionIteration;
+            this.nextBackJump = null;
+            this.nextForwardJump = null;
+        }
+        public $from: Fraction;
+        public to: Fraction;
+        public nextBackJump: Fraction;
+        public nextForwardJump: Fraction;
+        public curRepetition: Repetition;
+        public curRepetitionIteration: number;
+    }
+}

+ 477 - 0
src/MusicalScore/MusicParts/MusicPartManagerIterator.ts

@@ -0,0 +1,477 @@
+export class MusicPartManagerIterator {
+    constructor(manager: MusicPartManager) {
+        this(manager, null);
+
+    }
+    constructor(manager: MusicPartManager, startTimestamp: Fraction) {
+        this(manager, startTimestamp, null);
+
+    }
+    constructor(manager: MusicPartManager, startTimestamp: Fraction, endTimestamp: Fraction) {
+        try {
+            this.frontReached = true;
+            this.manager = manager;
+            this.currentVoiceEntries = null;
+            this.frontReached = false;
+            for (var idx: number = 0, len = manager.MusicSheet.Repetitions.Count; idx < len; ++idx) {
+                var rep: Repetition = manager.MusicSheet.Repetitions[idx];
+                this.repetitionIterationCountDict.Add(rep, 1);
+            }
+            for (var i: number = 0; i < manager.MusicSheet.getCompleteNumberOfStaves(); i++) {
+                this.activeDynamicExpressions.Add(null);
+            }
+            this.currentMeasure = this.manager.MusicSheet.SourceMeasures[0];
+            if (startTimestamp == null)
+                return
+            do {
+                this.moveToNext();
+            }
+            while ((this.currentVoiceEntries == null || this.currentTimeStamp < startTimestamp) && !this.endReached);
+            for (var staffIndex: number = 0; staffIndex < this.activeDynamicExpressions.Count; staffIndex++) {
+                if (this.activeDynamicExpressions[staffIndex] != null) {
+                    if (this.activeDynamicExpressions[staffIndex] instanceof ContinuousDynamicExpression) {
+                        var continuousDynamic: ContinuousDynamicExpression = <ContinuousDynamicExpression>this.activeDynamicExpressions[staffIndex];
+                        this.currentDynamicChangingExpressions.Add(new DynamicsContainer(continuousDynamic, staffIndex));
+                    }
+                    else {
+                        var instantaniousDynamic: InstantaniousDynamicExpression = <InstantaniousDynamicExpression>this.activeDynamicExpressions[staffIndex];
+                        this.currentDynamicChangingExpressions.Add(new DynamicsContainer(instantaniousDynamic, staffIndex));
+                    }
+                }
+            }
+            this.currentTempoChangingExpression = this.activeTempoExpression;
+        }
+        catch (err) {
+
+        }
+
+    }
+    public BackJumpOccurred: boolean;
+    public ForwardJumpOccurred: boolean;
+    private manager: MusicPartManager;
+    private currentMappingPart: MappingSourceMusicPart;
+    private currentMeasure: SourceMeasure;
+    private currentMeasureIndex: number = 0;
+    private currentPartIndex: number = 0;
+    private currentVoiceEntryIndex: number = -1;
+    private currentDynamicEntryIndex: number = 0;
+    private currentTempoEntryIndex: number = 0;
+    private currentVoiceEntries: List<VoiceEntry>;
+    private currentDynamicChangingExpressions: List<DynamicsContainer> = new List<DynamicsContainer>();
+    private currentTempoChangingExpression: MultiTempoExpression;
+    private repetitionIterationCountDict: Dictionary<Repetition, number> = new Dictionary<Repetition, number>();
+    private currentRepetition: Repetition = null;
+    private endReached: boolean = false;
+    private frontReached: boolean = false;
+    private currentTimeStamp: Fraction = new Fraction(new Fraction(0, 1));
+    private currentEnrolledMeasureTimestamp: Fraction = new Fraction(new Fraction(0, 1));
+    private currentVerticalContainerInMeasureTimestamp: Fraction = new Fraction(new Fraction(0, 1));
+    private jumpResponsibleRepetition: Repetition = null;
+    private activeDynamicExpressions: List<AbstractExpression> = new List<AbstractExpression>();
+    private activeTempoExpression: MultiTempoExpression;
+    public get EndReached(): boolean {
+        return this.endReached;
+    }
+    public get FrontReached(): boolean {
+        return this.frontReached;
+    }
+    public get CurrentMeasure(): SourceMeasure {
+        return this.currentMeasure;
+    }
+    public get CurrentRepetition(): Repetition {
+        return this.currentRepetition;
+    }
+    public get CurrentRepetitionIteration(): number {
+        if (this.CurrentRepetition != null)
+            return this.repetitionIterationCountDict[this.CurrentRepetition];
+        return 0;
+    }
+    public get CurrentJumpResponsibleRepetitionIterationBeforeJump(): number {
+        if (this.jumpResponsibleRepetition != null)
+            return this.repetitionIterationCountDict[this.jumpResponsibleRepetition] - 1;
+        return 0;
+    }
+    public get CurrentVoiceEntries(): List<VoiceEntry> {
+        return this.currentVoiceEntries;
+    }
+    public get CurrentMeasureIndex(): number {
+        return this.currentMeasureIndex;
+    }
+    public get CurrentEnrolledTimestamp(): Fraction {
+        return this.currentEnrolledMeasureTimestamp + this.currentVerticalContainerInMeasureTimestamp;
+    }
+    public get CurrentSourceTimestamp(): Fraction {
+        return this.currentTimeStamp;
+    }
+    public get JumpOccurred(): boolean {
+        return this.BackJumpOccurred || this.ForwardJumpOccurred;
+    }
+    public get ActiveTempoExpression(): MultiTempoExpression {
+        return this.activeTempoExpression;
+    }
+    public get ActiveDynamicExpressions(): List<AbstractExpression> {
+        return this.activeDynamicExpressions;
+    }
+    public get CurrentTempoChangingExpression(): MultiTempoExpression {
+        return this.currentTempoChangingExpression;
+    }
+    public get JumpResponsibleRepetition(): Repetition {
+        return this.jumpResponsibleRepetition;
+    }
+    public clone(): MusicPartManagerIterator {
+        var ret: MusicPartManagerIterator = new MusicPartManagerIterator(this.manager);
+        ret.currentVoiceEntryIndex = this.currentVoiceEntryIndex;
+        ret.currentMappingPart = this.currentMappingPart;
+        ret.currentPartIndex = this.currentPartIndex;
+        ret.currentVoiceEntries = this.currentVoiceEntries;
+        ret.endReached = this.endReached;
+        ret.frontReached = this.frontReached;
+        return ret;
+    }
+    public CurrentVisibleVoiceEntries(instrument: Instrument): List<VoiceEntry> {
+        var ret: List<VoiceEntry> = new List<VoiceEntry>();
+        if (this.currentVoiceEntries == null)
+            return ret;
+        for (var idx: number = 0, len = this.currentVoiceEntries.Count; idx < len; ++idx) {
+            var entry: VoiceEntry = this.currentVoiceEntries[idx];
+            if (entry.ParentVoice.Parent.IdString == instrument.IdString) {
+                this.getVisibleEntries(entry, ret);
+                return ret;
+            }
+        }
+        return ret;
+    }
+    public CurrentVisibleVoiceEntries(): List<VoiceEntry> {
+        var voiceEntries: List<VoiceEntry> = new List<VoiceEntry>();
+        if (this.currentVoiceEntries != null) {
+            for (var idx: number = 0, len = this.currentVoiceEntries.Count; idx < len; ++idx) {
+                var entry: VoiceEntry = this.currentVoiceEntries[idx];
+                this.getVisibleEntries(entry, voiceEntries);
+            }
+        }
+        return voiceEntries;
+    }
+    public CurrentAudibleVoiceEntries(instrument: Instrument): List<VoiceEntry> {
+        var ret: List<VoiceEntry> = new List<VoiceEntry>();
+        if (this.currentVoiceEntries == null)
+            return ret;
+        for (var idx: number = 0, len = this.currentVoiceEntries.Count; idx < len; ++idx) {
+            var entry: VoiceEntry = this.currentVoiceEntries[idx];
+            if (entry.ParentVoice.Parent.IdString == instrument.IdString) {
+                this.getAudibleEntries(entry, ret);
+                return ret;
+            }
+        }
+        return ret;
+    }
+    public CurrentAudibleVoiceEntries(): List<VoiceEntry> {
+        var voiceEntries: List<VoiceEntry> = new List<VoiceEntry>();
+        if (this.currentVoiceEntries != null) {
+            for (var idx: number = 0, len = this.currentVoiceEntries.Count; idx < len; ++idx) {
+                var entry: VoiceEntry = this.currentVoiceEntries[idx];
+                this.getAudibleEntries(entry, voiceEntries);
+            }
+        }
+        return voiceEntries;
+    }
+    public getCurrentDynamicChangingExpressions(): List<DynamicsContainer> {
+        return this.currentDynamicChangingExpressions;
+    }
+    public CurrentScoreFollowingVoiceEntries(instrument: Instrument): List<VoiceEntry> {
+        var ret: List<VoiceEntry> = new List<VoiceEntry>();
+        if (this.currentVoiceEntries == null)
+            return ret;
+        for (var idx: number = 0, len = this.currentVoiceEntries.Count; idx < len; ++idx) {
+            var entry: VoiceEntry = this.currentVoiceEntries[idx];
+            if (entry.ParentVoice.Parent.IdString == instrument.IdString) {
+                this.getScoreFollowingEntries(entry, ret);
+                return ret;
+            }
+        }
+        return ret;
+    }
+    public CurrentScoreFollowingVoiceEntries(): List<VoiceEntry> {
+        var voiceEntries: List<VoiceEntry> = new List<VoiceEntry>();
+        if (this.currentVoiceEntries != null) {
+            for (var idx: number = 0, len = this.currentVoiceEntries.Count; idx < len; ++idx) {
+                var entry: VoiceEntry = this.currentVoiceEntries[idx];
+                this.getScoreFollowingEntries(entry, voiceEntries);
+            }
+        }
+        return voiceEntries;
+    }
+    public currentPlaybackSettings(): PlaybackSettings {
+        return this.manager.MusicSheet.SheetPlaybackSetting;
+    }
+    public moveToNext(): void {
+        this.ForwardJumpOccurred = this.BackJumpOccurred = false;
+        if (this.endReached)
+            return
+        if (this.currentVoiceEntries != null)
+            this.currentVoiceEntries.Clear();
+        this.recursiveMove();
+        if (this.currentMeasure == null) {
+            this.currentTimeStamp = new Fraction(99999, 1);
+        }
+    }
+    public moveToNextVisibleVoiceEntry(notesOnly: boolean): void {
+        while (!this.endReached) {
+            this.moveToNext();
+            if (this.checkEntries(notesOnly))
+                return
+        }
+    }
+    private resetRepetitionIterationCount(repetition: Repetition): number {
+        this.setRepetitionIterationCount(repetition, 1);
+        return 1;
+    }
+    private incrementRepetitionIterationCount(repetition: Repetition): number {
+        if (this.repetitionIterationCountDict.ContainsKey(repetition)) {
+            var newIteration: number = this.repetitionIterationCountDict[repetition] + 1;
+            this.repetitionIterationCountDict[repetition] = newIteration;
+            return newIteration;
+        }
+        else {
+            this.repetitionIterationCountDict.Add(repetition, 1);
+            return 1;
+        }
+    }
+    private setRepetitionIterationCount(repetition: Repetition, iterationCount: number): void {
+        if (this.repetitionIterationCountDict.ContainsKey(repetition))
+            this.repetitionIterationCountDict[repetition] = iterationCount;
+        else {
+            this.repetitionIterationCountDict.Add(repetition, iterationCount);
+        }
+    }
+    private moveTempoIndexToTimestamp(measureNumber: number): void {
+        for (var index: number = 0; index < this.manager.MusicSheet.TimestampSortedTempoExpressionsList.Count; index++) {
+            if (this.manager.MusicSheet.TimestampSortedTempoExpressionsList[index].SourceMeasureParent.MeasureNumber >= measureNumber) {
+                this.currentTempoEntryIndex = Math.Max(-1, index - 1);
+                return
+            }
+        }
+    }
+    private getNextTempoEntryTimestamp(): Fraction {
+        if (this.currentTempoEntryIndex >= this.manager.MusicSheet.TimestampSortedTempoExpressionsList.Count - 1) {
+            return new Fraction(99999, 1);
+        }
+        return this.manager.MusicSheet.TimestampSortedTempoExpressionsList[this.currentTempoEntryIndex + 1].SourceMeasureParent.AbsoluteTimestamp + this.manager.MusicSheet.TimestampSortedTempoExpressionsList[this.currentTempoEntryIndex + 1].Timestamp;
+    }
+    private moveToNextDynamic(): void {
+        this.currentDynamicEntryIndex++;
+        this.currentDynamicChangingExpressions.Clear();
+        var curDynamicEntry: DynamicsContainer = this.manager.MusicSheet.TimestampSortedDynamicExpressionsList[this.currentDynamicEntryIndex];
+        this.currentDynamicChangingExpressions.Add(curDynamicEntry);
+        var tsNow: Fraction = curDynamicEntry.parMultiExpression().AbsoluteTimestamp;
+        for (var i: number = this.currentDynamicEntryIndex + 1; i < this.manager.MusicSheet.TimestampSortedDynamicExpressionsList.Count; i++) {
+            curDynamicEntry = this.manager.MusicSheet.TimestampSortedDynamicExpressionsList[i];
+            if ((curDynamicEntry.parMultiExpression().AbsoluteTimestamp != tsNow))
+                break;
+            this.currentDynamicEntryIndex = i;
+            this.currentDynamicChangingExpressions.Add(curDynamicEntry);
+        }
+    }
+    private moveDynamicIndexToTimestamp(absoluteTimestamp: Fraction): void {
+        var dynamics: List<DynamicsContainer> = this.manager.MusicSheet.TimestampSortedDynamicExpressionsList;
+        for (var index: number = 0; index < dynamics.Count; index++) {
+            if (dynamics[index].parMultiExpression().AbsoluteTimestamp >= absoluteTimestamp) {
+                this.currentDynamicEntryIndex = Math.Max(0, index - 1);
+                return
+            }
+        }
+    }
+    private getNextDynamicsEntryTimestamp(): Fraction {
+        if (this.currentDynamicEntryIndex >= this.manager.MusicSheet.TimestampSortedDynamicExpressionsList.Count - 1) {
+            return new Fraction(99999, 1);
+        }
+        return this.manager.MusicSheet.TimestampSortedDynamicExpressionsList[this.currentDynamicEntryIndex + 1].parMultiExpression().AbsoluteTimestamp;
+    }
+    private handleRepetitionsAtMeasureBegin(): void {
+        for (var idx: number = 0, len = this.currentMeasure.FirstRepetitionInstructions.Count; idx < len; ++idx) {
+            var repetitionInstruction: RepetitionInstruction = this.currentMeasure.FirstRepetitionInstructions[idx];
+            if (repetitionInstruction.ParentRepetition == null)
+                continue;
+            var currentRepetition: Repetition = repetitionInstruction.ParentRepetition;
+            this.currentRepetition = currentRepetition;
+            if (currentRepetition.StartIndex == this.currentMeasureIndex) {
+                if (this.JumpResponsibleRepetition != null && currentRepetition != this.JumpResponsibleRepetition && currentRepetition.StartIndex >= this.JumpResponsibleRepetition.StartIndex && currentRepetition.EndIndex <= this.JumpResponsibleRepetition.EndIndex)
+                    this.resetRepetitionIterationCount(currentRepetition);
+            }
+        }
+    }
+    private handleRepetitionsAtMeasureEnd(): void {
+        for (var idx: number = 0, len = this.currentMeasure.LastRepetitionInstructions.Count; idx < len; ++idx) {
+            var repetitionInstruction: RepetitionInstruction = this.currentMeasure.LastRepetitionInstructions[idx];
+            var currentRepetition: Repetition = repetitionInstruction.ParentRepetition;
+            if (currentRepetition == null)
+                continue;
+            if (currentRepetition.BackwardJumpInstructions.Contains(repetitionInstruction)) {
+                if (this.repetitionIterationCountDict[currentRepetition] < currentRepetition.UserNumberOfRepetitions) {
+                    this.doBackJump(currentRepetition);
+                    this.BackJumpOccurred = true;
+                    return
+                }
+            }
+            if (repetitionInstruction == currentRepetition.ForwardJumpInstruction) {
+                if (this.JumpResponsibleRepetition != null && currentRepetition != this.JumpResponsibleRepetition && currentRepetition.StartIndex >= this.JumpResponsibleRepetition.StartIndex && currentRepetition.EndIndex <= this.JumpResponsibleRepetition.EndIndex)
+                    this.resetRepetitionIterationCount(currentRepetition);
+                var forwardJumpTargetMeasureIndex: number = currentRepetition.getForwardJumpTargetForIteration(this.repetitionIterationCountDict[currentRepetition]);
+                if (forwardJumpTargetMeasureIndex >= 0) {
+                    this.currentMeasureIndex = forwardJumpTargetMeasureIndex;
+                    this.currentMeasure = this.manager.MusicSheet.SourceMeasures[this.currentMeasureIndex];
+                    this.currentVoiceEntryIndex = -1;
+                    this.jumpResponsibleRepetition = currentRepetition;
+                    this.ForwardJumpOccurred = true;
+                    return
+                }
+                if (forwardJumpTargetMeasureIndex == -2)
+                    this.endReached = true;
+            }
+        }
+        this.currentMeasureIndex++;
+        if (this.JumpResponsibleRepetition != null && this.currentMeasureIndex > this.JumpResponsibleRepetition.EndIndex)
+            this.jumpResponsibleRepetition = null;
+    }
+    private doBackJump(currentRepetition: Repetition): void {
+        this.currentMeasureIndex = currentRepetition.getBackwardJumpTarget();
+        this.currentMeasure = this.manager.MusicSheet.SourceMeasures[this.currentMeasureIndex];
+        this.currentVoiceEntryIndex = -1;
+        this.incrementRepetitionIterationCount(currentRepetition);
+        this.jumpResponsibleRepetition = currentRepetition;
+    }
+    private activateCurrentRhythmInstructions(): void {
+        if (this.currentMeasure != null && this.currentMeasure.FirstInstructionsStaffEntries.Count > 0 && this.currentMeasure.FirstInstructionsStaffEntries[0] != null) {
+            var instructions: List<AbstractNotationInstruction> = this.currentMeasure.FirstInstructionsStaffEntries[0].Instructions;
+            for (var idx: number = 0, len = instructions.Count; idx < len; ++idx) {
+                var abstractNotationInstruction: AbstractNotationInstruction = instructions[idx];
+                if (abstractNotationInstruction instanceof RhythmInstruction) {
+                    this.manager.MusicSheet.SheetPlaybackSetting.Rhythm = (<RhythmInstruction>abstractNotationInstruction).Rhythm;
+                }
+            }
+        }
+    }
+    private activateCurrentDynamicOrTempoInstructions(): void {
+        var timeSortedDynamics: List<DynamicsContainer> = this.manager.MusicSheet.TimestampSortedDynamicExpressionsList;
+        while (this.currentDynamicEntryIndex > 0 && (this.currentDynamicEntryIndex >= timeSortedDynamics.Count || timeSortedDynamics[this.currentDynamicEntryIndex].parMultiExpression().AbsoluteTimestamp >= this.CurrentSourceTimestamp))
+            this.currentDynamicEntryIndex--;
+        while (this.currentDynamicEntryIndex < timeSortedDynamics.Count && timeSortedDynamics[this.currentDynamicEntryIndex].parMultiExpression().AbsoluteTimestamp < this.CurrentSourceTimestamp)
+            this.currentDynamicEntryIndex++;
+        while (this.currentDynamicEntryIndex < timeSortedDynamics.Count && timeSortedDynamics[this.currentDynamicEntryIndex].parMultiExpression().AbsoluteTimestamp == this.CurrentSourceTimestamp) {
+            var dynamicsContainer: DynamicsContainer = timeSortedDynamics[this.currentDynamicEntryIndex];
+            var staffIndex: number = dynamicsContainer.StaffNumber;
+            if (this.CurrentSourceTimestamp == dynamicsContainer.parMultiExpression().AbsoluteTimestamp) {
+                if (dynamicsContainer.ContinuousDynamicExpression != null) {
+                    this.activeDynamicExpressions[staffIndex] = dynamicsContainer.ContinuousDynamicExpression;
+                }
+                else if (dynamicsContainer.InstantaniousDynamicExpression != null) {
+                    this.activeDynamicExpressions[staffIndex] = dynamicsContainer.InstantaniousDynamicExpression;
+                }
+            }
+            this.currentDynamicEntryIndex++;
+        }
+        this.currentDynamicChangingExpressions.Clear();
+        for (var staffIndex: number = 0; staffIndex < this.activeDynamicExpressions.Count; staffIndex++) {
+            if (this.activeDynamicExpressions[staffIndex] != null) {
+                var startTime: Fraction;
+                var endTime: Fraction;
+                if (this.activeDynamicExpressions[staffIndex] instanceof ContinuousDynamicExpression) {
+                    var continuousDynamic: ContinuousDynamicExpression = <ContinuousDynamicExpression>this.activeDynamicExpressions[staffIndex];
+                    startTime = continuousDynamic.StartMultiExpression.AbsoluteTimestamp;
+                    endTime = continuousDynamic.EndMultiExpression.AbsoluteTimestamp;
+                    if (this.CurrentSourceTimestamp >= startTime && this.CurrentSourceTimestamp <= endTime)
+                        this.currentDynamicChangingExpressions.Add(new DynamicsContainer(continuousDynamic, staffIndex));
+                }
+                else {
+                    var instantaniousDynamic: InstantaniousDynamicExpression = <InstantaniousDynamicExpression>this.activeDynamicExpressions[staffIndex];
+                    if (this.CurrentSourceTimestamp == instantaniousDynamic.ParentMultiExpression.AbsoluteTimestamp)
+                        this.currentDynamicChangingExpressions.Add(new DynamicsContainer(instantaniousDynamic, staffIndex));
+                }
+            }
+        }
+        var timeSortedTempoExpressions: List<MultiTempoExpression> = this.manager.MusicSheet.TimestampSortedTempoExpressionsList;
+        while (this.currentTempoEntryIndex > 0 && (this.currentTempoEntryIndex >= timeSortedTempoExpressions.Count || timeSortedTempoExpressions[this.currentTempoEntryIndex].AbsoluteTimestamp >= this.CurrentSourceTimestamp))
+            this.currentTempoEntryIndex--;
+        while (this.currentTempoEntryIndex < timeSortedTempoExpressions.Count && timeSortedTempoExpressions[this.currentTempoEntryIndex].AbsoluteTimestamp < this.CurrentSourceTimestamp)
+            this.currentTempoEntryIndex++;
+        while (this.currentTempoEntryIndex < timeSortedTempoExpressions.Count && timeSortedTempoExpressions[this.currentTempoEntryIndex].AbsoluteTimestamp == this.CurrentSourceTimestamp) {
+            this.activeTempoExpression = timeSortedTempoExpressions[this.currentTempoEntryIndex];
+            this.currentTempoEntryIndex++;
+        }
+        this.currentTempoChangingExpression = null;
+        if (this.activeTempoExpression != null) {
+            var endTime: Fraction = this.activeTempoExpression.AbsoluteTimestamp;
+            if (this.activeTempoExpression.ContinuousTempo != null)
+                endTime = this.activeTempoExpression.ContinuousTempo.AbsoluteEndTimestamp;
+            if (this.CurrentSourceTimestamp >= this.activeTempoExpression.AbsoluteTimestamp || this.CurrentSourceTimestamp <= endTime)
+                this.currentTempoChangingExpression = this.activeTempoExpression;
+        }
+    }
+    private recursiveMove(): void {
+        this.currentVoiceEntryIndex++;
+        if (this.currentVoiceEntryIndex == 0) {
+            this.handleRepetitionsAtMeasureBegin();
+            this.activateCurrentRhythmInstructions();
+        }
+        if (this.currentVoiceEntryIndex >= 0 && this.currentVoiceEntryIndex < this.currentMeasure.VerticalSourceStaffEntryContainers.Count) {
+            var currentContainer: VerticalSourceStaffEntryContainer = this.currentMeasure.VerticalSourceStaffEntryContainers[this.currentVoiceEntryIndex];
+            this.currentVoiceEntries = this.getVoiceEntries(currentContainer);
+            this.currentVerticalContainerInMeasureTimestamp = currentContainer.Timestamp;
+            this.currentTimeStamp = new Fraction(this.currentMeasure.AbsoluteTimestamp + this.currentVerticalContainerInMeasureTimestamp);
+            if (this.currentTimeStamp >= this.manager.MusicSheet.SelectionEnd)
+                this.endReached = true;
+            this.activateCurrentDynamicOrTempoInstructions();
+            return
+        }
+        this.currentEnrolledMeasureTimestamp.Add(this.currentMeasure.Duration);
+        this.handleRepetitionsAtMeasureEnd();
+        if (this.currentMeasureIndex >= 0 && this.currentMeasureIndex < this.manager.MusicSheet.SourceMeasures.Count) {
+            this.currentMeasure = this.manager.MusicSheet.SourceMeasures[this.currentMeasureIndex];
+            this.currentTimeStamp = new Fraction(this.currentMeasure.AbsoluteTimestamp + this.currentVerticalContainerInMeasureTimestamp);
+            this.currentVoiceEntryIndex = -1;
+            this.recursiveMove();
+            return
+        }
+        this.currentVerticalContainerInMeasureTimestamp = new Fraction();
+        this.currentMeasure = null;
+        this.currentVoiceEntries = null;
+        this.endReached = true;
+    }
+    private checkEntries(notesOnly: boolean): boolean {
+        var tlist: List<VoiceEntry> = this.CurrentVisibleVoiceEntries();
+        if (tlist.Count > 0) {
+            if (!notesOnly)
+                return true;
+            for (var idx: number = 0, len = tlist.Count; idx < len; ++idx) {
+                var entry: VoiceEntry = tlist[idx];
+                if (entry.Notes[0].Pitch != null)
+                    return true;
+            }
+        }
+        return false;
+    }
+    private getVisibleEntries(entry: VoiceEntry, visibleEntries: List<VoiceEntry>): void {
+        if (entry.ParentVoice.Visible)
+            visibleEntries.Add(entry);
+    }
+    private getAudibleEntries(entry: VoiceEntry, audibleEntries: List<VoiceEntry>): void {
+        if (entry.ParentVoice.Audible)
+            audibleEntries.Add(entry);
+    }
+    private getScoreFollowingEntries(entry: VoiceEntry, followingEntries: List<VoiceEntry>): void {
+        if (entry.ParentVoice.Following && entry.ParentVoice.Parent.Following)
+            followingEntries.Add(entry);
+    }
+    private getVoiceEntries(container: VerticalSourceStaffEntryContainer): List<VoiceEntry> {
+        var entries: List<VoiceEntry> = new List<VoiceEntry>();
+        for (var idx: number = 0, len = container.StaffEntries.Count; idx < len; ++idx) {
+            var sourceStaffEntry: SourceStaffEntry = container.StaffEntries[idx];
+            if (sourceStaffEntry == null)
+                continue;
+            for (var idx2: number = 0, len2 = sourceStaffEntry.VoiceEntries.Count; idx2 < len2; ++idx2) {
+                var voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[idx2];
+                entries.Add(voiceEntry);
+            }
+        }
+        return entries;
+    }
+}

+ 465 - 0
src/MusicalScore/MusicSheet.ts

@@ -0,0 +1,465 @@
+export class MusicSheet implements ISettableMusicSheet, IComparable<MusicSheet>
+{
+    constructor() {
+        try {
+            this.Rules = EngravingRules.Rules;
+        }
+        catch (ex) {
+
+        }
+
+        this.playbackSettings = this.SheetPlaybackSetting = new PlaybackSettings(new Fraction(4, 4, false), 100);
+        this.UserStartTempoInBPM = 100;
+        this.PageWidth = 120;
+        this.MusicPartManager = new MusicPartManager(this);
+    }
+    private idString: string = "kjgdfuilhsdaöoihfsvjh";
+    private sourceMeasures: List<SourceMeasure> = new List<SourceMeasure>();
+    private repetitions: List<Repetition> = new List<Repetition>();
+    private dynListStaves: List<List<DynamicsContainer>> = new List<List<DynamicsContainer>>();
+    private timestampSortedDynamicExpressionsList: List<DynamicsContainer> = new List<DynamicsContainer>();
+    private timestampSortedTempoExpressionsList: List<MultiTempoExpression> = new List<MultiTempoExpression>();
+    private instrumentalGroups: List<InstrumentalGroup> = new List<InstrumentalGroup>();
+    private instruments: List<Instrument> = new List<Instrument>();
+    private playbackSettings: PlaybackSettings;
+    private path: string;
+    private title: Label;
+    private subtitle: Label;
+    private composer: Label;
+    private lyricist: Label;
+    private languages: List<Language> = new List<Language>();
+    private activeLanguage: Language;
+    private musicPartManager: MusicPartManager = null;
+    private musicSheetErrors: MusicSheetErrors = new MusicSheetErrors();
+    private staves: List<Staff> = new List<Staff>();
+    private selectionStart: Fraction;
+    private selectionEnd: Fraction;
+    private transpose: number = 0;
+    private defaultStartTempoInBpm: number = 0;
+    private drawErroneousMeasures: boolean = false;
+    private hasBeenOpenedForTheFirstTime: boolean = false;
+    private currentEnrolledPosition: Fraction = new Fraction(0, 1);
+    private musicSheetParameterObject: MusicSheetParameterObject = null;
+    private engravingRules: EngravingRules;
+    private phonicScoreInterface: IPhonicScoreInterface;
+    private musicSheetParameterChangedDelegate: MusicSheetParameterChangedDelegate;
+    public static defaultTitle: string = "[kein Titel]";
+    public get PhonicScoreInterface(): IPhonicScoreInterface {
+        return this.phonicScoreInterface;
+    }
+    public set PhonicScoreInterface(value: IPhonicScoreInterface) {
+        this.phonicScoreInterface = value;
+    }
+    public get SourceMeasures(): List<SourceMeasure> {
+        return this.sourceMeasures;
+    }
+    public set SourceMeasures(value: List<SourceMeasure>) {
+        this.sourceMeasures = value;
+    }
+    public get Repetitions(): List<Repetition> {
+        return this.repetitions;
+    }
+    public set Repetitions(value: List<Repetition>) {
+        this.repetitions = value;
+    }
+    public get DynListStaves(): List<List<DynamicsContainer>> {
+        return this.dynListStaves;
+    }
+    public get TimestampSortedTempoExpressionsList(): List<MultiTempoExpression> {
+        return this.timestampSortedTempoExpressionsList;
+    }
+    public get TimestampSortedDynamicExpressionsList(): List<DynamicsContainer> {
+        return this.timestampSortedDynamicExpressionsList;
+    }
+    public get InstrumentalGroups(): List<InstrumentalGroup> {
+        return this.instrumentalGroups;
+    }
+    public get Instruments(): List<Instrument> {
+        return this.instruments;
+    }
+    public get SheetPlaybackSetting(): PlaybackSettings {
+        return this.playbackSettings;
+    }
+    public set SheetPlaybackSetting(value: PlaybackSettings) {
+        this.playbackSettings = value;
+    }
+    public get DrawErroneousMeasures(): boolean {
+        return this.drawErroneousMeasures;
+    }
+    public set DrawErroneousMeasures(value: boolean) {
+        this.drawErroneousMeasures = value;
+    }
+    public get HasBeenOpenedForTheFirstTime(): boolean {
+        return this.hasBeenOpenedForTheFirstTime;
+    }
+    public set HasBeenOpenedForTheFirstTime(value: boolean) {
+        this.hasBeenOpenedForTheFirstTime = value;
+    }
+    public InitializeStartTempoInBPM(startTempo: number): void {
+        this.playbackSettings.BeatsPerMinute = startTempo;
+        this.UserStartTempoInBPM = startTempo;
+    }
+    public UserStartTempoInBPM: number;
+    public get DefaultStartTempoInBpm(): number {
+        return this.defaultStartTempoInBpm;
+    }
+    public set DefaultStartTempoInBpm(value: number) {
+        this.defaultStartTempoInBpm = value;
+        this.InitializeStartTempoInBPM(value);
+    }
+    public PageWidth: number;
+    public get Path(): string {
+        return this.path;
+    }
+    public set Path(value: string) {
+        this.path = value;
+    }
+    public get Staves(): List<Staff> {
+        return this.staves;
+    }
+    public get TitleString(): string {
+        if (this.title != null)
+            return this.title.Text;
+        else return string.Empty;
+    }
+    public get SubtitleString(): string {
+        if (this.subtitle != null)
+            return this.subtitle.Text;
+        else return string.Empty;
+    }
+    public get ComposerString(): string {
+        if (this.composer != null)
+            return this.composer.Text;
+        else return string.Empty;
+    }
+    public get LyricistString(): string {
+        if (this.lyricist != null)
+            return this.lyricist.Text;
+        else return string.Empty;
+    }
+    public get Title(): Label {
+        return this.title;
+    }
+    public set Title(value: Label) {
+        this.title = value;
+    }
+    public get Subtitle(): Label {
+        return this.subtitle;
+    }
+    public set Subtitle(value: Label) {
+        this.subtitle = value;
+    }
+    public get Composer(): Label {
+        return this.composer;
+    }
+    public set Composer(value: Label) {
+        this.composer = value;
+    }
+    public get Lyricist(): Label {
+        return this.lyricist;
+    }
+    public set Lyricist(value: Label) {
+        this.lyricist = value;
+    }
+    public get Rules(): EngravingRules {
+        return this.engravingRules;
+    }
+    public set Rules(value: EngravingRules) {
+        this.engravingRules = value;
+    }
+    public get SheetErrors(): MusicSheetErrors {
+        return this.musicSheetErrors;
+    }
+    public get SelectionStart(): Fraction {
+        return this.selectionStart;
+    }
+    public set SelectionStart(value: Fraction) {
+        this.selectionStart = value;
+        this.currentEnrolledPosition = new Fraction(this.selectionStart);
+    }
+    public get SelectionEnd(): Fraction {
+        return this.selectionEnd;
+    }
+    public set SelectionEnd(value: Fraction) {
+        this.selectionEnd = value;
+    }
+    public get MusicSheetParameterObject(): MusicSheetParameterObject {
+        return this.musicSheetParameterObject;
+    }
+    public set MusicSheetParameterObject(value: MusicSheetParameterObject) {
+        this.musicSheetParameterObject = value;
+        this.Title = new Label(this.musicSheetParameterObject.Title);
+        this.Composer = new Label(this.musicSheetParameterObject.Composer);
+    }
+    public addMeasure(measure: SourceMeasure): void {
+        this.SourceMeasures.Add(measure);
+        measure.MeasureListIndex = this.SourceMeasures.Count - 1;
+    }
+    public checkForInstrumentWithNoVoice(): void {
+        for (var idx: number = 0, len = this.instruments.Count; idx < len; ++idx) {
+            var instrument: Instrument = this.instruments[idx];
+            if (instrument.Voices.Count == 0) {
+                var voice: Voice = new Voice(instrument, 1);
+                instrument.Voices.Add(voice);
+            }
+        }
+    }
+    public getStaffFromIndex(staffIndexInMusicSheet: number): Staff {
+        if (this.staves.Count > staffIndexInMusicSheet)
+            return this.staves[staffIndexInMusicSheet];
+        else return null;
+    }
+    public getIndexFromStaff(staff: Staff): number {
+        return staff.IdInMusicSheet;
+    }
+    public fillStaffList(): void {
+        var i: number = 0;
+        for (var idx: number = 0, len = this.instruments.Count; idx < len; ++idx) {
+            var instrument: Instrument = this.instruments[idx];
+            for (var idx2: number = 0, len2 = instrument.Staves.Count; idx2 < len2; ++idx2) {
+                var staff: Staff = instrument.Staves[idx2];
+                staff.IdInMusicSheet = i;
+                this.staves.Add(staff);
+                i++;
+            }
+        }
+    }
+    public get MusicPartManager(): MusicPartManager {
+        return this.musicPartManager;
+    }
+    public set MusicPartManager(value: MusicPartManager) {
+        this.musicPartManager = value;
+    }
+    public getCompleteNumberOfStaves(): number {
+        var number: number = 0;
+        for (var idx: number = 0, len = this.instruments.Count; idx < len; ++idx) {
+            var instrument: Instrument = this.instruments[idx];
+            number += instrument.Staves.Count;
+        }
+        return number;
+    }
+    public getListOfMeasuresFromIndeces(start: number, end: number): List<SourceMeasure> {
+        var measures: List<SourceMeasure> = new List<SourceMeasure>();
+        for (var i: number = start; i <= end; i++)
+            measures.Add(this.sourceMeasures[i]);
+        return measures;
+    }
+    public getNextSourceMeasure(measure: SourceMeasure): SourceMeasure {
+        var index: number = this.sourceMeasures.IndexOf(measure);
+        if (index == this.sourceMeasures.Count - 1)
+            return measure;
+        return this.sourceMeasures[index + 1];
+    }
+    public getFirstSourceMeasure(): SourceMeasure {
+        return this.sourceMeasures[0];
+    }
+    public getLastSourceMeasure(): SourceMeasure {
+        return this.sourceMeasures[this.sourceMeasures.Count - 1];
+    }
+    public resetAllNoteStates(): void {
+        var iterator: MusicPartManagerIterator = this.MusicPartManager.getIterator();
+        while (!iterator.EndReached && iterator.CurrentVoiceEntries != null) {
+            for (var idx: number = 0, len = iterator.CurrentVoiceEntries.Count; idx < len; ++idx) {
+                var voiceEntry: VoiceEntry = iterator.CurrentVoiceEntries[idx];
+                for (var idx2: number = 0, len2 = voiceEntry.Notes.Count; idx2 < len2; ++idx2) {
+                    var note: Note = voiceEntry.Notes[idx2];
+                    note.State = NoteState.Normal;
+                }
+            }
+            iterator.moveToNext();
+        }
+    }
+    public getMusicSheetInstrumentIndex(instrument: Instrument): number {
+        return this.Instruments.IndexOf(instrument);
+    }
+    public getGlobalStaffIndexOfFirstStaff(instrument: Instrument): number {
+        var instrumentIndex: number = this.getMusicSheetInstrumentIndex(instrument);
+        var staffLineIndex: number = 0;
+        for (var i: number = 0; i < instrumentIndex; i++)
+            staffLineIndex += this.Instruments[i].Staves.Count;
+        return staffLineIndex;
+    }
+    public setRepetitionNewUserNumberOfRepetitions(index: number, value: number): void {
+        var repIndex: number = 0;
+        for (var i: number = 0; i < this.repetitions.Count; i++) {
+            if (this.repetitions[i] instanceof Repetition) {
+                if (index == repIndex) {
+                    (<Repetition>this.repetitions[i]).UserNumberOfRepetitions = value;
+                    break;
+                }
+                else repIndex++;
+            }
+        }
+    }
+    public getRepetitionByIndex(index: number): Repetition {
+        var repIndex: number = 0;
+        for (var i: number = 0; i < this.repetitions.Count; i++) {
+            if (this.repetitions[i] instanceof Repetition) {
+                if (index == repIndex)
+                    return <Repetition>this.repetitions[i];
+                repIndex++;
+            }
+        }
+        return null;
+    }
+    public CompareTo(other: MusicSheet): number {
+        return this.Title.Text.CompareTo(other.Title.Text);
+    }
+    public get IInstruments(): List<IInstrument> {
+        var list: List<IInstrument> = new List<IInstrument>();
+        for (var idx: number = 0, len = this.instruments.Count; idx < len; ++idx) {
+            var instr: Instrument = this.instruments[idx];
+            list.Add(instr);
+        }
+        return list;
+    }
+    public get IInitializableInstruments(): List<ISettableInstrument> {
+        var list: List<ISettableInstrument> = new List<ISettableInstrument>();
+        for (var idx: number = 0, len = this.instruments.Count; idx < len; ++idx) {
+            var instr: Instrument = this.instruments[idx];
+            list.Add(instr);
+        }
+        return list;
+    }
+    public get IRepetitions(): List<IRepetition> {
+        try {
+            var repetitions: List<IRepetition> = new List<IRepetition>();
+            for (var idx: number = 0, len = this.repetitions.Count; idx < len; ++idx) {
+                var partListEntry: PartListEntry = this.repetitions[idx];
+                if (partListEntry instanceof Repetition) {
+                    repetitions.Add(<Repetition>partListEntry);
+                }
+            }
+            return repetitions;
+        }
+        catch (ex) {
+            Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheet.IRepetitions get: ", ex);
+            return null;
+        }
+
+    }
+    public GetExpressionsStartTempoInBPM(): number {
+        if (this.TimestampSortedTempoExpressionsList.Count > 0) {
+            var me: MultiTempoExpression = this.TimestampSortedTempoExpressionsList[0];
+            if (me.InstantaniousTempo != null) {
+                return me.InstantaniousTempo.TempoInBpm;
+            }
+            else if (me.ContinuousTempo != null) {
+                return me.ContinuousTempo.StartTempo;
+            }
+        }
+        return this.UserStartTempoInBPM;
+    }
+    public get Errors(): Dictionary<number, List<string>> {
+        try {
+            return this.musicSheetErrors.MeasureErrors;
+        }
+        catch (ex) {
+            Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheet.Errors get: ", ex);
+            return null;
+        }
+
+    }
+    public get FirstMeasureNumber(): number {
+        try {
+            return this.getFirstSourceMeasure().MeasureNumber;
+        }
+        catch (ex) {
+            Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheet.FirstMeasureNumber: ", ex);
+            return 0;
+        }
+
+    }
+    public get LastMeasureNumber(): number {
+        try {
+            return this.getLastSourceMeasure().MeasureNumber;
+        }
+        catch (ex) {
+            Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheet.LastMeasureNumber: ", ex);
+            return 0;
+        }
+
+    }
+    public get CurrentEnrolledPosition(): Fraction {
+        return this.currentEnrolledPosition;
+    }
+    public set CurrentEnrolledPosition(value: Fraction) {
+        this.currentEnrolledPosition = new Fraction(value);
+    }
+    public get Transpose(): number {
+        return this.transpose;
+    }
+    public set Transpose(value: number) {
+        this.transpose = value;
+    }
+    public SetMusicSheetParameter(parameter: MusicSheetParameters, value: Object): void {
+        if (this.PhonicScoreInterface != null)
+            this.PhonicScoreInterface.RequestMusicSheetParameter(parameter, value);
+        else {
+            var oldValue: Object = 0;
+            if (parameter == MusicSheetParameters.MusicSheetTranspose) {
+                oldValue = this.Transpose;
+                this.Transpose = <number>value;
+            }
+            if (parameter == MusicSheetParameters.StartTempoInBPM) {
+                oldValue = this.UserStartTempoInBPM;
+                this.UserStartTempoInBPM = <number>value;
+            }
+            if (parameter == MusicSheetParameters.HighlightErrors) {
+                oldValue = value;
+            }
+            if (this.MusicSheetParameterChanged != null)
+                MusicSheetParameterChanged(null, parameter, value, oldValue);
+        }
+    }
+    public get MusicSheetParameterChanged(): MusicSheetParameterChangedDelegate {
+        return this.musicSheetParameterChangedDelegate;
+    }
+    public set MusicSheetParameterChanged(value: MusicSheetParameterChangedDelegate) {
+        this.musicSheetParameterChangedDelegate = value;
+    }
+    public get FullNameString(): string {
+        return this.ComposerString + " " + this.TitleString;
+    }
+    public get IdString(): string {
+        return this.idString;
+    }
+    public set IdString(value: string) {
+        this.idString = value;
+    }
+    public Dispose(): void {
+        this.MusicSheetParameterChanged = null;
+        for (var idx: number = 0, len = this.IInstruments.Count; idx < len; ++idx) {
+            var instrument: IInstrument = this.IInstruments[idx];
+            instrument.Dispose();
+        }
+    }
+    public getEnrolledSelectionStartTimeStampWorkaround(): Fraction {
+        var iter: MusicPartManagerIterator = this.MusicPartManager.getIterator(this.SelectionStart);
+        return new Fraction(iter.CurrentEnrolledTimestamp);
+    }
+    public get SheetEndTimestamp(): Fraction {
+        var lastMeasure: SourceMeasure = this.getLastSourceMeasure();
+        return lastMeasure.AbsoluteTimestamp + lastMeasure.Duration;
+    }
+    public getSourceMeasureFromTimeStamp(timeStamp: Fraction): SourceMeasure {
+        for (var idx: number = 0, len = this.SourceMeasures.Count; idx < len; ++idx) {
+            var sm: SourceMeasure = this.SourceMeasures[idx];
+            for (var idx2: number = 0, len2 = sm.VerticalSourceStaffEntryContainers.Count; idx2 < len2; ++idx2) {
+                var vssec: VerticalSourceStaffEntryContainer = sm.VerticalSourceStaffEntryContainers[idx2];
+                if (timeStamp == vssec.getAbsoluteTimestamp()) {
+                    return sm;
+                }
+            }
+        }
+        return this.findSourceMeasureFromTimeStamp(timeStamp);
+    }
+    public findSourceMeasureFromTimeStamp(timeStamp: Fraction): SourceMeasure {
+        for (var idx: number = 0, len = this.SourceMeasures.Count; idx < len; ++idx) {
+            var sm: SourceMeasure = this.SourceMeasures[idx];
+            if (sm.AbsoluteTimestamp >= timeStamp && timeStamp < sm.AbsoluteTimestamp + sm.Duration)
+                return sm;
+        }
+        return null;
+    }
+}

+ 51 - 0
src/MusicalScore/MusicSource/MappingSourceMusicPart.ts

@@ -0,0 +1,51 @@
+export class MappingSourceMusicPart implements IComparable, IComparable<MappingSourceMusicPart>
+{
+    constructor(sourceMusicPart: SourceMusicPart, startTimestamp: Fraction) {
+        this(sourceMusicPart, null, startTimestamp, -1, false);
+
+    }
+    constructor(sourceMusicPart: SourceMusicPart, parentPartListEntry: Repetition, startTimestamp: Fraction, repetitionRun: number, isEnding: boolean) {
+        this.sourceMusicPart = sourceMusicPart;
+        this.parentPartListEntry = parentPartListEntry;
+        this.startTimestamp = new Fraction(startTimestamp);
+        this.repetitionRun = repetitionRun;
+        this.parentRepetition = __as__<Repetition>(parentPartListEntry, Repetition);
+        this.isEnding = isEnding;
+    }
+    private sourceMusicPart: SourceMusicPart;
+    private parentRepetition: Repetition;
+    private parentPartListEntry: PartListEntry;
+    private startTimestamp: Fraction;
+    private repetitionRun: number = -1;
+    private isEnding: boolean;
+    public get IsRepetition(): boolean {
+        return this.parentRepetition != null;
+    }
+    public get IsEnding(): boolean {
+        return this.isEnding;
+    }
+    public get IsLastRepetitionRun(): boolean {
+        return this.IsRepetition && (this.repetitionRun + 1 == this.parentRepetition.UserNumberOfRepetitions);
+    }
+    public get RepetitionRun(): number {
+        return this.repetitionRun;
+    }
+    public get ParentPartListEntry(): PartListEntry {
+        return this.parentPartListEntry;
+    }
+    public get SourceMusicPart(): SourceMusicPart {
+        return this.sourceMusicPart;
+    }
+    public get StartTimestamp(): Fraction {
+        return this.startTimestamp;
+    }
+    public CompareTo(obj: Object): number {
+        var comp: MappingSourceMusicPart = __as__<MappingSourceMusicPart>(obj, MappingSourceMusicPart);
+        if (comp != null)
+            return this.startTimestamp.CompareTo(comp.startTimestamp);
+        else return 1;
+    }
+    public CompareTo(other: MappingSourceMusicPart): number {
+        return this.CompareTo(<Object>other);
+    }
+}

+ 23 - 0
src/MusicalScore/MusicSource/PartListEntry.ts

@@ -0,0 +1,23 @@
+export class PartListEntry {
+    constructor(musicSheet: MusicSheet) {
+        this.musicSheet = musicSheet;
+    }
+    protected enrolledTimestamps: List<Fraction> = new List<Fraction>();
+    protected visible: boolean = true;
+    private musicSheet: MusicSheet;
+    public AbsoluteTimestamp: Fraction;
+    public get Visible(): boolean {
+        return this.visible;
+    }
+    public set Visible(value: boolean) {
+        this.visible = value;
+    }
+    public StartIndex: number;
+    public EndIndex: number;
+    public getFirstSourceMeasure(): SourceMeasure {
+        return this.musicSheet.SourceMeasures[this.StartIndex];
+    }
+    public getLastSourceMeasure(): SourceMeasure {
+        return this.musicSheet.SourceMeasures[this.EndIndex];
+    }
+}

+ 168 - 0
src/MusicalScore/MusicSource/Repetition.ts

@@ -0,0 +1,168 @@
+export class Repetition extends PartListEntry implements IRepetition {
+    constructor(musicSheet: MusicSheet) {
+        super(musicSheet);
+        this.musicSheet = musicSheet;
+    }
+    constructor(musicSheet: MusicSheet, virtualOverallRepetition: boolean) {
+        super(musicSheet);
+        this.musicSheet = musicSheet;
+        this.virtualOverallRepetition = virtualOverallRepetition;
+    }
+    private backwardJumpInstructions: List<RepetitionInstruction> = new List<RepetitionInstruction>();
+    private endingParts: List<RepetitionEndingPart> = new List<RepetitionEndingPart>();
+    private endingIndexDict: Dictionary<number, RepetitionEndingPart> = new Dictionary<number, RepetitionEndingPart>();
+    private userNumberOfRepetitions: number = 0;
+    private visibles: List<boolean> = new List<boolean>();
+    private fromWords: boolean = false;
+    private musicSheet: MusicSheet;
+    private repetitonIterationOrder: List<number> = new List<number>();
+    private numberOfEndings: number = 1;
+    private virtualOverallRepetition: boolean;
+    public StartMarker: RepetitionInstruction;
+    public EndMarker: RepetitionInstruction;
+    public ForwardJumpInstruction: RepetitionInstruction;
+    public get BackwardJumpInstructions(): List<RepetitionInstruction> {
+        return this.backwardJumpInstructions;
+    }
+    public get EndingIndexDict(): Dictionary<number, RepetitionEndingPart> {
+        return this.endingIndexDict;
+    }
+    public get EndingParts(): List<RepetitionEndingPart> {
+        return this.endingParts;
+    }
+    public get Visibles(): List<boolean> {
+        return this.visibles;
+    }
+    public set Visibles(value: List<boolean>) {
+        this.visibles = value;
+    }
+    public get DefaultNumberOfRepetitions(): number {
+        var defaultNumber: number = 2;
+        if (this.virtualOverallRepetition)
+            defaultNumber = 1;
+        return Math.Max(Math.Max(defaultNumber, this.endingIndexDict.Count), this.checkRepetitionForMultipleLyricVerses());
+    }
+    public get UserNumberOfRepetitions(): number {
+        return this.userNumberOfRepetitions;
+    }
+    public set UserNumberOfRepetitions(value: number) {
+        this.userNumberOfRepetitions = value;
+        this.repetitonIterationOrder.Clear();
+        var endingsDiff: number = this.userNumberOfRepetitions - this.NumberOfEndings;
+        for (var i: number = 1; i <= this.userNumberOfRepetitions; i++) {
+            if (i <= endingsDiff)
+                this.repetitonIterationOrder.Add(1);
+            else {
+                this.repetitonIterationOrder.Add(i - endingsDiff);
+            }
+        }
+    }
+    public getForwardJumpTargetForIteration(iteration: number): number {
+        var endingIndex: number = this.repetitonIterationOrder[iteration - 1];
+        if (this.endingIndexDict.ContainsKey(endingIndex))
+            return this.endingIndexDict[endingIndex].part.StartIndex;
+        return -1;
+    }
+    public getBackwardJumpTarget(): number {
+        return this.StartMarker.MeasureIndex;
+    }
+    public SetEndingStartIndex(endingNumbers: List<number>, startIndex: number): void {
+        var part: RepetitionEndingPart = new RepetitionEndingPart(new SourceMusicPart(this.musicSheet, startIndex, startIndex));
+        this.endingParts.Add(part);
+        for (var idx: number = 0, len = endingNumbers.Count; idx < len; ++idx) {
+            var endingNumber: number = endingNumbers[idx];
+            try {
+                this.endingIndexDict.Add(endingNumber, part);
+                part.endingIndices.Add(endingNumber);
+                if (this.numberOfEndings < endingNumber)
+                    this.numberOfEndings = endingNumber;
+            }
+            catch (err) {
+
+            }
+
+        }
+    }
+    public SetEndingStartIndex(endingNumber: number, startIndex: number): void {
+        var part: RepetitionEndingPart = new RepetitionEndingPart(new SourceMusicPart(this.musicSheet, startIndex, startIndex));
+        this.endingParts.Add(part);
+        this.endingIndexDict.Add(endingNumber, part);
+        part.endingIndices.Add(endingNumber);
+        if (this.numberOfEndings < endingNumber)
+            this.numberOfEndings = endingNumber;
+    }
+    public setEndingEndIndex(endingNumber: number, endIndex: number): void {
+        if (this.endingIndexDict.ContainsKey(endingNumber)) {
+            this.endingIndexDict[endingNumber].part.setEndIndex(endIndex);
+        }
+    }
+    public get NumberOfEndings(): number {
+        return this.numberOfEndings;
+    }
+    public get FromWords(): boolean {
+        return this.fromWords;
+    }
+    public set FromWords(value: boolean) {
+        this.fromWords = value;
+    }
+    public get AbsoluteTimestamp(): Fraction {
+        return new Fraction(this.musicSheet.SourceMeasures[this.StartMarker.MeasureIndex].AbsoluteTimestamp);
+    }
+    public get StartIndex(): number {
+        return this.StartMarker.MeasureIndex;
+    }
+    public get EndIndex(): number {
+        if (this.BackwardJumpInstructions.Count == 0)
+            return this.StartIndex;
+        var result: number = this.BackwardJumpInstructions.Last().MeasureIndex;
+        if (this.endingIndexDict.ContainsKey(this.NumberOfEndings))
+            result = Math.Max(this.endingIndexDict[this.NumberOfEndings].part.EndIndex, result);
+        return result;
+    }
+    private checkRepetitionForMultipleLyricVerses(): number {
+        var lyricVerses: number = 0;
+        var start: number = this.StartIndex;
+        var end: number = this.EndIndex;
+        for (var measureIndex: number = start; measureIndex <= end; measureIndex++) {
+            var sourceMeasure: SourceMeasure = this.musicSheet.SourceMeasures[measureIndex];
+            for (var i: number = 0; i < sourceMeasure.CompleteNumberOfStaves; i++) {
+                for (var j: number = 0; j < sourceMeasure.VerticalSourceStaffEntryContainers.Count; j++) {
+                    if (sourceMeasure.VerticalSourceStaffEntryContainers[j][i] != null) {
+                        var sourceStaffEntry: SourceStaffEntry = sourceMeasure.VerticalSourceStaffEntryContainers[j][i];
+                        var verses: number = 0;
+                        for (var idx: number = 0, len = sourceStaffEntry.VoiceEntries.Count; idx < len; ++idx) {
+                            var voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[idx];
+                            verses += voiceEntry.LyricsEntries.Count;
+                        }
+                        lyricVerses = Math.Max(lyricVerses, verses);
+                    }
+                }
+            }
+        }
+        return lyricVerses;
+    }
+    public get FirstSourceMeasureNumber(): number {
+        return getFirstSourceMeasure().MeasureNumber;
+    }
+    public get LastSourceMeasureNumber(): number {
+        return getLastSourceMeasure().MeasureNumber;
+    }
+}
+export module Repetition {
+    export class RepetitionEndingPart {
+        constructor(endingPart: SourceMusicPart) {
+            this.part = endingPart;
+        }
+        public part: SourceMusicPart;
+        public endingIndices: List<number> = new List<number>();
+        public ToString(): string {
+            var result: string = "";
+            if (this.endingIndices.Count > 0)
+                result += this.endingIndices[0];
+            for (var i: number = 1; i < this.endingIndices.Count; i++) {
+                result += ", " + this.endingIndices[i];
+            }
+            return result;
+        }
+    }
+}

+ 44 - 0
src/MusicalScore/MusicSource/SourceMusicPart.ts

@@ -0,0 +1,44 @@
+import {PartListEntry} from "./PartListEntry";
+import {Repetition} from "./Repetition";
+import {Fraction} from "../../Common/DataObjects/fraction";
+
+export class SourceMusicPart extends PartListEntry {
+    constructor(musicSheet: MusicSheet) {
+        super(musicSheet);
+        this.musicSheet = musicSheet;
+    }
+    constructor(musicSheet: MusicSheet, startIndex: number, endIndex: number) {
+        super(musicSheet);
+        this.musicSheet = musicSheet;
+        this.startIndex = startIndex;
+        this.endIndex = endIndex;
+    }
+    protected musicSheet: MusicSheet;
+    protected parentRepetition: Repetition;
+    private startIndex: number;
+    private endIndex: number;
+    public get MeasuresCount(): number {
+        return this.endIndex - this.startIndex + 1;
+    }
+    public get StartIndex(): number {
+        return this.startIndex;
+    }
+    public get EndIndex(): number {
+        return this.endIndex;
+    }
+    public get ParentRepetition(): Repetition {
+        return this.parentRepetition;
+    }
+    public set ParentRepetition(value: Repetition) {
+        this.parentRepetition = value;
+    }
+    public get AbsoluteTimestamp(): Fraction {
+        return new Fraction(this.musicSheet.SourceMeasures[this.startIndex].AbsoluteTimestamp);
+    }
+    public setStartIndex(startIndex: number): void {
+        this.startIndex = startIndex;
+    }
+    public setEndIndex(index: number): void {
+        this.endIndex = index;
+    }
+}

+ 930 - 0
src/MusicalScore/ScoreIO/InstrumentReader.ts

@@ -0,0 +1,930 @@
+export class InstrumentReader {
+    constructor(repetitionInstructionReader: RepetitionInstructionReader, xmlMeasureList: IEnumerable<IXmlElement>, instrument: Instrument) {
+        this.repetitionInstructionReader = repetitionInstructionReader;
+        this.xmlMeasureList = xmlMeasureList.ToArray();
+        this.musicSheet = instrument.GetMusicSheet;
+        this.instrument = instrument;
+        this.activeClefs = new Array(instrument.Staves.Count);
+        this.activeClefsHaveBeenInitialized = new Array(instrument.Staves.Count);
+        for (var i: number = 0; i < instrument.Staves.Count; i++)
+            this.activeClefsHaveBeenInitialized[i] = false;
+        createExpressionGenerators(instrument.Staves.Count);
+        this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
+    }
+    private repetitionInstructionReader: RepetitionInstructionReader;
+    private xmlMeasureList: IXmlElement[];
+    private musicSheet: MusicSheet;
+    private slurReader: SlurReader;
+    private instrument: Instrument;
+    private voiceGeneratorsDict: Dictionary<number, VoiceGenerator> = new Dictionary<number, VoiceGenerator>();
+    private staffMainVoiceGeneratorDict: Dictionary<Staff, VoiceGenerator> = new Dictionary<Staff, VoiceGenerator>();
+    private inSourceMeasureInstrumentIndex: number;
+    private divisions: number = 0;
+    private currentMeasure: SourceMeasure;
+    private previousMeasure: SourceMeasure;
+    private currentXmlMeasureIndex: number = 0;
+    private currentStaff: Staff;
+    private currentStaffEntry: SourceStaffEntry;
+    private activeClefs: ClefInstruction[];
+    private activeKey: KeyInstruction;
+    private activeRhythm: RhythmInstruction;
+    private activeClefsHaveBeenInitialized: boolean[];
+    private activeKeyHasBeenInitialized: boolean = false;
+    private abstractInstructions: List<KeyValuePairClass<number, AbstractNotationInstruction>> = new List<KeyValuePairClass<number, AbstractNotationInstruction>>();
+    private openChordSymbolContainer: ChordSymbolContainer;
+    private expressionReaders: ExpressionReader[];
+    private currentVoiceGenerator: VoiceGenerator;
+    private openSlurDict: Dictionary<number, Slur> = new Dictionary<number, Slur>();
+    private maxTieNoteFraction: Fraction;
+    public get ActiveKey(): KeyInstruction {
+        return this.activeKey;
+    }
+    public get MaxTieNoteFraction(): Fraction {
+        return this.maxTieNoteFraction;
+    }
+    public get ActiveRhythm(): RhythmInstruction {
+        return this.activeRhythm;
+    }
+    public set ActiveRhythm(value: RhythmInstruction) {
+        this.activeRhythm = value;
+    }
+    public readNextXmlMeasure(currentMeasure: SourceMeasure, measureStartAbsoluteTimestamp: Fraction, guitarPro: boolean): boolean {
+        if (this.currentXmlMeasureIndex >= this.xmlMeasureList.length)
+            return false;
+        this.currentMeasure = currentMeasure;
+        this.inSourceMeasureInstrumentIndex = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument);
+        if (this.repetitionInstructionReader != null)
+            this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
+        var currentFraction: Fraction = new Fraction(0, 1);
+        var previousFraction: Fraction = new Fraction(0, 1);
+        var divisionsException: boolean = false;
+        this.maxTieNoteFraction = new Fraction(0, 1);
+        var lastNoteWasGrace: boolean = false;
+        try {
+            var xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[this.currentXmlMeasureIndex].Elements().ToArray();
+            for (var idx: number = 0, len = xmlMeasureListArr.length; idx < len; ++idx) {
+                var xmlNode: IXmlElement = xmlMeasureListArr[idx];
+                if (xmlNode.Name == "note") {
+                    if ((xmlNode.HasAttributes && xmlNode.Attribute("print-object") != null && xmlNode.Attribute("print-spacing") != null)) {
+                        continue;
+                    }
+                    var noteStaff: number = 1;
+                    if (this.instrument.Staves.Count > 1) {
+                        try {
+                            if (xmlNode.Element("staff") != null)
+                                noteStaff = StringToNumberConverter.ToInteger(xmlNode.Element("staff").Value);
+                        }
+                        catch (ex) {
+                            Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.readNextXmlMeasure.get staff number", ex);
+                            noteStaff = 1;
+                        }
+
+                    }
+                    this.currentStaff = this.instrument.Staves[noteStaff - 1];
+                    var isChord: boolean = xmlNode.Element("chord") != null;
+                    if (xmlNode.Element("voice") != null) {
+                        var noteVoice: number = StringToNumberConverter.ToInteger(xmlNode.Element("voice").Value);
+                        this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(noteVoice, noteStaff - 1);
+                    }
+                    else {
+                        if (!isChord || this.currentVoiceGenerator == null)
+                            this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(1, noteStaff - 1);
+                    }
+                    var noteDivisions: number = 0;
+                    var noteDuration: Fraction = new Fraction(0, 1);
+                    var isTuplet: boolean = false;
+                    if (xmlNode.Element("duration") != null) {
+                        try {
+                            noteDivisions = StringToNumberConverter.ToInteger(xmlNode.Element("duration").Value);
+                            noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
+                            if (noteDivisions == 0) {
+                                noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
+                            }
+                            if (xmlNode.Element("time-modification") != null) {
+                                noteDuration = this.getNoteDurationForTuplet(xmlNode);
+                                isTuplet = true;
+                            }
+                        }
+                        catch (ex) {
+                            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid Note Duration.");
+                            this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                            Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.readNextXmlMeasure", errorMsg, ex);
+                            continue;
+                        }
+
+                    }
+                    var restNote: boolean = xmlNode.Element("rest") != null;
+                    var isGraceNote: boolean = xmlNode.Element("grace") != null || noteDivisions == 0 || isChord && lastNoteWasGrace;
+                    var musicTimestamp: Fraction = new Fraction(currentFraction);
+                    if (isChord)
+                        musicTimestamp = new Fraction(previousFraction);
+                    var newContainerCreated: boolean;
+                    this.currentStaffEntry = this.currentMeasure.findOrCreateStaffEntry(musicTimestamp,
+                        this.inSourceMeasureInstrumentIndex + noteStaff - 1, this.currentStaff, newContainerCreated);
+                    if (!this.currentVoiceGenerator.hasVoiceEntry() || !isChord && !isGraceNote && !lastNoteWasGrace || !lastNoteWasGrace && isGraceNote) {
+                        this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote);
+                    }
+                    if (!isGraceNote && !isChord) {
+                        previousFraction = new Fraction(currentFraction);
+                        currentFraction.Add(new Fraction(noteDuration));
+                    }
+                    if (isChord) {
+                        if (this.currentStaffEntry != null && this.currentStaffEntry.ParentStaff != this.currentStaff)
+                            this.currentStaffEntry = this.currentVoiceGenerator.checkForStaffEntryLink(this.inSourceMeasureInstrumentIndex + noteStaff - 1, this.currentStaff, this.currentStaffEntry, this.currentMeasure);
+                    }
+                    var beginOfMeasure: boolean = (this.currentStaffEntry != null && this.currentStaffEntry.Timestamp != null && this.currentStaffEntry.Timestamp == new Fraction(0, 1) && !this.currentStaffEntry.hasNotes());
+                    saveAbstractInstructionList(this.instrument.Staves.Count, beginOfMeasure);
+                    if (this.openChordSymbolContainer != null) {
+                        this.currentStaffEntry.ChordContainer = this.openChordSymbolContainer;
+                        this.openChordSymbolContainer = null;
+                    }
+                    if (this.activeRhythm != null)
+                        this.musicSheet.SheetPlaybackSetting.Rhythm = this.activeRhythm.Rhythm;
+                    if (isTuplet)
+                        this.currentVoiceGenerator.read(xmlNode, noteDuration.Numerator, noteDuration.Denominator,
+                            restNote, isGraceNote, this.currentStaffEntry, this.currentMeasure,
+                            measureStartAbsoluteTimestamp, this.maxTieNoteFraction, isChord, guitarPro);
+                    else this.currentVoiceGenerator.read(xmlNode, noteDivisions, 4 * this.divisions, restNote, isGraceNote,
+                        this.currentStaffEntry, this.currentMeasure, measureStartAbsoluteTimestamp,
+                        this.maxTieNoteFraction, isChord, guitarPro);
+                    var notationsNode: IXmlElement = xmlNode.Element("notations");
+                    if (notationsNode != null && notationsNode.Element("dynamics") != null) {
+                        var expressionReader: ExpressionReader = this.expressionReaders[this.readExpressionStaffNumber(xmlNode) - 1];
+                        if (expressionReader != null) {
+                            expressionReader.readExpressionParameters(xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false);
+                            expressionReader.read(xmlNode, this.currentMeasure, previousFraction);
+                        }
+                    }
+                    lastNoteWasGrace = isGraceNote;
+                }
+                else if (xmlNode.Name == "attributes") {
+                    var divisionsNode: IXmlElement = xmlNode.Element("divisions");
+                    if (divisionsNode != null) {
+                        try {
+                            this.divisions = StringToNumberConverter.ToInteger(divisionsNode.Value);
+                        }
+                        catch (e) {
+                            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
+                            Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.readNextXmlMeasure", errorMsg, e);
+                            this.divisions = this.readDivisionsFromNotes();
+                            if (this.divisions > 0)
+                                this.musicSheet.SheetErrors.Errors.Add(errorMsg + this.instrument.Name);
+                            else {
+                                divisionsException = true;
+                                throw new MusicSheetReadingException(errorMsg + this.instrument.Name, 0);
+                            }
+                        }
+
+                    }
+                    if (xmlNode.Element("divisions") == null && this.divisions == 0 && this.currentXmlMeasureIndex == 0) {
+                        var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
+                        this.divisions = this.readDivisionsFromNotes();
+                        if (this.divisions > 0)
+                            this.musicSheet.SheetErrors.Errors.Add(errorMsg + this.instrument.Name);
+                        else {
+                            divisionsException = true;
+                            throw new MusicSheetReadingException(errorMsg + this.instrument.Name, 0);
+                        }
+                    }
+                    this.addAbstractInstruction(xmlNode, guitarPro);
+                    if (currentFraction == new Fraction(0, 1) && this.isAttributesNodeAtBeginOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode))
+                        saveAbstractInstructionList(this.instrument.Staves.Count, true);
+                    if (this.isAttributesNodeAtEndOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode))
+                        this.saveClefInstructionAtEndOfMeasure();
+                }
+                else if (xmlNode.Name == "forward") {
+                    var forFraction: number = StringToNumberConverter.ToInteger(xmlNode.Element("duration").Value);
+                    currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
+                }
+                else if (xmlNode.Name == "backup") {
+                    var backFraction: number = StringToNumberConverter.ToInteger(xmlNode.Element("duration").Value);
+                    currentFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
+                    if (currentFraction.Numerator < 0)
+                        currentFraction = new Fraction(0, 1);
+                    previousFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
+                    if (previousFraction.Numerator < 0)
+                        previousFraction = new Fraction(0, 1);
+                }
+                else if (xmlNode.Name == "direction") {
+                    var directionTypeNode: IXmlElement = xmlNode.Element("direction-type");
+                    MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
+                    var relativePositionInMeasure: number = Math.Min(1, currentFraction.RealValue);
+                    if (this.activeRhythm != null && this.activeRhythm.Rhythm != null)
+                        relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
+                    var handeled: boolean = false;
+                    if (this.repetitionInstructionReader != null)
+                        handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode, relativePositionInMeasure);
+                    if (!handeled) {
+                        var expressionReader: ExpressionReader = this.expressionReaders[0];
+                        var staffIndex: number = this.readExpressionStaffNumber(xmlNode) - 1;
+                        if (staffIndex < this.expressionReaders.Count())
+                            expressionReader = this.expressionReaders[staffIndex];
+                        if (expressionReader != null) {
+                            if (directionTypeNode.Element("octave-shift") != null) {
+                                expressionReader.readExpressionParameters(xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, true);
+                                expressionReader.addOctaveShift(xmlNode, this.currentMeasure, new Fraction(previousFraction));
+                            }
+                            expressionReader.readExpressionParameters(xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false);
+                            expressionReader.read(xmlNode, this.currentMeasure, currentFraction);
+                        }
+                    }
+                }
+                else if (xmlNode.Name == "barline") {
+                    if (this.repetitionInstructionReader != null) {
+                        var measureEndsSystem: boolean = false;
+                        this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
+                        if (measureEndsSystem) {
+                            this.currentMeasure.BreakSystemAfter = true;
+                            this.currentMeasure.EndsPiece = true;
+                        }
+                    }
+                }
+                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);
+                }
+            }
+            for (var j: number = 0; j < this.voiceGeneratorsDict.Count; j++) {
+                var keyValuePair: KeyValuePair<number, VoiceGenerator> = this.voiceGeneratorsDict.ElementAt(j);
+                var voiceGenerator: VoiceGenerator = keyValuePair.Value;
+                voiceGenerator.checkForOpenBeam();
+                voiceGenerator.checkForOpenGraceNotes();
+            }
+            if (this.currentXmlMeasureIndex == this.xmlMeasureList.length - 1) {
+                for (var i: number = 0; i < this.instrument.Staves.Count; i++)
+                    if (!this.activeClefsHaveBeenInitialized[i])
+                        createDefaultClefInstruction(this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument) + i);
+                if (!this.activeKeyHasBeenInitialized)
+                    this.createDefaultKeyInstruction();
+                for (var i: number = 0; i < this.expressionReaders.length; i++) {
+                    var reader: ExpressionReader = this.expressionReaders[i];
+                    if (reader != null)
+                        reader.checkForOpenExpressions(this.currentMeasure, currentFraction);
+                }
+            }
+        }
+        catch (e) {
+            if (divisionsException) {
+                throw new MusicSheetReadingException(e.Message, e, 0);
+            }
+            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MeasureError", "Error while reading Measure.");
+            this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+            Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.readNextXmlMeasure", errorMsg, e);
+        }
+
+        this.previousMeasure = this.currentMeasure;
+        this.currentXmlMeasureIndex++;
+        return true;
+    }
+    public doCalculationsAfterDurationHasBeenSet(): void {
+        for (var j: number = 0; j < this.voiceGeneratorsDict.Count; j++) {
+            var keyValuePair: KeyValuePair<number, VoiceGenerator> = this.voiceGeneratorsDict.ElementAt(j);
+            var voiceGenerator: VoiceGenerator = keyValuePair.Value;
+            voiceGenerator.checkOpenTies();
+        }
+    }
+    private getOrCreateVoiceGenerator(voiceId: number, staffId: number): VoiceGenerator {
+        var voiceGenerator: VoiceGenerator;
+        var staff: Staff = this.instrument.Staves[staffId];
+        if (this.voiceGeneratorsDict.ContainsKey(voiceId)) {
+            voiceGenerator = this.voiceGeneratorsDict[voiceId];
+            if (!staff.Voices.Contains(voiceGenerator.GetVoice))
+                staff.Voices.Add(voiceGenerator.GetVoice);
+            return voiceGenerator;
+        }
+        else {
+            if (this.staffMainVoiceGeneratorDict.ContainsKey(staff)) {
+                var mainVoiceGenerator: VoiceGenerator = this.staffMainVoiceGeneratorDict[staff];
+                voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader, mainVoiceGenerator.GetVoice);
+                staff.Voices.Add(voiceGenerator.GetVoice);
+                this.voiceGeneratorsDict.Add(voiceId, voiceGenerator);
+                return voiceGenerator;
+            }
+            voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader);
+            staff.Voices.Add(voiceGenerator.GetVoice);
+            this.voiceGeneratorsDict.Add(voiceId, voiceGenerator);
+            this.staffMainVoiceGeneratorDict.Add(staff, voiceGenerator);
+            return voiceGenerator;
+        }
+    }
+    private createExpressionGenerators(numberOfStaves: number): void {
+        this.expressionReaders = new Array(numberOfStaves);
+        for (var i: number = 0; i < numberOfStaves; i++)
+            this.expressionReaders[i] = MusicSymbolModuleFactory.createExpressionGenerator(this.musicSheet, this.instrument, i + 1);
+    }
+    private createDefaultClefInstruction(staffIndex: number): void {
+        var first: SourceMeasure;
+        if (this.musicSheet.SourceMeasures.Count > 0)
+            first = this.musicSheet.SourceMeasures[0];
+        else first = this.currentMeasure;
+        var clefInstruction: ClefInstruction = new ClefInstruction(ClefEnum.G, 0, 2);
+        var firstStaffEntry: SourceStaffEntry;
+        if (first.FirstInstructionsStaffEntries[staffIndex] == null) {
+            firstStaffEntry = new SourceStaffEntry(null, null);
+            first.FirstInstructionsStaffEntries[staffIndex] = firstStaffEntry;
+        }
+        else {
+            firstStaffEntry = first.FirstInstructionsStaffEntries[staffIndex];
+            firstStaffEntry.removeFirstInstructionOfType<ClefInstruction>();
+        }
+        clefInstruction.Parent = firstStaffEntry;
+        firstStaffEntry.Instructions.Insert(0, clefInstruction);
+    }
+    private createDefaultKeyInstruction(): void {
+        var first: SourceMeasure;
+        if (this.musicSheet.SourceMeasures.Count > 0)
+            first = this.musicSheet.SourceMeasures[0];
+        else first = this.currentMeasure;
+        var keyInstruction: KeyInstruction = new KeyInstruction(0, KeyEnum.major);
+        for (var j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + this.instrument.Staves.Count; j++) {
+            if (first.FirstInstructionsStaffEntries[j] == null) {
+                var firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(null, null);
+                first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+                keyInstruction.Parent = firstStaffEntry;
+                firstStaffEntry.Instructions.Add(keyInstruction);
+            }
+            else {
+                var firstStaffEntry: SourceStaffEntry = first.FirstInstructionsStaffEntries[j];
+                keyInstruction.Parent = firstStaffEntry;
+                firstStaffEntry.removeFirstInstructionOfType<KeyInstruction>();
+                if (firstStaffEntry.Instructions[0] instanceof ClefInstruction)
+                    firstStaffEntry.Instructions.Insert(1, keyInstruction);
+                else firstStaffEntry.Instructions.Insert(0, keyInstruction);
+            }
+        }
+    }
+    private isAttributesNodeAtBeginOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
+        var childs: IXmlElement[] = parentNode.Elements().ToArray();
+        var attributesNodeIndex: number = 0;
+        for (var i: number = 0; i < childs.length; i++) {
+            if (childs[i] == attributesNode) {
+                attributesNodeIndex = i;
+                break;
+            }
+        }
+        if (attributesNodeIndex > 0 && childs[attributesNodeIndex - 1].Name == "backup")
+            return true;
+        var firstNoteNodeIndex: number = -1;
+        for (var i: number = 0; i < childs.length; i++) {
+            if (childs[i].Name == "note") {
+                firstNoteNodeIndex = i;
+                break;
+            }
+        }
+        if ((attributesNodeIndex < firstNoteNodeIndex && firstNoteNodeIndex > 0) || (firstNoteNodeIndex < 0))
+            return true;
+        return false;
+    }
+    private isAttributesNodeAtEndOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
+        var childs: IXmlElement[] = parentNode.Elements().ToArray();
+        var attributesNodeIndex: number = 0;
+        for (var i: number = 0; i < childs.length; i++) {
+            if (childs[i] == attributesNode) {
+                attributesNodeIndex = i;
+                break;
+            }
+        }
+        var nextNoteNodeIndex: number = 0;
+        for (var i: number = attributesNodeIndex; i < childs.length; i++) {
+            if (childs[i].Name == "note") {
+                nextNoteNodeIndex = i;
+                break;
+            }
+        }
+        if (attributesNodeIndex > nextNoteNodeIndex)
+            return true;
+        return false;
+    }
+    private getNoteDurationFromTypeNode(xmlNode: IXmlElement): Fraction {
+        if (xmlNode.Element("type") != null) {
+            var typeNode: IXmlElement = xmlNode.Element("type");
+            if (typeNode != null) {
+                var type: string = typeNode.Value;
+                return this.currentVoiceGenerator.getNoteDurationFromType(type);
+            }
+        }
+        return new Fraction(0, 4 * this.divisions);
+    }
+    private addAbstractInstruction(node: IXmlElement, guitarPro: boolean): void {
+        if (node.Element("divisions") != null) {
+            if (node.Elements().Count() == 1)
+                return
+        }
+        var transposeNode: IXmlElement = node.Element("transpose");
+        if (transposeNode != null) {
+            var chromaticNode: IXmlElement = transposeNode.Element("chromatic");
+            if (chromaticNode != null)
+                this.instrument.PlaybackTranspose = StringToNumberConverter.ToInteger(chromaticNode.Value);
+        }
+        var clefList: IXmlElement[] = node.Elements("clef").ToArray();
+        if (clefList.length > 0) {
+            for (var idx: number = 0, len = clefList.Count(); idx < len; ++idx) {
+                var nodeList: IXmlElement = clefList[idx];
+                var clefEnum: ClefEnum = ClefEnum.G;
+                var line: number = 2;
+                var staffNumber: number = 1;
+                var clefOctaveOffset: number = 0;
+                var lineNode: IXmlElement = nodeList.Element("line");
+                if (lineNode != null) {
+                    try {
+                        line = StringToNumberConverter.ToInteger(lineNode.Value);
+                    }
+                    catch (ex) {
+                        var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ClefLineError",
+                            "Invalid clef line given -> using default clef line.");
+                        this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                        line = 2;
+                        Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.addAbstractInstruction", errorMsg, ex);
+                    }
+
+                }
+                var signNode: IXmlElement = nodeList.Element("sign");
+                if (signNode != null) {
+                    try {
+                        clefEnum = <ClefEnum>Enum.Parse(/*typeof*/ClefEnum, signNode.Value);
+                        if (!ClefInstruction.isSupportedClef(clefEnum)) {
+                            if (clefEnum == ClefEnum.TAB && guitarPro) {
+                                clefOctaveOffset = -1;
+                            }
+                            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ClefError",
+                                "Unsupported clef found -> using default clef.");
+                            this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                            clefEnum = ClefEnum.G;
+                            line = 2;
+                        }
+                    }
+                    catch (e) {
+                        var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ClefError",
+                            "Invalid clef found -> using default clef.");
+                        this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                        clefEnum = ClefEnum.G;
+                        line = 2;
+                        Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.addAbstractInstruction", errorMsg, e);
+                    }
+
+                }
+                var clefOctaveNode: IXmlElement = nodeList.Element("clef-octave-change");
+                if (clefOctaveNode != null) {
+                    try {
+                        clefOctaveOffset = StringToNumberConverter.ToInteger(clefOctaveNode.Value);
+                    }
+                    catch (e) {
+                        var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ClefOctaveError",
+                            "Invalid clef octave found -> using default clef octave.");
+                        this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                        clefOctaveOffset = 0;
+                    }
+
+                }
+                if (nodeList.HasAttributes)
+                    if (nodeList.Attributes().First().Name == "number") {
+                        try {
+                            staffNumber = StringToNumberConverter.ToInteger(nodeList.Attributes().First().Value);
+                        }
+                        catch (err) {
+                            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ClefError",
+                                "Invalid clef found -> using default clef.");
+                            this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                            staffNumber = 1;
+                        }
+
+                    }
+                var clefInstruction: ClefInstruction = new ClefInstruction(clefEnum, clefOctaveOffset, line);
+                this.abstractInstructions.Add(new KeyValuePairClass<number, AbstractNotationInstruction>(staffNumber, clefInstruction));
+            }
+        }
+        if (node.Element("key") != null && this.instrument.MidiInstrumentId != Common.Enums.MidiInstrument.Percussion) {
+            var key: number = 0;
+            var keyNode: IXmlElement = node.Element("key").Element("fifths");
+            if (keyNode != null) {
+                try {
+                    key = <number>StringToNumberConverter.ToInteger(keyNode.Value);
+                }
+                catch (ex) {
+                    var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/KeyError",
+                        "Invalid key found -> set to default.");
+                    this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                    key = 0;
+                    Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.addAbstractInstruction", errorMsg, ex);
+                }
+
+            }
+            var keyEnum: KeyEnum = KeyEnum.none;
+            var modeNode: IXmlElement = node.Element("key");
+            if (modeNode != null)
+                modeNode = modeNode.Element("mode");
+            if (modeNode != null) {
+                try {
+                    keyEnum = <KeyEnum>Enum.Parse(/*typeof*/KeyEnum, modeNode.Value);
+                }
+                catch (ex) {
+                    var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/KeyError",
+                        "Invalid key found -> set to default.");
+                    this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                    keyEnum = KeyEnum.major;
+                    Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.addAbstractInstruction", errorMsg, ex);
+                }
+
+            }
+            var keyInstruction: KeyInstruction = new KeyInstruction(key, keyEnum);
+            this.abstractInstructions.Add(new KeyValuePairClass<number, AbstractNotationInstruction>(1, keyInstruction));
+        }
+        if (node.Element("time") != null) {
+            var symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
+            var timeNode: IXmlElement = node.Element("time");
+            if (timeNode != null)
+                if (timeNode.HasAttributes)
+                    if (timeNode.Attributes().First() != null) {
+                        var firstAttr: IXmlAttribute = timeNode.Attributes().First();
+                        if (firstAttr.Name == "symbol") {
+                            if (firstAttr.Value == "common")
+                                symbolEnum = RhythmSymbolEnum.COMMON;
+                            else if (firstAttr.Value == "cut")
+                                symbolEnum = RhythmSymbolEnum.CUT;
+                        }
+                    }
+            var num: number = 0;
+            var denom: number = 0;
+            var senzaMisura: boolean = (timeNode != null && timeNode.Element("senza-misura") != null);
+            var timeList: IXmlElement[] = node.Elements("time").ToArray();
+            var beatsList: List<IXmlElement> = new List<IXmlElement>();
+            var typeList: List<IXmlElement> = new List<IXmlElement>();
+            for (var idx: number = 0, len = timeList.length; idx < len; ++idx) {
+                var xmlNode: IXmlElement = timeList[idx];
+                beatsList.AddRange(xmlNode.Elements("beats"));
+                typeList.AddRange(xmlNode.Elements("beat-type"));
+            }
+            if (!senzaMisura) {
+                try {
+                    if (beatsList != null && beatsList.Count > 0 && typeList != null && beatsList.Count == typeList.Count) {
+                        var length: number = beatsList.Count();
+                        var fractions: Fraction[] = new Array(length);
+                        var maxDenom: number = 0;
+                        for (var i: number = 0; i < length; i++) {
+                            var s: string = beatsList[i].Value;
+                            var n: number = 0;
+                            var d: number = 0;
+                            if (s.IndexOf("+") != -1) {
+                                var numbers: string[] = s.Split('+');
+                                for (var idx: number = 0, len = numbers.Count(); idx < len; ++idx) {
+                                    var number: String = numbers[idx];
+                                    n += StringToNumberConverter.ToInteger(number);
+                                }
+                            }
+                            else n = StringToNumberConverter.ToInteger(s);
+                            d = StringToNumberConverter.ToInteger(typeList[i].Value);
+                            maxDenom = Math.Max(maxDenom, d);
+                            fractions[i] = new Fraction(n, d, false);
+                        }
+                        for (var i: number = 0; i < length; i++) {
+                            if (fractions[i].Denominator == maxDenom)
+                                num += fractions[i].Numerator;
+                            else num += (maxDenom / fractions[i].Denominator) * fractions[i].Numerator;
+                        }
+                        denom = maxDenom;
+                    }
+                    else {
+                        num = StringToNumberConverter.ToInteger(node.Element("time").Element("beats").Value);
+                        denom = StringToNumberConverter.ToInteger(node.Element("time").Element("beat-type").Value);
+                    }
+                }
+                catch (ex) {
+                    var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/RhythmError", "Invalid rhythm found -> set to default.");
+                    this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                    num = 4;
+                    denom = 4;
+                    Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.addAbstractInstruction", errorMsg, ex);
+                }
+
+                var measure: Fraction = new Fraction(num, denom, false);
+                if (symbolEnum != RhythmSymbolEnum.NONE && (measure != new Fraction(4, 4) || measure != new Fraction(2, 2)))
+                    symbolEnum = RhythmSymbolEnum.NONE;
+                var rhythmInstruction: RhythmInstruction = new RhythmInstruction(measure, num, denom, symbolEnum);
+                this.abstractInstructions.Add(new KeyValuePairClass<number, AbstractNotationInstruction>(1, rhythmInstruction));
+            }
+            else {
+                var rhythmInstruction: RhythmInstruction = new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE);
+                this.abstractInstructions.Add(new KeyValuePairClass<number, AbstractNotationInstruction>(1, rhythmInstruction));
+            }
+        }
+    }
+    private saveAbstractInstructionList(numberOfStaves: number, beginOfMeasure: boolean): void {
+        for (var i: number = this.abstractInstructions.Count - 1; i >= 0; i--) {
+            var keyValuePair: KeyValuePairClass<number, AbstractNotationInstruction> = this.abstractInstructions[i];
+            if (keyValuePair.value instanceof ClefInstruction) {
+                var clefInstruction: ClefInstruction = <ClefInstruction>keyValuePair.value;
+                if (this.currentXmlMeasureIndex == 0 || (keyValuePair.key <= this.activeClefs.length && clefInstruction != this.activeClefs[keyValuePair.key - 1])) {
+                    if (!beginOfMeasure && this.currentStaffEntry != null && !this.currentStaffEntry.hasNotes() && keyValuePair.key - 1 == this.instrument.Staves.IndexOf(this.currentStaffEntry.ParentStaff)) {
+                        var newClefInstruction: ClefInstruction = clefInstruction;
+                        newClefInstruction.Parent = this.currentStaffEntry;
+                        this.currentStaffEntry.removeFirstInstructionOfType<ClefInstruction>();
+                        this.currentStaffEntry.Instructions.Add(newClefInstruction);
+                        this.activeClefs[keyValuePair.key - 1] = clefInstruction;
+                        this.abstractInstructions.Remove(keyValuePair);
+                    }
+                    else if (beginOfMeasure) {
+                        if (this.currentMeasure != null) {
+                            var newClefInstruction: ClefInstruction = clefInstruction;
+                            if (this.currentXmlMeasureIndex == 0) {
+                                if (this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1] == null) {
+                                    var firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(null, null);
+                                    this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1] = firstStaffEntry;
+                                    newClefInstruction.Parent = firstStaffEntry;
+                                    firstStaffEntry.Instructions.Add(newClefInstruction);
+                                    this.activeClefsHaveBeenInitialized[keyValuePair.key - 1] = true;
+                                }
+                                else if (this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1] != null && !(this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1].Instructions[0] instanceof ClefInstruction)) {
+                                    var firstStaffEntry: SourceStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1];
+                                    newClefInstruction.Parent = firstStaffEntry;
+                                    firstStaffEntry.removeFirstInstructionOfType<ClefInstruction>();
+                                    firstStaffEntry.Instructions.Insert(0, newClefInstruction);
+                                    this.activeClefsHaveBeenInitialized[keyValuePair.key - 1] = true;
+                                }
+                                else {
+                                    var lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(null, null);
+                                    this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1] = lastStaffEntry;
+                                    newClefInstruction.Parent = lastStaffEntry;
+                                    lastStaffEntry.Instructions.Add(newClefInstruction);
+                                }
+                            }
+                            else if (!this.activeClefsHaveBeenInitialized[keyValuePair.key - 1]) {
+                                var first: SourceMeasure = this.musicSheet.SourceMeasures[0];
+                                var firstStaffEntry: SourceStaffEntry;
+                                if (first.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1] == null)
+                                    firstStaffEntry = new SourceStaffEntry(null, null);
+                                else {
+                                    firstStaffEntry = first.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1];
+                                    firstStaffEntry.removeFirstInstructionOfType<ClefInstruction>();
+                                }
+                                newClefInstruction.Parent = firstStaffEntry;
+                                firstStaffEntry.Instructions.Insert(0, newClefInstruction);
+                                this.activeClefsHaveBeenInitialized[keyValuePair.key - 1] = true;
+                            }
+                            else {
+                                var lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(null, null);
+                                this.previousMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1] = lastStaffEntry;
+                                newClefInstruction.Parent = lastStaffEntry;
+                                lastStaffEntry.Instructions.Add(newClefInstruction);
+                            }
+                            this.activeClefs[keyValuePair.key - 1] = clefInstruction;
+                            this.abstractInstructions.Remove(keyValuePair);
+                        }
+                    }
+                }
+                if (keyValuePair.key <= this.activeClefs.length && clefInstruction == this.activeClefs[keyValuePair.key - 1])
+                    this.abstractInstructions.Remove(keyValuePair);
+            }
+            if (keyValuePair.value instanceof KeyInstruction) {
+                var keyInstruction: KeyInstruction = <KeyInstruction>keyValuePair.value;
+                if (this.activeKey == null || this.activeKey.Key != keyInstruction.Key) {
+                    this.activeKey = keyInstruction;
+                    this.abstractInstructions.Remove(keyValuePair);
+                    var sourceMeasure: SourceMeasure;
+                    if (!this.activeKeyHasBeenInitialized) {
+                        this.activeKeyHasBeenInitialized = true;
+                        if (this.currentXmlMeasureIndex > 0)
+                            sourceMeasure = this.musicSheet.SourceMeasures[0];
+                        else sourceMeasure = this.currentMeasure;
+                    }
+                    else sourceMeasure = this.currentMeasure;
+                    if (sourceMeasure != null) {
+                        for (var j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
+                            var newKeyInstruction: KeyInstruction = keyInstruction;
+                            if (sourceMeasure.FirstInstructionsStaffEntries[j] == null) {
+                                var firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(null, null);
+                                sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+                                newKeyInstruction.Parent = firstStaffEntry;
+                                firstStaffEntry.Instructions.Add(newKeyInstruction);
+                            }
+                            else {
+                                var firstStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[j];
+                                newKeyInstruction.Parent = firstStaffEntry;
+                                firstStaffEntry.removeFirstInstructionOfType<KeyInstruction>();
+                                if (firstStaffEntry.Instructions.Count == 0) {
+                                    firstStaffEntry.Instructions.Add(newKeyInstruction);
+                                }
+                                else {
+                                    if (firstStaffEntry.Instructions[0] instanceof ClefInstruction)
+                                        firstStaffEntry.Instructions.Insert(1, newKeyInstruction);
+                                    else firstStaffEntry.Instructions.Insert(0, newKeyInstruction);
+                                }
+                            }
+                        }
+                    }
+                }
+                if (this.activeKey != null && this.activeKey == keyInstruction)
+                    this.abstractInstructions.Remove(keyValuePair);
+            }
+            if (keyValuePair.value instanceof RhythmInstruction) {
+                var rhythmInstruction: RhythmInstruction = <RhythmInstruction>keyValuePair.value;
+                if (this.activeRhythm == null || this.activeRhythm != rhythmInstruction) {
+                    this.activeRhythm = rhythmInstruction;
+                    this.abstractInstructions.Remove(keyValuePair);
+                    if (this.currentMeasure != null) {
+                        for (var j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
+                            var newRhythmInstruction: RhythmInstruction = rhythmInstruction;
+                            var firstStaffEntry: SourceStaffEntry;
+                            if (this.currentMeasure.FirstInstructionsStaffEntries[j] == null) {
+                                firstStaffEntry = new SourceStaffEntry(null, null);
+                                this.currentMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
+                            }
+                            else {
+                                firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[j];
+                                firstStaffEntry.removeFirstInstructionOfType<RhythmInstruction>();
+                            }
+                            newRhythmInstruction.Parent = firstStaffEntry;
+                            firstStaffEntry.Instructions.Add(newRhythmInstruction);
+                        }
+                    }
+                }
+                if (this.activeRhythm != null && this.activeRhythm == rhythmInstruction)
+                    this.abstractInstructions.Remove(keyValuePair);
+            }
+        }
+    }
+    private saveClefInstructionAtEndOfMeasure(): void {
+        for (var i: number = this.abstractInstructions.Count - 1; i >= 0; i--) {
+            var keyValuePair: KeyValuePairClass<number, AbstractNotationInstruction> = this.abstractInstructions[i];
+            if (keyValuePair.value instanceof ClefInstruction) {
+                var clefInstruction: ClefInstruction = __as__<ClefInstruction>(keyValuePair.value, ClefInstruction);
+                if ((this.activeClefs[keyValuePair.key - 1] == null) || (this.activeClefs[keyValuePair.key - 1] != null && (clefInstruction.ClefType != this.activeClefs[keyValuePair.key - 1].ClefType || (clefInstruction.ClefType == this.activeClefs[keyValuePair.key - 1].ClefType && clefInstruction.Line != this.activeClefs[keyValuePair.key - 1].Line)))) {
+                    var lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(null, null);
+                    this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + keyValuePair.key - 1] = lastStaffEntry;
+                    var newClefInstruction: ClefInstruction = clefInstruction;
+                    newClefInstruction.Parent = lastStaffEntry;
+                    lastStaffEntry.Instructions.Add(newClefInstruction);
+                    this.activeClefs[keyValuePair.key - 1] = clefInstruction;
+                    this.abstractInstructions.Remove(keyValuePair);
+                }
+            }
+        }
+    }
+    private getNoteDurationForTuplet(xmlNode: IXmlElement): Fraction {
+        var duration: Fraction = new Fraction(0, 1);
+        var typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
+        if (xmlNode.Element("time-modification") != null) {
+            var time: IXmlElement = xmlNode.Element("time-modification");
+            if (time != null) {
+                if (time.Element("actual-notes") != null && time.Element("normal-notes") != null) {
+                    var actualNotes: IXmlElement = time.Element("actual-notes");
+                    var normalNotes: IXmlElement = time.Element("normal-notes");
+                    if (actualNotes != null && normalNotes != null) {
+                        var actual: number = StringToNumberConverter.ToInteger(actualNotes.Value);
+                        var normal: number = StringToNumberConverter.ToInteger(normalNotes.Value);
+                        duration = new Fraction(normal, actual) * typeDuration;
+                    }
+                }
+            }
+        }
+        return duration;
+    }
+    private readExpressionStaffNumber(xmlNode: IXmlElement): number {
+        var directionStaffNumber: number = 1;
+        if (xmlNode.Element("staff") != null) {
+            var staffNode: IXmlElement = xmlNode.Element("staff");
+            if (staffNode != null) {
+                try {
+                    directionStaffNumber = StringToNumberConverter.ToInteger(staffNode.Value);
+                }
+                catch (ex) {
+                    var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/ExpressionStaffError", "Invalid Expression staff number -> set to default.");
+                    this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                    directionStaffNumber = 1;
+                    Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.readExpressionStaffNumber", errorMsg, ex);
+                }
+
+            }
+        }
+        return directionStaffNumber;
+    }
+    private readDivisionsFromNotes(): number {
+        var divisionsFromNote: number = 0;
+        var xmlMeasureIndex: number = this.currentXmlMeasureIndex;
+        var read: boolean = false;
+        while (!read) {
+            var xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].Elements().ToArray();
+            for (var idx: number = 0, len = xmlMeasureListArr.length; idx < len; ++idx) {
+                var xmlNode: IXmlElement = xmlMeasureListArr[idx];
+                if (xmlNode.Name == "note" && xmlNode.Element("time-modification") == null) {
+                    if (xmlNode.Element("duration") != null && xmlNode.Element("type") != null) {
+                        var durationNode: IXmlElement = xmlNode.Element("duration");
+                        var typeNode: IXmlElement = xmlNode.Element("type");
+                        if (durationNode != null && typeNode != null) {
+                            var type: string = typeNode.Value;
+                            var noteDuration: number = 0;
+                            try {
+                                noteDuration = StringToNumberConverter.ToInteger(durationNode.Value);
+                            }
+                            catch (ex) {
+                                Logger.DefaultLogger.LogError(LogLevel.DEBUG, "InstrumentReader.readDivisionsFromNotes", ex);
+                                continue;
+                            }
+
+                            switch (type) {
+                                case "1024th":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 1024;
+                                        break;
+                                    }
+                                case "512th":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 512;
+                                        break;
+                                    }
+                                case "256th":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 256;
+                                        break;
+                                    }
+                                case "128th":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 128;
+                                        break;
+                                    }
+                                case "64th":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 64;
+                                        break;
+                                    }
+                                case "32nd":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 32;
+                                        break;
+                                    }
+                                case "16th":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 16;
+                                        break;
+                                    }
+                                case "eighth":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 8;
+                                        break;
+                                    }
+                                case "quarter":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 4;
+                                        break;
+                                    }
+                                case "half":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) * 2;
+                                        break;
+                                    }
+                                case "whole":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4);
+                                        break;
+                                    }
+                                case "breve":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) / 2;
+                                        break;
+                                    }
+                                case "long":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) / 4;
+                                        break;
+                                    }
+                                case "maxima":
+                                    {
+                                        divisionsFromNote = (noteDuration / 4) / 8;
+                                        break;
+                                    }
+                                default:
+                                    {
+                                        break;
+                                    }
+                            }
+                        }
+                    }
+                }
+                if (divisionsFromNote > 0) {
+                    read = true;
+                    break;
+                }
+            }
+            if (divisionsFromNote == 0) {
+                xmlMeasureIndex++;
+                if (xmlMeasureIndex == this.xmlMeasureList.length) {
+                    var errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
+                    throw new MusicSheetReadingException(errorMsg + this.instrument.Name, 0);
+                }
+            }
+        }
+        return divisionsFromNote;
+    }
+}
+export module InstrumentReader {
+    export class KeyValuePairClass<T, TU>
+    {
+        constructor(key: T, value: TU) {
+            this.key = key;
+            this.value = value;
+        }
+        public key: T;
+        public value: TU;
+    }
+}

+ 720 - 0
src/MusicalScore/ScoreIO/MusicSheetReader.ts

@@ -0,0 +1,720 @@
+export class MusicSheetReader implements IMusicSheetReader {
+    constructor(afterSheetReadingModules: List<IAfterSheetReadingModule>) {
+        this.afterSheetReadingModules = afterSheetReadingModules;
+        if (this.afterSheetReadingModules == null)
+            this.afterSheetReadingModules = new List<IAfterSheetReadingModule>();
+        this.repetitionInstructionReader = MusicSymbolModuleFactory.createRepetitionInstructionReader();
+        this.repetitionCalculator = MusicSymbolModuleFactory.createRepetitionCalculator();
+    }
+    private phonicScoreInterface: IPhonicScoreInterface;
+    private repetitionInstructionReader: RepetitionInstructionReader;
+    private repetitionCalculator: RepetitionCalculator;
+    private afterSheetReadingModules: List<IAfterSheetReadingModule>;
+    private musicSheet: MusicSheet;
+    private completeNumberOfStaves: number = 0;
+    private currentMeasure: SourceMeasure;
+    private previousMeasure: SourceMeasure;
+    private currentFraction: Fraction;
+    public get CompleteNumberOfStaves(): number {
+        return this.completeNumberOfStaves;
+    }
+    private static doCalculationsAfterDurationHasBeenSet(instrumentReaders: List<InstrumentReader>): void {
+        for (var idx: number = 0, len = instrumentReaders.Count; idx < len; ++idx) {
+            var instrumentReader: InstrumentReader = instrumentReaders[idx];
+            instrumentReader.doCalculationsAfterDurationHasBeenSet();
+        }
+    }
+    public SetPhonicScoreInterface(phonicScoreInterface: IPhonicScoreInterface): void {
+        this.phonicScoreInterface = phonicScoreInterface;
+    }
+    public ReadMusicSheetParameters(sheetObject: MusicSheetParameterObject, root: IXmlElement, path: string): MusicSheetParameterObject {
+        this.musicSheet = new MusicSheet();
+        if (root != null) {
+            this.addSheetLabels(root, path);
+            if (this.musicSheet.Title != null)
+                sheetObject.Title = this.musicSheet.Title.Text;
+            if (this.musicSheet.Composer != null)
+                sheetObject.Composer = this.musicSheet.Composer.Text;
+            if (this.musicSheet.Lyricist != null)
+                sheetObject.Lyricist = this.musicSheet.Lyricist.Text;
+            var partlistNode: IXmlElement = root.Element("part-list");
+            var partList: IEnumerable<IXmlElement> = partlistNode.Elements();
+            this.createInstrumentGroups(partList);
+            for (var idx: number = 0, len = this.musicSheet.Instruments.Count; idx < len; ++idx) {
+                var instr: Instrument = this.musicSheet.Instruments[idx];
+                sheetObject.InstrumentList.Add(__init(new MusicSheetParameterObject.LibrarySheetInstrument(), { Name: instr.Name }));
+            }
+        }
+        return sheetObject;
+    }
+    public createMusicSheet(root: IXmlElement, path: string): MusicSheet {
+        try {
+            return this._createMusicSheet(root, path);
+        }
+        catch (e) {
+            Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheetReader.CreateMusicSheet", e);
+            return null;
+        }
+
+    }
+    public CreateIMusicSheet(root: IXmlElement, path: string): IMusicSheet {
+        return this.createMusicSheet(root, path);
+    }
+    private _createMusicSheet(root: IXmlElement, path: string): MusicSheet {
+        var instrumentReaders: List<InstrumentReader> = new List<InstrumentReader>();
+        var sourceMeasureCounter: number = 0;
+        this.musicSheet = new MusicSheet();
+        this.musicSheet.Path = path;
+        try {
+            if (root != null) {
+                this.addSheetLabels(root, path);
+                var partlistNode: IXmlElement = root.Element("part-list");
+                if (partlistNode != null) {
+                    var partInst: IEnumerable<IXmlElement> = root.Elements("part");
+                    var partList: IEnumerable<IXmlElement> = partlistNode.Elements();
+                    this.initializeReading(partList, partInst, instrumentReaders);
+                    var couldReadMeasure: boolean = true;
+                    this.currentFraction = new Fraction(0, 1);
+                    var guitarPro: boolean = false;
+                    var encoding: IXmlElement = root.Element("identification");
+                    if (encoding != null)
+                        encoding = encoding.Element("encoding");
+                    if (encoding != null)
+                        encoding = encoding.Element("software");
+                    if (encoding != null) {
+                        if (encoding.Value == "Guitar Pro 5")
+                            guitarPro = true;
+                    }
+                    while (couldReadMeasure) {
+                        if (this.currentMeasure != null && this.currentMeasure.EndsPiece)
+                            sourceMeasureCounter = 0;
+                        this.currentMeasure = new SourceMeasure(this.completeNumberOfStaves);
+                        for (var i: number = 0; i < instrumentReaders.Count; i++) {
+                            try {
+                                couldReadMeasure = instrumentReaders[i].readNextXmlMeasure(this.currentMeasure, this.currentFraction, guitarPro);
+                            }
+                            catch (e) {
+                                var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/InstrumentError", "Error while reading instruments.");
+                                throw new MusicSheetReadingException(errorMsg, e, 0);
+                            }
+
+                        }
+                        if (couldReadMeasure) {
+                            this.musicSheet.addMeasure(this.currentMeasure);
+                            this.checkIfRhythmInstructionsAreSetAndEqual(instrumentReaders);
+                            this.checkSourceMeasureForNullEntries();
+                            this.setSourceMeasureDuration(instrumentReaders, sourceMeasureCounter);
+                            MusicSheetReader.doCalculationsAfterDurationHasBeenSet(instrumentReaders);
+                            this.currentMeasure.AbsoluteTimestamp = new Fraction(this.currentFraction);
+                            this.musicSheet.SheetErrors.TransferTempErrorsToDict(this.currentMeasure.MeasureNumber);
+                            this.currentFraction.Add(this.currentMeasure.Duration);
+                            this.previousMeasure = this.currentMeasure;
+                        }
+                    }
+                }
+            }
+            if (this.repetitionInstructionReader != null) {
+                this.repetitionInstructionReader.removeRedundantInstructions();
+                if (this.repetitionCalculator != null)
+                    this.repetitionCalculator.calculateRepetitions(this.musicSheet, this.repetitionInstructionReader.RepetitionInstructions);
+            }
+            this.musicSheet.checkForInstrumentWithNoVoice();
+            this.musicSheet.fillStaffList();
+            this.musicSheet.DefaultStartTempoInBpm = this.musicSheet.SheetPlaybackSetting.BeatsPerMinute;
+            for (var idx: number = 0, len = this.afterSheetReadingModules.Count; idx < len; ++idx) {
+                var afterSheetReadingModule: IAfterSheetReadingModule = this.afterSheetReadingModules[idx];
+                afterSheetReadingModule.calculate(this.musicSheet);
+            }
+        }
+        catch (e) {
+            Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheetReader._createMusicSheet", "", e);
+            return null;
+        }
+
+        return this.musicSheet;
+    }
+    private initializeReading(partList: IEnumerable<IXmlElement>, partInst: IEnumerable<IXmlElement>,
+        instrumentReaders: List<InstrumentReader>): void {
+        var instrumentDict: Dictionary<string, Instrument> = this.createInstrumentGroups(partList);
+        this.completeNumberOfStaves = this.getCompleteNumberOfStavesFromXml(partInst);
+        if (partInst.Any()) {
+            this.repetitionInstructionReader.MusicSheet = this.musicSheet;
+            this.currentFraction = new Fraction(0, 1);
+            this.currentMeasure = null;
+            this.previousMeasure = null;
+        }
+        var counter: number = 0;
+        var partInstArr: IXmlElement[] = partInst.ToArray();
+        for (var idx: number = 0, len = partInstArr.length; idx < len; ++idx) {
+            var node: IXmlElement = partInstArr[idx];
+            if (node.Attribute("id") != null) {
+                var idNode: IXmlAttribute = node.Attribute("id");
+                if (idNode != null) {
+                    var partInstId: string = idNode.Value;
+                    var currentInstrument: Instrument = instrumentDict[partInstId];
+                    var xmlMeasureList: IEnumerable<IXmlElement> = node.Elements("measure");
+                    var instrumentNumberOfStaves: number = 1;
+                    try {
+                        instrumentNumberOfStaves = this.getInstrumentNumberOfStavesFromXml(node);
+                    }
+                    catch (err) {
+                        var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/InstrumentStavesNumberError",
+                            "Invalid number of staves at instrument: ");
+                        this.musicSheet.SheetErrors.Errors.Add(errorMsg + currentInstrument.Name);
+                        continue;
+                    }
+
+                    currentInstrument.createStaves(instrumentNumberOfStaves);
+                    var instrumentReader: InstrumentReader = new InstrumentReader(this.repetitionInstructionReader, xmlMeasureList, currentInstrument);
+                    instrumentReaders.Add(instrumentReader);
+                    if (this.repetitionInstructionReader != null)
+                        this.repetitionInstructionReader.XmlMeasureList[counter] = xmlMeasureList.ToArray();
+                    counter++;
+                }
+            }
+        }
+    }
+    private checkIfRhythmInstructionsAreSetAndEqual(instrumentReaders: List<InstrumentReader>): void {
+        var rhythmInstructions: List<RhythmInstruction> = new List<RhythmInstruction>();
+        for (var i: number = 0; i < this.completeNumberOfStaves; i++) {
+            if (this.currentMeasure.FirstInstructionsStaffEntries[i] != null && this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.Last() instanceof RhythmInstruction)
+                rhythmInstructions.Add(<RhythmInstruction>this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.Last());
+        }
+        var maxRhythmValue: number = 0.0f;
+        var index: number = -1;
+        for (var idx: number = 0, len = rhythmInstructions.Count; idx < len; ++idx) {
+            var rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
+            if (rhythmInstruction.Rhythm.RealValue > maxRhythmValue) {
+                if (this.areRhythmInstructionsMixed(rhythmInstructions) && rhythmInstruction.SymbolEnum != RhythmSymbolEnum.NONE)
+                    continue;
+                maxRhythmValue = rhythmInstruction.Rhythm.RealValue;
+                index = rhythmInstructions.IndexOf(rhythmInstruction);
+            }
+        }
+        if (rhythmInstructions.Count > 0 && rhythmInstructions.Count < this.completeNumberOfStaves) {
+            var rhythmInstruction: RhythmInstruction = new RhythmInstruction(rhythmInstructions[index]);
+            for (var i: number = 0; i < this.completeNumberOfStaves; i++) {
+                if (this.currentMeasure.FirstInstructionsStaffEntries[i] != null && !(this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.Last() instanceof RhythmInstruction)) {
+                    this.currentMeasure.FirstInstructionsStaffEntries[i].removeAllInstructionsOfType<RhythmInstruction>();
+                    this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.Add(new RhythmInstruction(rhythmInstruction));
+                }
+                if (this.currentMeasure.FirstInstructionsStaffEntries[i] == null) {
+                    this.currentMeasure.FirstInstructionsStaffEntries[i] = new SourceStaffEntry(null, null);
+                    this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.Add(new RhythmInstruction(rhythmInstruction));
+                }
+            }
+            for (var idx: number = 0, len = instrumentReaders.Count; idx < len; ++idx) {
+                var instrumentReader: InstrumentReader = instrumentReaders[idx];
+                instrumentReader.ActiveRhythm = rhythmInstruction;
+            }
+        }
+        if (rhythmInstructions.Count == 0 && this.currentMeasure == this.musicSheet.SourceMeasures[0]) {
+            var rhythmInstruction: RhythmInstruction = new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE);
+            for (var i: number = 0; i < this.completeNumberOfStaves; i++) {
+                if (this.currentMeasure.FirstInstructionsStaffEntries[i] == null)
+                    this.currentMeasure.FirstInstructionsStaffEntries[i] = new SourceStaffEntry(null, null);
+                else this.currentMeasure.FirstInstructionsStaffEntries[i].removeAllInstructionsOfType<RhythmInstruction>();
+                this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.Add(rhythmInstruction);
+            }
+            for (var idx: number = 0, len = instrumentReaders.Count; idx < len; ++idx) {
+                var instrumentReader: InstrumentReader = instrumentReaders[idx];
+                instrumentReader.ActiveRhythm = rhythmInstruction;
+            }
+        }
+        for (var idx: number = 0, len = rhythmInstructions.Count; idx < len; ++idx) {
+            var rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
+            if (rhythmInstruction.Rhythm.RealValue < maxRhythmValue) {
+                if (this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.IndexOf(rhythmInstruction)].Instructions.Last() instanceof RhythmInstruction) {
+                    var rhythm: RhythmInstruction = new RhythmInstruction(rhythmInstructions[index]);
+                    this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.IndexOf(rhythmInstruction)].Instructions.RemoveAt(this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.IndexOf(rhythmInstruction)].Instructions.Count - 1);
+                    this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.IndexOf(rhythmInstruction)].Instructions.Add(rhythm);
+                }
+            }
+            if (Math.Abs(rhythmInstruction.Rhythm.RealValue - maxRhythmValue) < 0.000001f && rhythmInstruction.SymbolEnum != RhythmSymbolEnum.NONE && this.areRhythmInstructionsMixed(rhythmInstructions))
+            {
+                rhythmInstruction.SymbolEnum = RhythmSymbolEnum.NONE;
+            }
+        }
+    }
+    private areRhythmInstructionsMixed(rhythmInstructions: List<RhythmInstruction>): boolean {
+        for (var i: number = 1; i < rhythmInstructions.Count; i++) {
+            if (Math.Abs(rhythmInstructions[i].Rhythm.RealValue - rhythmInstructions[0].Rhythm.RealValue) < 0.000001f && rhythmInstructions[i].SymbolEnum != rhythmInstructions[0].SymbolEnum)
+            return true;
+        }
+        return false;
+    }
+    private setSourceMeasureDuration(instrumentReaders: List<InstrumentReader>, sourceMeasureCounter: number): void {
+        var activeRhythm: Fraction = new Fraction(0, 1);
+        var instrumentsMaxTieNoteFractions: List<Fraction> = new List<Fraction>();
+        for (var idx: number = 0, len = instrumentReaders.Count; idx < len; ++idx) {
+            var instrumentReader: InstrumentReader = instrumentReaders[idx];
+            instrumentsMaxTieNoteFractions.Add(instrumentReader.MaxTieNoteFraction);
+            var activeRythmMeasure: Fraction = instrumentReader.ActiveRhythm.Rhythm;
+            if (activeRhythm < activeRythmMeasure)
+                activeRhythm = new Fraction(activeRythmMeasure.Numerator, activeRythmMeasure.Denominator, false);
+        }
+        var instrumentsDurations: List<Fraction> = this.currentMeasure.calculateInstrumentsDuration(this.musicSheet, instrumentsMaxTieNoteFractions);
+        var maxInstrumentDuration: Fraction = new Fraction(0, 1);
+        for (var idx: number = 0, len = instrumentsDurations.Count; idx < len; ++idx) {
+            var instrumentsDuration: Fraction = instrumentsDurations[idx];
+            if (maxInstrumentDuration < instrumentsDuration)
+                maxInstrumentDuration = instrumentsDuration;
+        }
+        if (maxInstrumentDuration == activeRhythm) {
+            this.checkFractionsForEquivalence(maxInstrumentDuration, activeRhythm);
+        }
+        else {
+            if (maxInstrumentDuration < activeRhythm) {
+                maxInstrumentDuration = this.currentMeasure.reverseCheck(this.musicSheet, maxInstrumentDuration);
+                this.checkFractionsForEquivalence(maxInstrumentDuration, activeRhythm);
+            }
+        }
+        this.currentMeasure.ImplicitMeasure = this.checkIfMeasureIsImplicit(maxInstrumentDuration, activeRhythm);
+        if (!this.currentMeasure.ImplicitMeasure)
+            sourceMeasureCounter++;
+        this.currentMeasure.Duration = maxInstrumentDuration;
+        this.currentMeasure.MeasureNumber = sourceMeasureCounter;
+        for (var i: number = 0; i < instrumentsDurations.Count; i++) {
+            var instrumentsDuration: Fraction = instrumentsDurations[i];
+            if ((this.currentMeasure.ImplicitMeasure && instrumentsDuration != maxInstrumentDuration) || instrumentsDuration != activeRhythm && !this.allInstrumentsHaveSameDuration(instrumentsDurations, maxInstrumentDuration)) {
+                var firstStaffIndexOfInstrument: number = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.musicSheet.Instruments[i]);
+                for (var staffIndex: number = 0; staffIndex < this.musicSheet.Instruments[i].Staves.Count; staffIndex++) {
+                    if (!this.staffMeasureIsEmpty(firstStaffIndexOfInstrument + staffIndex)) {
+                        this.currentMeasure.setErrorInStaffMeasure(firstStaffIndexOfInstrument + staffIndex, true);
+                        var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MissingNotesError", "Given Notes don't correspond to measure duration.");
+                        this.musicSheet.SheetErrors.AddErrorMessageInTempList(errorMsg);
+                    }
+                }
+            }
+        }
+    }
+    private checkFractionsForEquivalence(maxInstrumentDuration: Fraction, activeRhythm: Fraction): void {
+        if (activeRhythm.Denominator > maxInstrumentDuration.Denominator) {
+            var factor: number = activeRhythm.Denominator / maxInstrumentDuration.Denominator;
+            maxInstrumentDuration.multiplyWithFactor(factor);
+        }
+    }
+    private checkIfMeasureIsImplicit(maxInstrumentDuration: Fraction, activeRhythm: Fraction): boolean {
+        if (this.previousMeasure == null && maxInstrumentDuration < activeRhythm)
+            return true;
+        if (this.previousMeasure != null)
+            return (this.previousMeasure.Duration + maxInstrumentDuration == activeRhythm);
+        return false;
+    }
+    private allInstrumentsHaveSameDuration(instrumentsDurations: List<Fraction>, maxInstrumentDuration: Fraction): boolean {
+        var counter: number = 0;
+        for (var idx: number = 0, len = instrumentsDurations.Count; idx < len; ++idx) {
+            var instrumentsDuration: Fraction = instrumentsDurations[idx];
+            if (instrumentsDuration == maxInstrumentDuration)
+                counter++;
+        }
+        if (counter == instrumentsDurations.Count && maxInstrumentDuration != new Fraction(0, 1))
+            return true;
+        return false;
+    }
+    private staffMeasureIsEmpty(index: number): boolean {
+        var counter: number = 0;
+        for (var i: number = 0; i < this.currentMeasure.VerticalSourceStaffEntryContainers.Count; i++)
+            if (this.currentMeasure.VerticalSourceStaffEntryContainers[i][index] == null)
+                counter++;
+        if (counter == this.currentMeasure.VerticalSourceStaffEntryContainers.Count)
+            return true;
+        return false;
+    }
+    private checkSourceMeasureForNullEntries(): void {
+        for (var i: number = this.currentMeasure.VerticalSourceStaffEntryContainers.Count - 1; i >= 0; i--) {
+            for (var j: number = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.Count - 1; j >= 0; j--) {
+                var sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[j];
+                if (sourceStaffEntry != null) {
+                    for (var k: number = sourceStaffEntry.VoiceEntries.Count - 1; k >= 0; k--) {
+                        var voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[k];
+                        if (voiceEntry.Notes.Count == 0) {
+                            voiceEntry.ParentVoice.VoiceEntries.Remove(voiceEntry);
+                            sourceStaffEntry.VoiceEntries.Remove(voiceEntry);
+                        }
+                    }
+                }
+                if (sourceStaffEntry != null && sourceStaffEntry.VoiceEntries.Count == 0)
+                    this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[j] = null;
+            }
+        }
+        for (var i: number = this.currentMeasure.VerticalSourceStaffEntryContainers.Count - 1; i >= 0; i--) {
+            var counter: number = 0;
+            for (var idx: number = 0, len = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.Count; idx < len; ++idx) {
+                var sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[idx];
+                if (sourceStaffEntry == null)
+                    counter++;
+            }
+            if (counter == this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.Count)
+                this.currentMeasure.VerticalSourceStaffEntryContainers.Remove(this.currentMeasure.VerticalSourceStaffEntryContainers[i]);
+        }
+    }
+    private addSheetLabels(root: IXmlElement, filePath: string): void {
+        this.readComposer(root);
+        this.readTitle(root);
+        if (this.musicSheet.Title == null || this.musicSheet.Composer == null)
+            this.readTitleAndComposerFromCredits(root);
+        if (this.musicSheet.Title == null) {
+            try {
+                var filename: string = (filePath.Split('/', '\\')).Last();
+                var filenameSplits: string[] = filename.Split('.');
+                this.musicSheet.Title = new Label(filenameSplits.First());
+            }
+            catch (ex) {
+                Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheetReader.addSheetLabels: ", ex);
+            }
+
+        }
+    }
+    private readComposer(root: IXmlElement): void {
+        var identificationNode: IXmlElement = root.Element("identification");
+        if (identificationNode != null) {
+            var creators: IXmlElement[] = identificationNode.Elements("creator").ToArray();
+            for (var idx: number = 0, len = creators.length; idx < len; ++idx) {
+                var creator: IXmlElement = creators[idx];
+                if (creator.HasAttributes) {
+                    if ((from n in creator.Attributes() where n.Value == "composer" select n).Any())
+                    {
+                        this.musicSheet.Composer = new Label(creator.Value.Trim('\n', '\r'));
+                        continue;
+                    }
+                    if ((from n in creator.Attributes() where n.Value == "lyricist" || n.Value == "poet" select n).Any())
+                    this.musicSheet.Lyricist = new Label(creator.Value.Trim('\n', '\r'));
+                }
+            }
+        }
+    }
+    private readTitleAndComposerFromCredits(root: IXmlElement): void {
+        var systemYCoordinates: number = this.computeSystemYCoordinates(root);
+        if (systemYCoordinates == 0)
+            return
+        var largestTitleCreditSize: number = 1;
+        var finalTitle: string = null;
+        var largestCreditYInfo: number = 0;
+        var finalSubtitle: string = null;
+        var possibleTitle: string = null;
+        var creditElements: IXmlElement[] = root.Elements("credit").ToArray();
+        for (var idx: number = 0, len = creditElements.length; idx < len; ++idx) {
+            var credit: IXmlElement = creditElements[idx];
+            if (credit.Attribute("page") == null)
+                return
+            if (credit.Attribute("page").Value == "1") {
+                var creditChild: IXmlElement = null;
+                if (credit != null) {
+                    creditChild = credit.Element("credit-words");
+                    if (creditChild.Attribute("justify") == null) {
+                        break;
+                    }
+                    var creditJustify: string = creditChild.Attribute("justify").Value;
+                    var creditY: string = creditChild.Attribute("default-y").Value;
+                    var creditYInfo: number = StringToNumberConverter.ToNumber(creditY);
+                    if (creditYInfo > systemYCoordinates) {
+                        if (this.musicSheet.Title == null) {
+                            var creditSize: string = creditChild.Attribute("font-size").Value;
+                            var titleCreditSizeInt: number = StringToNumberConverter.ToNumber(creditSize);
+                            if (largestTitleCreditSize < titleCreditSizeInt) {
+                                largestTitleCreditSize = titleCreditSizeInt;
+                                finalTitle = creditChild.Value;
+                            }
+                        }
+                        if (this.musicSheet.Subtitle == null) {
+                            if (creditJustify != "right" && creditJustify != "left") {
+                                if (largestCreditYInfo < creditYInfo) {
+                                    largestCreditYInfo = creditYInfo;
+                                    if (!String.IsNullOrEmpty(possibleTitle)) {
+                                        finalSubtitle = possibleTitle;
+                                        possibleTitle = creditChild.Value;
+                                    }
+                                    else {
+                                        possibleTitle = creditChild.Value;
+                                    }
+                                }
+                            }
+                        }
+                        if (!(this.musicSheet.Composer != null && this.musicSheet.Lyricist != null)) {
+                            switch (creditJustify) {
+                                case "right":
+                                    this.musicSheet.Composer = new Label(creditChild.Value.Trim('\n', '\r'));
+                                    break;
+                                case "left":
+                                    this.musicSheet.Lyricist = new Label(creditChild.Value.Trim('\n', '\r'));
+                                    break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (this.musicSheet.Title == null && !String.IsNullOrEmpty(finalTitle)) {
+            this.musicSheet.Title = new Label(finalTitle.Trim('\n', '\r'));
+        }
+        if (this.musicSheet.Subtitle == null && !String.IsNullOrEmpty(finalSubtitle)) {
+            this.musicSheet.Subtitle = new Label(finalSubtitle.Trim('\n', '\r'));
+        }
+    }
+    private computeSystemYCoordinates(root: IXmlElement): number {
+        if (root.Element("defaults") == null)
+            return 0;
+        var paperHeight: number = 0;
+        var topSystemDistance: number = 0;
+        var defi: string = root.Element("defaults").Element("page-layout").Element("page-height").Value;
+        paperHeight = StringToNumberConverter.ToNumber(defi);
+        var found: boolean = false;
+        var parts: IXmlElement[] = root.Elements("part").ToArray();
+        for (var idx: number = 0, len = parts.length; idx < len; ++idx) {
+            var measures: IXmlElement[] = parts[idx].Elements("measure").ToArray();
+            for (var idx2: number = 0, len2 = measures.length; idx2 < len2; ++idx2) {
+                var measure: IXmlElement = measures[idx2];
+                if (measure.Element("print") != null) {
+                    var systemLayouts: IXmlElement[] = measure.Element("print").Elements("system-layout").ToArray();
+                    for (var idx3: number = 0, len3 = systemLayouts.length; idx3 < len3; ++idx3) {
+                        var syslab: IXmlElement = systemLayouts[idx3];
+                        if (syslab.Element("top-system-distance") != null) {
+                            var topSystemDistanceString: string = syslab.Element("top-system-distance").Value;
+                            topSystemDistance = StringToNumberConverter.ToNumber(topSystemDistanceString);
+                            found = true;
+                            break;
+                        }
+                    }
+                    break;
+                }
+            }
+            if (found == true)
+                break;
+        }
+        if (root.Element("defaults").Element("system-layout") != null) {
+            var syslay: IXmlElement = root.Element("defaults").Element("system-layout");
+            if (syslay.Element("top-system-distance") != null) {
+                var topSystemDistanceString: string = root.Element("defaults").Element("system-layout").Element("top-system-distance").Value;
+                topSystemDistance = StringToNumberConverter.ToNumber(topSystemDistanceString);
+            }
+        }
+        if (topSystemDistance == 0)
+            return 0;
+        return paperHeight - topSystemDistance;
+    }
+    private readTitle(root: IXmlElement): void {
+        var titleNode: IXmlElement = root.Element("work");
+        var titleNodeChild: IXmlElement = null;
+        if (titleNode != null) {
+            titleNodeChild = titleNode.Element("work-title");
+            if (titleNodeChild != null && !String.IsNullOrEmpty(titleNodeChild.Value)) {
+                this.musicSheet.Title = new Label(titleNodeChild.Value.Trim('\n', '\r'));
+            }
+        }
+        var movementNode: IXmlElement = root.Element("movement-title");
+        var finalSubTitle: string = "";
+        if (movementNode != null) {
+            if (this.musicSheet.Title == null) {
+                this.musicSheet.Title = new Label(movementNode.Value.Trim('\n', '\r'));
+            }
+            else {
+                finalSubTitle = movementNode.Value.Trim('\n', '\r');
+            }
+        }
+        if (titleNode != null) {
+            var subtitleNodeChild: IXmlElement = titleNode.Element("work-number");
+            if (subtitleNodeChild != null) {
+                var workNumber: string = subtitleNodeChild.Value;
+                if (!String.IsNullOrEmpty(workNumber)) {
+                    if (String.IsNullOrEmpty(finalSubTitle)) {
+                        finalSubTitle = workNumber;
+                    }
+                    else {
+                        finalSubTitle = finalSubTitle + ", " + workNumber;
+                    }
+                }
+            }
+        }
+        if (!String.IsNullOrEmpty(finalSubTitle))
+            this.musicSheet.Subtitle = new Label(finalSubTitle);
+    }
+    private createInstrumentGroups(entryList: IEnumerable<IXmlElement>): Dictionary<string, Instrument> {
+        var instrumentId: number = 0;
+        var instrumentDict: Dictionary<string, Instrument> = new Dictionary<string, Instrument>();
+        var currentGroup: InstrumentalGroup = null;
+        try {
+            var entryArray: IXmlElement[] = entryList.ToArray();
+            for (var idx: number = 0, len = entryArray.length; idx < len; ++idx) {
+                var node: IXmlElement = entryArray[idx];
+                if (node.Name == "score-part") {
+                    var instrIdString: string = node.Attribute("id").Value;
+                    var instrument: Instrument = new Instrument(instrumentId, instrIdString, this.phonicScoreInterface, this.musicSheet, currentGroup);
+                    instrumentId++;
+                    var partElements: IXmlElement[] = node.Elements().ToArray();
+                    for (var idx2: number = 0, len2 = partElements.length; idx2 < len2; ++idx2) {
+                        var partElement: IXmlElement = partElements[idx2];
+                        try {
+                            if (partElement.Name == "part-name") {
+                                instrument.Name = partElement.Value;
+                            }
+                            else if (partElement.Name == "score-instrument") {
+                                var subInstrument: SubInstrument = new SubInstrument(instrument);
+                                subInstrument.IdString = partElement.FirstAttribute.Value;
+                                instrument.SubInstruments.Add(subInstrument);
+                                var subElement: IXmlElement = partElement.Element("instrument-name");
+                                if (subElement != null) {
+                                    subInstrument.Name = subElement.Value;
+                                    subInstrument.setMidiInstrument(subElement.Value);
+                                }
+                            }
+                            else if (partElement.Name == "midi-instrument") {
+                                var subInstrument: SubInstrument = instrument.getSubInstrument(partElement.FirstAttribute.Value);
+                                for (var idx3: number = 0, len3 = instrument.SubInstruments.Count; idx3 < len3; ++idx3) {
+                                    var subInstr: SubInstrument = instrument.SubInstruments[idx3];
+                                    if (subInstr.IdString == partElement.Value) {
+                                        subInstrument = subInstr;
+                                        break;
+                                    }
+                                }
+                                var instrumentElements: IXmlElement[] = partElement.Elements().ToArray();
+                                for (var idx3: number = 0, len3 = instrumentElements.length; idx3 < len3; ++idx3) {
+                                    var instrumentElement: IXmlElement = instrumentElements[idx3];
+                                    try {
+                                        if (instrumentElement.Name == "midi-channel") {
+                                            if (StringToNumberConverter.ToInteger(instrumentElement.Value) == 10)
+                                                instrument.MidiInstrumentId = MidiInstrument.Percussion;
+                                        }
+                                        else if (instrumentElement.Name == "midi-program") {
+                                            if (instrument.SubInstruments.Count > 0 && instrument.MidiInstrumentId != MidiInstrument.Percussion)
+                                                subInstrument.MidiInstrumentId = <MidiInstrument>Math.Max(0, StringToNumberConverter.ToInteger(instrumentElement.Value) - 1);
+                                        }
+                                        else if (instrumentElement.Name == "midi-unpitched") {
+                                            subInstrument.FixedKey = Math.Max(0, StringToNumberConverter.ToInteger(instrumentElement.Value));
+                                        }
+                                        else if (instrumentElement.Name == "volume") {
+                                            try {
+                                                var result: number = <number>StringToNumberConverter.ToNumber(instrumentElement.Value);
+                                                subInstrument.Volume = result / 127.0f;
+                                            }
+                                            catch (ex) {
+                                                Logger.DefaultLogger.LogError(LogLevel.DEBUG, "ExpressionReader.readExpressionParameters", "read volume", ex);
+                                            }
+
+                                        }
+                                        else if (instrumentElement.Name == "pan") {
+                                            try {
+                                                var result: number = <number>StringToNumberConverter.ToNumber(instrumentElement.Value);
+                                                subInstrument.Pan = result / 64.0f;
+                                            }
+                                            catch (ex) {
+                                                Logger.DefaultLogger.LogError(LogLevel.DEBUG, "ExpressionReader.readExpressionParameters", "read pan", ex);
+                                            }
+
+                                        }
+                                    }
+                                    catch (ex) {
+                                        Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheetReader.createInstrumentGroups midi settings: ", ex);
+                                    }
+
+                                }
+                            }
+                        }
+                        catch (ex) {
+                            Logger.DefaultLogger.LogError(LogLevel.NORMAL, "MusicSheetReader.createInstrumentGroups: ", ex);
+                        }
+
+                    }
+                    if (instrument.SubInstruments.Count == 0) {
+                        var subInstrument: SubInstrument = new SubInstrument(instrument);
+                        instrument.SubInstruments.Add(subInstrument);
+                    }
+                    instrumentDict.Add(instrIdString, instrument);
+                    if (currentGroup != null) {
+                        currentGroup.InstrumentalGroups.Add(instrument);
+                        this.musicSheet.Instruments.Add(instrument);
+                    }
+                    else {
+                        this.musicSheet.InstrumentalGroups.Add(instrument);
+                        this.musicSheet.Instruments.Add(instrument);
+                    }
+                }
+                else {
+                    if ((node.Name == "part-group") && (node.Attribute("type").Value == "start")) {
+                        var iG: InstrumentalGroup = new InstrumentalGroup("group", this.musicSheet, currentGroup);
+                        if (currentGroup != null)
+                            currentGroup.InstrumentalGroups.Add(iG);
+                        else this.musicSheet.InstrumentalGroups.Add(iG);
+                        currentGroup = iG;
+                    }
+                    else {
+                        if ((node.Name == "part-group") && (node.Attribute("type").Value == "stop")) {
+                            if (currentGroup != null) {
+                                if (currentGroup.InstrumentalGroups.Count == 1) {
+                                    var instr: InstrumentalGroup = currentGroup.InstrumentalGroups[0];
+                                    if (currentGroup.Parent != null) {
+                                        currentGroup.Parent.InstrumentalGroups.Add(instr);
+                                        currentGroup.Parent.InstrumentalGroups.Remove(currentGroup);
+                                    }
+                                    else {
+                                        this.musicSheet.InstrumentalGroups.Add(instr);
+                                        this.musicSheet.InstrumentalGroups.Remove(currentGroup);
+                                    }
+                                }
+                                currentGroup = currentGroup.Parent;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        catch (e) {
+            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/InstrumentError", "Error while reading Instruments");
+            throw new MusicSheetReadingException(errorMsg, e, 0);
+        }
+
+        for (var idx: number = 0, len = this.musicSheet.Instruments.Count; idx < len; ++idx) {
+            var instrument: Instrument = this.musicSheet.Instruments[idx];
+            if (string.IsNullOrEmpty(instrument.Name)) {
+                instrument.Name = "Instr. " + instrument.IdString;
+            }
+        }
+        return instrumentDict;
+    }
+    private getCompleteNumberOfStavesFromXml(partInst: IEnumerable<IXmlElement>): number {
+        var number: number = 0;
+        var partInstArr: IXmlElement[] = partInst.ToArray();
+        for (var idx: number = 0, len = partInstArr.length; idx < len; ++idx) {
+            var partNode: IXmlElement = partInstArr[idx];
+            var xmlMeasureList: IEnumerable<IXmlElement> = partNode.Elements("measure");
+            if (xmlMeasureList != null) {
+                var xmlMeasure: IXmlElement = xmlMeasureList.First();
+                if (xmlMeasure != null) {
+                    var stavesNode: IXmlElement = xmlMeasure.Element("attributes");
+                    if (stavesNode != null)
+                        stavesNode = stavesNode.Element("staves");
+                    if (stavesNode == null)
+                        number++;
+                    else {
+                        number += StringToNumberConverter.ToInteger(stavesNode.Value);
+                    }
+                }
+            }
+        }
+        if (number <= 0) {
+            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/StaffError", "Invalid number of staves.");
+            throw new MusicSheetReadingException(errorMsg);
+        }
+        return number;
+    }
+    private getInstrumentNumberOfStavesFromXml(partNode: IXmlElement): number {
+        var number: number = 0;
+        var xmlMeasure: IXmlElement = partNode.Element("measure");
+        if (xmlMeasure != null) {
+            var attributes: IXmlElement = xmlMeasure.Element("attributes");
+            var staves: IXmlElement = null;
+            if (attributes != null)
+                staves = attributes.Element("staves");
+            if (attributes == null || staves == null)
+                number = 1;
+            else {
+                number = StringToNumberConverter.ToInteger(staves.Value);
+            }
+        }
+        if (number <= 0) {
+            var errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/StaffError", "Invalid number of Staves.");
+            throw new MusicSheetReadingException(errorMsg);
+        }
+        return number;
+    }
+}

+ 1 - 0
src/MusicalScore/ScoreIO/VoiceGenerator.ts

@@ -0,0 +1 @@
+//TODO

+ 110 - 0
src/MusicalScore/SubInstrument.ts

@@ -0,0 +1,110 @@
+export class SubInstrument {
+    constructor(parentInstrument: Instrument) {
+        this.parentInstrument = parentInstrument;
+        this.FixedKey = -1;
+        this.MidiInstrumentId = parseMidiInstrument(this.parentInstrument.Name);
+        this.Name = this.MidiInstrumentId.ToString();
+        this.Volume = 1f;
+    }
+    private static midiInstrument: Dictionary<string, MidiInstrument> = __init(new Dictionary<string, MidiInstrument>(), { { "cello",MidiInstrument.Cello },
+        { "violon-c",MidiInstrument.Cello },
+        { "contrabass",MidiInstrument.Contrabass },
+        { "kontrabass",MidiInstrument.Contrabass },
+        { "clarinet",MidiInstrument.Clarinet },
+        { "klarinette",MidiInstrument.Clarinet },
+        { "flute",MidiInstrument.Flute },
+        { "flöte",MidiInstrument.Flute },
+        { "frenchhorn",MidiInstrument.French_Horn },
+        { "guitar",MidiInstrument.Acoustic_Guitar_nylon },
+        { "gitarre",MidiInstrument.Acoustic_Guitar_nylon },
+        { "harp",MidiInstrument.Orchestral_Harp },
+        { "harfe",MidiInstrument.Orchestral_Harp },
+        { "oboe",MidiInstrument.Oboe },
+        { "organ",MidiInstrument.Church_Organ },
+        { "orgue",MidiInstrument.Church_Organ },
+        { "orgel",MidiInstrument.Church_Organ },
+        { "piano",MidiInstrument.Acoustic_Grand_Piano },
+        { "klavier",MidiInstrument.Acoustic_Grand_Piano },
+        { "piccolo",MidiInstrument.Piccolo },
+        { "strings",MidiInstrument.String_Ensemble_1 },
+        { "streicher",MidiInstrument.String_Ensemble_1 },
+        { "steeldrum",MidiInstrument.Steel_Drums },
+        { "trombone",MidiInstrument.Trombone },
+        { "posaune",MidiInstrument.Trombone },
+        { "brass",MidiInstrument.Trombone },
+        { "trumpet",MidiInstrument.Trumpet },
+        { "trompete",MidiInstrument.Trumpet },
+        { "tpt",MidiInstrument.Trumpet },
+        { "tuba",MidiInstrument.Tuba },
+        { "sax",MidiInstrument.Tenor_Sax },
+        { "viola",MidiInstrument.Viola },
+        { "bratsche",MidiInstrument.Viola },
+        { "violin",MidiInstrument.Violin },
+        { "violon.",MidiInstrument.Violin },
+        { "woodblock",MidiInstrument.Woodblock },
+        { "alt",MidiInstrument.Synth_Voice },
+        { "alto",MidiInstrument.Synth_Voice },
+        { "tenor",MidiInstrument.Synth_Voice },
+        { "bariton",MidiInstrument.Synth_Voice },
+        { "baritone",MidiInstrument.Synth_Voice },
+        { "bass",MidiInstrument.Synth_Voice },
+        { "sopran",MidiInstrument.Synth_Voice },
+        { "voice",MidiInstrument.Synth_Voice },
+        { "recorder",MidiInstrument.Recorder },
+        { "blockflöte",MidiInstrument.Recorder },
+        { "banjo",MidiInstrument.Banjo },
+        { "drums",MidiInstrument.Percussion },
+        { "percussion",MidiInstrument.Percussion },
+        { "schlagzeug",MidiInstrument.Percussion },
+        { "schlagwerk",MidiInstrument.Percussion },
+        { "unnamed",MidiInstrument.Acoustic_Grand_Piano } });
+ public IdString: string;
+ public MidiInstrumentId: MidiInstrument;
+ public Volume: number;
+ public Pan: number;
+ public FixedKey: number;
+ public Name: string;
+private parentInstrument: Instrument;
+public get ParentInstrument(): Instrument
+{
+    return this.parentInstrument;
+}
+public static isPianoInstrument(instrument:MidiInstrument): boolean
+{
+    if (instrument == MidiInstrument.Acoustic_Grand_Piano || instrument == MidiInstrument.Bright_Acoustic_Piano || instrument == MidiInstrument.Electric_Grand_Piano || instrument == MidiInstrument.Electric_Piano_1 || instrument == MidiInstrument.Electric_Piano_2)
+        return true;
+    return false;
+}
+public setMidiInstrument(instrumentType:string): void
+    {
+        this.MidiInstrumentId = this.parseMidiInstrument(instrumentType);
+    }
+private parseMidiInstrument(instrumentType:string): MidiInstrument
+{
+    try {
+        if (!string.IsNullOrEmpty(instrumentType)) {
+            var tmpName: string = instrumentType.ToLower().Trim();
+            var midiInstrumentArr: KeyValuePair<string, MidiInstrument>[] = SubInstrument.midiInstrument.ToArray();
+            for (var idx: number = 0, len = midiInstrumentArr.length; idx < len; ++idx) {
+                var keyValuePair: KeyValuePair<string, MidiInstrument> = midiInstrumentArr[idx];
+                if (tmpName.Contains(keyValuePair.Key))
+                    return keyValuePair.Value;
+            }
+        }
+        if (!string.IsNullOrEmpty(this.parentInstrument.Name)) {
+            var tmpName: string = this.parentInstrument.Name.ToLower().Trim();
+            var midiInstrumentArr: KeyValuePair<string, MidiInstrument>[] = SubInstrument.midiInstrument.ToArray();
+            for (var idx: number = 0, len = midiInstrumentArr.length; idx < len; ++idx) {
+                var keyValuePair: KeyValuePair<string, MidiInstrument> = midiInstrumentArr[idx];
+                if (tmpName.Contains(keyValuePair.Key))
+                    return keyValuePair.Value;
+            }
+        }
+        return MidiInstrument.Acoustic_Grand_Piano;
+    }
+    catch (e) {
+        return MidiInstrument.Acoustic_Grand_Piano;
+    }
+
+} 
+                }

+ 39 - 0
src/MusicalScore/VoiceData/Beam.ts

@@ -0,0 +1,39 @@
+export class Beam {
+    constructor() {
+
+    }
+    private notes: List<Note> = new List<Note>();
+    private extendedNoteList: List<Note> = new List<Note>();
+    public get Notes(): List<Note> {
+        return this.notes;
+    }
+    public set Notes(value: List<Note>) {
+        this.notes = value;
+    }
+    public get ExtendedNoteList(): List<Note> {
+        return this.extendedNoteList;
+    }
+    public set ExtendedNoteList(value: List<Note>) {
+        this.extendedNoteList = value;
+    }
+    public addNoteToBeam(note: Note): void {
+        if (note != null) {
+            note.NoteBeam = this;
+            this.notes.Add(note);
+            this.extendedNoteList.Add(note);
+        }
+    }
+}
+export enum BeamEnum {
+    BeamNone = -1,
+
+    BeamBegin = 0,
+
+    BeamContinue = 1,
+
+    BeamEnd = 2,
+
+    BeamForward = 3,
+
+    BeamBackward = 4
+}

+ 30 - 0
src/MusicalScore/VoiceData/HelperObjects/DynamicsContainer.ts

@@ -0,0 +1,30 @@
+export class DynamicsContainer implements IComparable<DynamicsContainer>
+{
+    constructor(continuousDynamicExpression: ContinuousDynamicExpression, staffNumber: number) {
+        this.ContinuousDynamicExpression = continuousDynamicExpression;
+        this.StaffNumber = staffNumber;
+    }
+    constructor(instantaniousDynamicExpression: InstantaniousDynamicExpression, staffNumber: number) {
+        this.InstantaniousDynamicExpression = instantaniousDynamicExpression;
+        this.StaffNumber = staffNumber;
+    }
+    public ContinuousDynamicExpression: ContinuousDynamicExpression;
+    public InstantaniousDynamicExpression: InstantaniousDynamicExpression;
+    public StaffNumber: number;
+    public parMultiExpression(): MultiExpression {
+        if (this.ContinuousDynamicExpression != null)
+            return this.ContinuousDynamicExpression.StartMultiExpression;
+        if (this.InstantaniousDynamicExpression != null)
+            return this.InstantaniousDynamicExpression.ParentMultiExpression;
+        return null;
+    }
+    public CompareTo(other: DynamicsContainer): number {
+        var thisTimestamp: number = this.parMultiExpression().AbsoluteTimestamp.RealValue;
+        var otherTimestamp: number = other.parMultiExpression().AbsoluteTimestamp.RealValue;
+        if (thisTimestamp > otherTimestamp)
+            return 1;
+        if (thisTimestamp < otherTimestamp)
+            return -1;
+        return 0;
+    }
+}

+ 14 - 0
src/MusicalScore/VoiceData/Instructions/AbstractNotationInstruction.ts

@@ -0,0 +1,14 @@
+export class AbstractNotationInstruction {
+    constructor() {
+    }
+    constructor(parent: SourceStaffEntry) {
+        this.parent = parent;
+    }
+    protected parent: SourceStaffEntry;
+    public get Parent(): SourceStaffEntry {
+        return this.parent;
+    }
+    public set Parent(value: SourceStaffEntry) {
+        this.parent = value;
+    }
+}

+ 144 - 0
src/MusicalScore/VoiceData/Instructions/ClefInstruction.ts

@@ -0,0 +1,144 @@
+import {Pitch} from "../../../Common/DataObjects/pitch";
+
+export class ClefInstruction extends AbstractNotationInstruction {
+    constructor(clefType: ClefEnum, octaveOffset: number, line: number) {
+        this.line = line;
+        this.clefType = clefType;
+        this.octaveOffset = octaveOffset;
+        this.calcParameters();
+    }
+    private clefType: ClefEnum = ClefEnum.G;
+    private line: number = 2;
+    private octaveOffset: number = 0;
+    private clefPitch: Pitch;
+    private referenceCyPosition: number;
+    public get ClefType(): ClefEnum {
+        return this.clefType;
+    }
+    public set ClefType(value: ClefEnum) {
+        this.clefType = value;
+    }
+    public get Line(): number {
+        return this.line;
+    }
+    public set Line(value: number) {
+        this.line = value;
+    }
+    public get OctaveOffset(): number {
+        return this.octaveOffset;
+    }
+    public set OctaveOffset(value: number) {
+        this.octaveOffset = value;
+    }
+    public get ClefPitch(): Pitch {
+        return this.clefPitch;
+    }
+    public set ClefPitch(value: Pitch) {
+        this.clefPitch = value;
+    }
+    public get ReferenceCyPosition(): number {
+        return this.referenceCyPosition;
+    }
+    public set ReferenceCyPosition(value: number) {
+        this.referenceCyPosition = value;
+    }
+    public OperatorEquals(clef2: ClefInstruction): boolean {
+        var clef1 = this;
+        if (ReferenceEquals(clef1, clef2)) {
+            return true;
+        }
+        if ((<Object>clef1 == null) || (<Object>clef2 == null)) {
+            return false;
+        }
+        return (clef1.ClefPitch == clef2.ClefPitch && clef1.Line == clef2.Line);
+    }
+
+    public OperatorNotEqual(clef2: ClefInstruction): boolean {
+        var clef1 = this;
+        return !(clef1 == clef2);
+    }
+
+    public static getDefaultClefFromMidiInstrument(instrument: MidiInstrument): ClefInstruction {
+        switch (instrument) {
+            case MidiInstrument.Acoustic_Grand_Piano:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Electric_Bass_finger:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Electric_Bass_pick:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Fretless_Bass:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Slap_Bass_1:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Slap_Bass_2:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Synth_Bass_1:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Synth_Bass_2:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            case MidiInstrument.Contrabass:
+                return new ClefInstruction(ClefEnum.F, 0, 4);
+            default:
+                return new ClefInstruction(ClefEnum.G, 0, 2);
+        }
+    }
+    public static getAllPossibleClefs(): List<ClefInstruction> {
+        var clefList: List<ClefInstruction> = new List<ClefInstruction>();
+        for (var i: number = 0; i <= 2; i++) {
+            var clefInstructionG: ClefInstruction = new ClefInstruction(ClefEnum.G, i, 2);
+            clefList.Add(clefInstructionG);
+        }
+        for (var i: number = -2; i <= 0; i++) {
+            var clefInstructionF: ClefInstruction = new ClefInstruction(ClefEnum.F, i, 4);
+            clefList.Add(clefInstructionF);
+        }
+        return clefList;
+    }
+    public static isSupportedClef(clef: ClefEnum): boolean {
+        switch (clef) {
+            case ClefEnum.G:
+            case ClefEnum.F:
+            case ClefEnum.C:
+            case ClefEnum.percussion:
+                return true;
+            default:
+                return false;
+        }
+    }
+    public ToString(): string {
+        return "ClefType: " + this.clefType.ToString();
+    }
+    private calcParameters(): void {
+        switch (this.clefType) {
+            case ClefEnum.G:
+                this.clefPitch = new Pitch(NoteEnum.G, <number>(1 + this.octaveOffset), AccidentalEnum.NONE);
+                this.referenceCyPosition = (5 - this.line) + 2;
+                break;
+            case ClefEnum.F:
+                this.clefPitch = new Pitch(NoteEnum.F, <number>(0 + this.octaveOffset), AccidentalEnum.NONE);
+                this.referenceCyPosition = (5 - this.line) + 1.5f;
+                break;
+            case ClefEnum.C:
+                this.clefPitch = new Pitch(NoteEnum.C, <number>(1 + this.octaveOffset), AccidentalEnum.NONE);
+                this.referenceCyPosition = (5 - this.line);
+                break;
+            case ClefEnum.percussion:
+                this.clefPitch = new Pitch(NoteEnum.C, 2, AccidentalEnum.NONE);
+                this.referenceCyPosition = 2;
+                break;
+            default:
+                throw new ArgumentOutOfRangeException("clefType");
+        }
+    }
+}
+export enum ClefEnum {
+    G = 0,
+
+    F = 1,
+
+    C = 2,
+
+    percussion = 3,
+
+    TAB = 4
+}

+ 108 - 0
src/MusicalScore/VoiceData/Instructions/KeyInstruction.ts

@@ -0,0 +1,108 @@
+export class KeyInstruction extends AbstractNotationInstruction {
+    constructor(key: number, mode: KeyEnum) {
+        super();
+        this.Key = key;
+        this.mode = mode;
+    }
+    constructor(parent: SourceStaffEntry, key: number, mode: KeyEnum) {
+        super(parent);
+        this.Key = key;
+        this.mode = mode;
+    }
+    constructor(keyInstruction: KeyInstruction) {
+        this(keyInstruction.parent, keyInstruction.keyType, keyInstruction.mode);
+        this.keyType = keyInstruction.keyType;
+        this.mode = keyInstruction.mode;
+    }
+    private keyType: number;
+    private mode: KeyEnum;
+    private static sharpPositionList: NoteEnum[] = [NoteEnum.F, NoteEnum.C, NoteEnum.G, NoteEnum.D, NoteEnum.A, NoteEnum.E, NoteEnum.B];
+    private static flatPositionList: NoteEnum[] = [NoteEnum.B, NoteEnum.E, NoteEnum.A, NoteEnum.D, NoteEnum.G, NoteEnum.C, NoteEnum.F];
+    public static getAllPossibleMajorKeyInstructions(): List<KeyInstruction> {
+        var keyInstructionList: List<KeyInstruction> = new List<KeyInstruction>();
+        for (var keyType: number = -7; keyType < 7; keyType++) {
+            var currentKeyInstruction: KeyInstruction = new KeyInstruction(keyType, KeyEnum.major);
+            keyInstructionList.Add(currentKeyInstruction);
+        }
+        return keyInstructionList;
+    }
+    public get Key(): number {
+        return this.keyType;
+    }
+    public set Key(value: number) {
+        this.keyType = value;
+    }
+    public get Mode(): KeyEnum {
+        return this.mode;
+    }
+    public set Mode(value: KeyEnum) {
+        this.mode = value;
+    }
+    public getFundamentalNotesOfAccidentals(): List<NoteEnum> {
+        var noteList: List<NoteEnum> = new List<NoteEnum>();
+        if (this.keyType > 0) {
+            for (var i: number = 0; i < this.keyType; i++) {
+                noteList.Add(KeyInstruction.sharpPositionList[i]);
+            }
+        }
+        else if (this.keyType < 0) {
+            for (var i: number = 0; i < -this.keyType; i++) {
+                noteList.Add(KeyInstruction.flatPositionList[i]);
+            }
+        }
+        return noteList;
+    }
+    public getAlterationForPitch(pitch: Pitch): AccidentalEnum {
+        if (this.keyType > 0 && Array.IndexOf(KeyInstruction.sharpPositionList, pitch.FundamentalNote) <= this.keyType)
+            return AccidentalEnum.SHARP;
+        else if (this.keyType < 0 && Array.IndexOf(KeyInstruction.flatPositionList, pitch.FundamentalNote) <= Math.Abs(this.keyType))
+            return AccidentalEnum.FLAT;
+        return AccidentalEnum.NONE;
+    }
+    public ToString(): string {
+        return "Key: " + this.keyType.ToString() + this.mode.ToString();
+    }
+    public OperatorEquals(key2: KeyInstruction): boolean {
+        var key1 = this;
+        if (ReferenceEquals(key1, key2)) {
+            return true;
+        }
+        if ((<Object>key1 == null) || (<Object>key2 == null)) {
+            return false;
+        }
+        return (key1.Key == key2.Key && key1.Mode == key2.Mode);
+    }
+
+    public OperatorNotEqual(key2: KeyInstruction): boolean {
+        var key1 = this;
+        return !(key1 == key2);
+    }
+
+    public static getNoteEnumList(instruction: KeyInstruction): List<NoteEnum> {
+        var enums: List<NoteEnum> = new List<NoteEnum>();
+        if (instruction.keyType > 0)
+            for (var i: number = 0; i < instruction.keyType; i++)
+                enums.Add(KeyInstruction.sharpPositionList[i]);
+        if (instruction.keyType < 0)
+            for (var i: number = 0; i < Math.Abs(instruction.keyType); i++)
+                enums.Add(KeyInstruction.flatPositionList[i]);
+        return enums;
+    }
+}
+export enum KeyEnum {
+    major = 0,
+
+    minor = 1,
+
+    none = 2
+}
+export module KeyInstruction {
+    export class NoteEnumToHalfToneLink {
+        constructor(note: NoteEnum, halftone: number) {
+            this.note = note;
+            this.halfTone = halftone;
+        }
+        public note: NoteEnum;
+        public halfTone: number;
+    }
+}

+ 150 - 0
src/MusicalScore/VoiceData/Instructions/RepetitionInstruction.ts

@@ -0,0 +1,150 @@
+export enum RepetitionInstructionEnum {
+    StartLine,
+
+    ForwardJump,
+
+    BackJumpLine,
+
+    Ending,
+
+    DaCapo,
+
+    DalSegno,
+
+    Fine,
+
+    ToCoda,
+
+    DalSegnoAlFine,
+
+    DaCapoAlFine,
+
+    DalSegnoAlCoda,
+
+    DaCapoAlCoda,
+
+    Coda,
+
+    Segno,
+
+    None
+}
+export enum AlignmentType {
+    Begin,
+
+    End
+}
+export class RepetitionInstructionComparer implements IComparer<RepetitionInstruction>
+{
+    public Compare(x: RepetitionInstruction, y: RepetitionInstruction): number {
+        if (x.ParentRepetition != null && y.ParentRepetition != null) {
+            if (x.Alignment == AlignmentType.End && y.Alignment == AlignmentType.End) {
+                if (x.ParentRepetition.StartIndex < y.ParentRepetition.StartIndex)
+                    return 1;
+                if (x.ParentRepetition.StartIndex > y.ParentRepetition.StartIndex)
+                    return -1;
+            }
+            if (x.Alignment == AlignmentType.Begin && y.Alignment == AlignmentType.Begin) {
+                if (x.ParentRepetition.EndIndex < y.ParentRepetition.EndIndex)
+                    return 1;
+                if (x.ParentRepetition.EndIndex > y.ParentRepetition.EndIndex)
+                    return -1;
+            }
+        }
+        return 0;
+    }
+}
+export class RepetitionInstruction implements IComparable {
+    constructor(measureIndex: number, type: RepetitionInstructionEnum) {
+        this(measureIndex, new List<number>(), type, AlignmentType.End, null);
+        if (type == RepetitionInstructionEnum.StartLine || type == RepetitionInstructionEnum.Segno || type == RepetitionInstructionEnum.Coda)
+            this.Alignment = AlignmentType.Begin;
+    }
+    constructor(measureIndex: number, type: RepetitionInstructionEnum, alignment: AlignmentType, parentRepetition: Repetition) {
+        this(measureIndex, new List<number>(), type, alignment, parentRepetition);
+
+    }
+    constructor(measureIndex: number, endingIndex: number, type: RepetitionInstructionEnum, alignment: AlignmentType, parentRepetition: Repetition) {
+        this(measureIndex, __init(new List<number>(), { endingIndex }), type, alignment, parentRepetition);
+
+    }
+    constructor(measureIndex: number, endingIndices: List<number>, type: RepetitionInstructionEnum, alignment: AlignmentType, parentRepetition: Repetition) {
+        this.MeasureIndex = measureIndex;
+        this.EndingIndices = new List<number>();
+        for (var idx: number = 0, len = endingIndices.Count; idx < len; ++idx) {
+            var endingIndex: number = endingIndices[idx];
+            this.EndingIndices.Add(endingIndex);
+        }
+        this.Type = type;
+        this.Alignment = alignment;
+        this.ParentRepetition = parentRepetition;
+    }
+    public MeasureIndex: number;
+    public EndingIndices: List<number>;
+    public Type: RepetitionInstructionEnum;
+    public Alignment: AlignmentType;
+    public ParentRepetition: Repetition;
+    public CompareTo(obj: Object): number {
+        var other: RepetitionInstruction = <RepetitionInstruction>obj;
+        if (this.MeasureIndex > other.MeasureIndex)
+            return 1;
+        else if (this.MeasureIndex < other.MeasureIndex)
+            return -1;
+        if (this.Alignment == AlignmentType.Begin) {
+            if (other.Alignment == AlignmentType.End)
+                return -1;
+            switch (this.Type) {
+                case RepetitionInstructionEnum.Ending:
+                    return 1;
+                case RepetitionInstructionEnum.StartLine:
+                    if (other.Type == RepetitionInstructionEnum.Ending)
+                        return -1;
+                    return 1;
+                case RepetitionInstructionEnum.Coda:
+                case RepetitionInstructionEnum.Segno:
+                    if (other.Type == RepetitionInstructionEnum.Coda)
+                        return 1;
+                    return -1;
+            }
+        }
+        else {
+            if (other.Alignment == AlignmentType.Begin)
+                return 1;
+            switch (this.Type) {
+                case RepetitionInstructionEnum.Ending:
+                    return -1;
+                case RepetitionInstructionEnum.Fine:
+                case RepetitionInstructionEnum.ToCoda:
+                    if (other.Type == RepetitionInstructionEnum.Ending)
+                        return 1;
+                    return -1;
+                case RepetitionInstructionEnum.ForwardJump:
+                    switch (other.Type) {
+                        case RepetitionInstructionEnum.Ending:
+                        case RepetitionInstructionEnum.Fine:
+                        case RepetitionInstructionEnum.ToCoda:
+                            return 1;
+                    }
+                    return -1;
+                case RepetitionInstructionEnum.DalSegnoAlFine:
+                case RepetitionInstructionEnum.DaCapoAlFine:
+                case RepetitionInstructionEnum.DalSegnoAlCoda:
+                case RepetitionInstructionEnum.DaCapoAlCoda:
+                case RepetitionInstructionEnum.DaCapo:
+                case RepetitionInstructionEnum.DalSegno:
+                case RepetitionInstructionEnum.BackJumpLine:
+                    return 1;
+            }
+        }
+        return 0;
+    }
+    public isIdenticalTo(other: RepetitionInstruction): boolean {
+        if (this.MeasureIndex != other.MeasureIndex || this.Type != other.Type || this.Alignment != other.Alignment || this.EndingIndices.Count != other.EndingIndices.Count)
+            return false;
+        for (var i: number = 0; i < this.EndingIndices.Count; i++) {
+            if (this.EndingIndices[i] != other.EndingIndices[i])
+                return false;
+        }
+        return true;
+    }
+}

+ 58 - 0
src/MusicalScore/VoiceData/Instructions/RhythmInstruction.ts

@@ -0,0 +1,58 @@
+export class RhythmInstruction extends AbstractNotationInstruction {
+    constructor(rhythm: Fraction, numerator: number, denominator: number, rhythmSymbolEnum: RhythmSymbolEnum) {
+        super();
+        this.rhythm = rhythm;
+        this.numerator = numerator;
+        this.denominator = denominator;
+        this.symbolEnum = rhythmSymbolEnum;
+    }
+    constructor(rhythmInstruction: RhythmInstruction) {
+        super(rhythmInstruction.parent);
+        this.rhythm = rhythmInstruction.rhythm;
+        this.numerator = rhythmInstruction.numerator;
+        this.denominator = rhythmInstruction.denominator;
+        this.symbolEnum = rhythmInstruction.symbolEnum;
+    }
+    private numerator: number;
+    private denominator: number;
+    private rhythm: Fraction;
+    private symbolEnum: RhythmSymbolEnum;
+    public get Rhythm(): Fraction {
+        return this.rhythm;
+    }
+    public set Rhythm(value: Fraction) {
+        this.rhythm = value;
+    }
+    public get SymbolEnum(): RhythmSymbolEnum {
+        return this.symbolEnum;
+    }
+    public set SymbolEnum(value: RhythmSymbolEnum) {
+        this.symbolEnum = value;
+    }
+    public OperatorEquals(rhythm2: RhythmInstruction): boolean {
+        var rhythm1 = this;
+        if (ReferenceEquals(rhythm1, rhythm2)) {
+            return true;
+        }
+        if ((<Object>rhythm1 == null) || (<Object>rhythm2 == null)) {
+            return false;
+        }
+        return (rhythm1.numerator == rhythm2.numerator && rhythm1.denominator == rhythm2.denominator);
+    }
+
+    public OperatorNotEqual(rhythm2: RhythmInstruction): boolean {
+        var rhythm1 = this;
+        return !(rhythm1 == rhythm2);
+    }
+
+    public ToString(): string {
+        return "Rhythm: " + this.rhythm.ToString();
+    }
+}
+export enum RhythmSymbolEnum {
+    NONE = 0,
+
+    COMMON = 1,
+
+    CUT = 2
+}

+ 7 - 0
src/MusicalScore/VoiceData/Instructions/TechnicalInstruction.ts

@@ -0,0 +1,7 @@
+export enum TechnicalInstructionType {
+    Fingering
+}
+export class TechnicalInstruction {
+    public type: TechnicalInstructionType;
+    public value: string;
+}

+ 10 - 0
src/MusicalScore/VoiceData/LinkedVoice.ts

@@ -0,0 +1,10 @@
+export class LinkedVoice extends Voice {
+    constructor(parent: Instrument, voiceId: number, master: Voice) {
+        super(parent, voiceId);
+        this.master = master;
+    }
+    private master: Voice;
+    public get Master(): Voice {
+        return this.master;
+    }
+}

+ 27 - 0
src/MusicalScore/VoiceData/Lyrics/LyricsEntry.ts

@@ -0,0 +1,27 @@
+import {LyricWord} from "./LyricsWord";
+
+export class LyricsEntry {
+    constructor(text: string, word: LyricWord, parent: VoiceEntry) {
+        this._text = text;
+        this._word = word;
+        this._parent = parent;
+    }
+    private _text: string;
+    private _word: LyricWord;
+    private _parent: VoiceEntry;
+    public get Text(): string {
+        return this._text;
+    }
+    public set Text(value: string) {
+        this._text = value;
+    }
+    public get Word(): LyricWord {
+        return this._word;
+    }
+    public get Parent(): VoiceEntry {
+        return this._parent;
+    }
+    public set Parent(value: VoiceEntry) {
+        this._parent = value;
+    }
+}

+ 26 - 0
src/MusicalScore/VoiceData/Lyrics/LyricsWord.ts

@@ -0,0 +1,26 @@
+import {LyricsEntry} from "./LyricsEntry";
+
+export class LyricWord {
+    private _syllabels: Array<LyricsEntry> = new Array<LyricsEntry>();
+    public get Syllabels(): Array<LyricsEntry> {
+        return this._syllabels;
+    }
+    public containsVoiceEntry(voiceEntry: VoiceEntry): boolean {
+        for (let idx: number = 0, len: number = this.Syllabels.length; idx < len; ++idx) {
+            let lyricsEntry: LyricsEntry = this.Syllabels[idx];
+            if (lyricsEntry.Parent === voiceEntry) {
+                return true;
+            }
+        }
+        return false;
+    }
+    public findLyricEntryInVoiceEntry(voiceEntry: VoiceEntry): LyricsEntry {
+        for (let idx: number = 0, len: number = this.Syllabels.length; idx < len; ++idx) {
+            let lyricsEntry: LyricsEntry = this.Syllabels[idx];
+            if (lyricsEntry.Parent === voiceEntry) {
+                return lyricsEntry;
+            }
+        }
+        return undefined;
+    }
+}

+ 153 - 0
src/MusicalScore/VoiceData/Note.ts

@@ -0,0 +1,153 @@
+export class Note {
+    constructor(voiceEntry: VoiceEntry, parentStaffEntry: SourceStaffEntry, length: Fraction, pitch: Pitch) {
+        this.voiceEntry = voiceEntry;
+        this.parentStaffEntry = parentStaffEntry;
+        this.length = length;
+        this.pitch = pitch;
+        if (pitch != null)
+            this.HalfTone = pitch.getHalfTone();
+        else this.HalfTone = 0;
+    }
+    private voiceEntry: VoiceEntry;
+    private parentStaffEntry: SourceStaffEntry;
+    private length: Fraction;
+    private pitch: Pitch;
+    private beam: Beam;
+    private tuplet: Tuplet;
+    private tie: Tie;
+    private slurs: List<Slur> = new List<Slur>();
+    private graceNoteSlash: boolean = false;
+    private playbackInstrumentId: string = null;
+    public get GraceNoteSlash(): boolean {
+        return this.graceNoteSlash;
+    }
+    public set GraceNoteSlash(value: boolean) {
+        this.graceNoteSlash = value;
+    }
+    public get ParentVoiceEntry(): VoiceEntry {
+        return this.voiceEntry;
+    }
+    public set ParentVoiceEntry(value: VoiceEntry) {
+        this.voiceEntry = value;
+    }
+    public get ParentStaffEntry(): SourceStaffEntry {
+        return this.parentStaffEntry;
+    }
+    public get ParentStaff(): Staff {
+        return this.parentStaffEntry.ParentStaff;
+    }
+    public get Length(): Fraction {
+        return this.length;
+    }
+    public set Length(value: Fraction) {
+        this.length = value;
+    }
+    public get Pitch(): Pitch {
+        return this.pitch;
+    }
+    public HalfTone: number;
+    public get NoteBeam(): Beam {
+        return this.beam;
+    }
+    public set NoteBeam(value: Beam) {
+        this.beam = value;
+    }
+    public get NoteTuplet(): Tuplet {
+        return this.tuplet;
+    }
+    public set NoteTuplet(value: Tuplet) {
+        this.tuplet = value;
+    }
+    public get NoteTie(): Tie {
+        return this.tie;
+    }
+    public set NoteTie(value: Tie) {
+        this.tie = value;
+    }
+    public get NoteSlurs(): List<Slur> {
+        return this.slurs;
+    }
+    public set NoteSlurs(value: List<Slur>) {
+        this.slurs = value;
+    }
+    public State: NoteState;
+    public get PlaybackInstrumentId(): string {
+        return this.playbackInstrumentId;
+    }
+    public set PlaybackInstrumentId(value: string) {
+        this.playbackInstrumentId = value;
+    }
+    public calculateNoteLengthWithoutTie(): Fraction {
+        var withoutTieLength: Fraction = new Fraction(this.length);
+        if (this.tie != null) {
+            var tempLength: Fraction = new Fraction(this.length);
+            for (var idx: number = 0, len = this.tie.Fractions.Count; idx < len; ++idx) {
+                var fraction: Fraction = this.tie.Fractions[idx];
+                tempLength.Sub(fraction);
+            }
+            withoutTieLength = tempLength;
+        }
+        return withoutTieLength;
+    }
+    public calculateNoteOriginalLength(): Fraction {
+        return this.calculateNoteOriginalLength(new Fraction(this.length));
+    }
+    public calculateNoteOriginalLength(originalLength: Fraction): Fraction {
+        if (this.tie != null)
+            originalLength = this.calculateNoteLengthWithoutTie();
+        if (this.tuplet != null)
+            return this.length;
+        if (originalLength.Numerator > 1) {
+            var exp: number = <number>Math.Log(originalLength.Denominator, 2) - this.calculateNumberOfNeededDots(originalLength);
+            originalLength.Denominator = <number>Math.Pow(2, exp);
+            originalLength.Numerator = 1;
+        }
+        return originalLength;
+    }
+    public calculateNoteLengthWithDots(): Fraction {
+        if (this.tie != null)
+            return this.calculateNoteLengthWithoutTie();
+        return this.length;
+    }
+    public calculateNumberOfNeededDots(): number {
+        return this.calculateNumberOfNeededDots(this.length);
+    }
+    public calculateNumberOfNeededDots(fraction: Fraction): number {
+        var number: number = 1;
+        var product: number = 2;
+        if (this.tuplet == null) {
+            while (product < fraction.Numerator) {
+                number++;
+                product = <number>Math.Pow(2, number);
+            }
+        }
+        return number - 1;
+    }
+    public ToString(): string {
+        if (this.pitch != null)
+            return this.Pitch.ToString() + ", length: " + this.Length.ToString();
+        else return "rest note, length: " + this.Length.ToString();
+    }
+    public getAbsoluteTimestamp(): Fraction {
+        var absolute: Fraction = new Fraction(this.voiceEntry.Timestamp);
+        absolute += this.parentStaffEntry.VerticalContainerParent.ParentMeasure.AbsoluteTimestamp;
+        return absolute;
+    }
+    public checkForDoubleSlur(slur: Slur): boolean {
+        for (var idx: number = 0, len = this.slurs.Count; idx < len; ++idx) {
+            var noteSlur: Slur = this.slurs[idx];
+            if (noteSlur.StartNote != null && noteSlur.EndNote != null && slur.StartNote != null && slur.StartNote == noteSlur.StartNote && noteSlur.EndNote == this)
+                return true;
+        }
+        return false;
+    }
+}
+export module Note {
+    export enum Appearance {
+        Normal,
+
+        Grace,
+
+        Cue
+    }
+}

+ 38 - 0
src/MusicalScore/VoiceData/OrnamentContainer.ts

@@ -0,0 +1,38 @@
+export class OrnamentContainer {
+    constructor(ornament: OrnamentEnum) {
+        this.ornament = ornament;
+    }
+    private ornament: OrnamentEnum;
+    private accidentalAbove: AccEnum = AccEnum.NONE;
+    private accidentalBelow: AccEnum = AccEnum.NONE;
+    public get GetOrnament(): OrnamentEnum {
+        return this.ornament;
+    }
+    public get AccidentalAbove(): AccEnum {
+        return this.accidentalAbove;
+    }
+    public set AccidentalAbove(value: AccEnum) {
+        this.accidentalAbove = value;
+    }
+    public get AccidentalBelow(): AccEnum {
+        return this.accidentalBelow;
+    }
+    public set AccidentalBelow(value: AccEnum) {
+        this.accidentalBelow = value;
+    }
+}
+export enum OrnamentEnum {
+    Trill,
+
+    Turn,
+
+    InvertedTurn,
+
+    DelayedTurn,
+
+    DelayedInvertedTurn,
+
+    Mordent,
+
+    InvertedMordent
+}

+ 260 - 0
src/MusicalScore/VoiceData/SourceMeasure.ts

@@ -0,0 +1,260 @@
+export class SourceMeasure {
+    constructor(completeNumberOfStaves: number) {
+        this.completeNumberOfStaves = completeNumberOfStaves;
+        this.initialize();
+    }
+    public MeasureListIndex: number;
+    public EndsPiece: boolean;
+    private measureNumber: number;
+    private parentMusicPart: SourceMusicPart;
+    private absoluteTimestamp: Fraction;
+    private completeNumberOfStaves: number;
+    private duration: Fraction;
+    private staffLinkedExpressions: List<List<MultiExpression>> = new List<List<MultiExpression>>();
+    private tempoExpressions: List<MultiTempoExpression> = new List<MultiTempoExpression>();
+    private verticalSourceStaffEntryContainers: List<VerticalSourceStaffEntryContainer> = new List<VerticalSourceStaffEntryContainer>();
+    private implicitMeasure: boolean;
+    private breakSystemAfter: boolean;
+    private staffMeasureErrors: List<boolean> = new List<boolean>();
+    private firstInstructionsStaffEntries: List<SourceStaffEntry> = new List<SourceStaffEntry>();
+    private lastInstructionsStaffEntries: List<SourceStaffEntry> = new List<SourceStaffEntry>();
+    private firstRepetitionInstructions: List<RepetitionInstruction> = new List<RepetitionInstruction>();
+    private lastRepetitionInstructions: List<RepetitionInstruction> = new List<RepetitionInstruction>();
+    public get MeasureNumber(): number {
+        return this.measureNumber;
+    }
+    public set MeasureNumber(value: number) {
+        this.measureNumber = value;
+    }
+    public get AbsoluteTimestamp(): Fraction {
+        return this.absoluteTimestamp;
+    }
+    public set AbsoluteTimestamp(value: Fraction) {
+        this.absoluteTimestamp = value;
+    }
+    public get CompleteNumberOfStaves(): number {
+        return this.completeNumberOfStaves;
+    }
+    public get Duration(): Fraction {
+        return this.duration;
+    }
+    public set Duration(value: Fraction) {
+        this.duration = value;
+    }
+    public get ImplicitMeasure(): boolean {
+        return this.implicitMeasure;
+    }
+    public set ImplicitMeasure(value: boolean) {
+        this.implicitMeasure = value;
+    }
+    public get BreakSystemAfter(): boolean {
+        return this.breakSystemAfter;
+    }
+    public set BreakSystemAfter(value: boolean) {
+        this.breakSystemAfter = value;
+    }
+    public get StaffLinkedExpressions(): List<List<MultiExpression>> {
+        return this.staffLinkedExpressions;
+    }
+    public get TempoExpressions(): List<MultiTempoExpression> {
+        return this.tempoExpressions;
+    }
+    public get VerticalSourceStaffEntryContainers(): List<VerticalSourceStaffEntryContainer> {
+        return this.verticalSourceStaffEntryContainers;
+    }
+    public get FirstInstructionsStaffEntries(): List<SourceStaffEntry> {
+        return this.firstInstructionsStaffEntries;
+    }
+    public get LastInstructionsStaffEntries(): List<SourceStaffEntry> {
+        return this.lastInstructionsStaffEntries;
+    }
+    public get FirstRepetitionInstructions(): List<RepetitionInstruction> {
+        return this.firstRepetitionInstructions;
+    }
+    public get LastRepetitionInstructions(): List<RepetitionInstruction> {
+        return this.lastRepetitionInstructions;
+    }
+    public getErrorInMeasure(staffIndex: number): boolean {
+        return this.staffMeasureErrors[staffIndex];
+    }
+    public setErrorInStaffMeasure(staffIndex: number, hasError: boolean): void {
+        this.staffMeasureErrors[staffIndex] = hasError;
+    }
+    public getNextMeasure(measures: List<SourceMeasure>): SourceMeasure {
+        if (this.MeasureListIndex + 1 < measures.Count)
+            return measures[this.MeasureListIndex + 1];
+        return null;
+    }
+    public getPreviousMeasure(measures: List<SourceMeasure>): SourceMeasure {
+        if (this.MeasureListIndex - 1 > 0)
+            return measures[this.MeasureListIndex - 1];
+        return null;
+    }
+    public findOrCreateStaffEntry(inMeasureTimestamp: Fraction, inSourceMeasureStaffIndex: number, staff: Staff, createdNewContainer: boolean): SourceStaffEntry {
+        var staffEntry: SourceStaffEntry = null;
+        createdNewContainer = false;
+        var existingVerticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = this.verticalSourceStaffEntryContainers.Find(o => o.Timestamp == inMeasureTimestamp);
+        if (existingVerticalSourceStaffEntryContainer != null) {
+            if (existingVerticalSourceStaffEntryContainer[inSourceMeasureStaffIndex] != null)
+                return existingVerticalSourceStaffEntryContainer[inSourceMeasureStaffIndex];
+            else {
+                staffEntry = new SourceStaffEntry(existingVerticalSourceStaffEntryContainer, staff);
+                existingVerticalSourceStaffEntryContainer[inSourceMeasureStaffIndex] = staffEntry;
+                return staffEntry;
+            }
+        }
+        createdNewContainer = true;
+        if (this.verticalSourceStaffEntryContainers.Count == 0 || this.verticalSourceStaffEntryContainers.Last().Timestamp < inMeasureTimestamp) {
+            var container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(this, new Fraction(inMeasureTimestamp), this.completeNumberOfStaves);
+            this.verticalSourceStaffEntryContainers.Add(container);
+            staffEntry = new SourceStaffEntry(container, staff);
+            container[inSourceMeasureStaffIndex] = staffEntry;
+        }
+        else {
+            for (var i: number = this.verticalSourceStaffEntryContainers.Count - 1; i >= 0; i--) {
+                if (this.verticalSourceStaffEntryContainers[i].Timestamp < inMeasureTimestamp) {
+                    var container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(this, new Fraction(inMeasureTimestamp), this.completeNumberOfStaves);
+                    this.verticalSourceStaffEntryContainers.Insert(i + 1, container);
+                    staffEntry = new SourceStaffEntry(container, staff);
+                    container[inSourceMeasureStaffIndex] = staffEntry;
+                    return staffEntry;
+                }
+                if (i == 0) {
+                    var container: VerticalSourceStaffEntryContainer = new VerticalSourceStaffEntryContainer(this, new Fraction(inMeasureTimestamp), this.completeNumberOfStaves);
+                    this.verticalSourceStaffEntryContainers.Insert(i, container);
+                    staffEntry = new SourceStaffEntry(container, staff);
+                    container[inSourceMeasureStaffIndex] = staffEntry;
+                    return staffEntry;
+                }
+            }
+        }
+        return staffEntry;
+    }
+    public findOrCreateVoiceEntry(sse: SourceStaffEntry, voice: Voice, createdNewVoiceEntry: boolean): VoiceEntry {
+        var ve: VoiceEntry = null;
+        for (var idx: number = 0, len = sse.VoiceEntries.Count; idx < len; ++idx) {
+            var voiceEntry: VoiceEntry = sse.VoiceEntries[idx];
+            if (voiceEntry.ParentVoice == voice) {
+                ve = voiceEntry;
+                break;
+            }
+        }
+        if (ve == null) {
+            ve = new VoiceEntry(sse.Timestamp, voice, sse);
+            sse.VoiceEntries.Add(ve);
+            createdNewVoiceEntry = true;
+        }
+        else {
+            createdNewVoiceEntry = false;
+        }
+        return ve;
+    }
+    public getPreviousSourceStaffEntryFromIndex(verticalIndex: number, horizontalIndex: number): SourceStaffEntry {
+        for (var i: number = horizontalIndex - 1; i >= 0; i--)
+            if (this.verticalSourceStaffEntryContainers[i][verticalIndex] != null)
+                return this.verticalSourceStaffEntryContainers[i][verticalIndex];
+        return null;
+    }
+    public getVerticalContainerIndexByTimestamp(musicTimestamp: Fraction): number {
+        var index: number = -1;
+        for (var idx: number = 0, len = this.VerticalSourceStaffEntryContainers.Count; idx < len; ++idx) {
+            var verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = this.VerticalSourceStaffEntryContainers[idx];
+            if (verticalSourceStaffEntryContainer.Timestamp == musicTimestamp)
+                return this.verticalSourceStaffEntryContainers.IndexOf(verticalSourceStaffEntryContainer);
+        }
+        return index;
+    }
+    public getVerticalContainerByTimestamp(musicTimestamp: Fraction): VerticalSourceStaffEntryContainer {
+        for (var idx: number = 0, len = this.VerticalSourceStaffEntryContainers.Count; idx < len; ++idx) {
+            var verticalSourceStaffEntryContainer: VerticalSourceStaffEntryContainer = this.VerticalSourceStaffEntryContainers[idx];
+            if (verticalSourceStaffEntryContainer.Timestamp == musicTimestamp)
+                return verticalSourceStaffEntryContainer;
+        }
+        return null;
+    }
+    public checkForEmptyVerticalContainer(index: number): void {
+        var nullCounter: number = 0;
+        for (var i: number = 0; i < this.completeNumberOfStaves; i++)
+            if (this.verticalSourceStaffEntryContainers[index][i] == null)
+                nullCounter++;
+        if (nullCounter == this.completeNumberOfStaves)
+            this.verticalSourceStaffEntryContainers.Remove(this.verticalSourceStaffEntryContainers[index]);
+    }
+    public reverseCheck(musicSheet: MusicSheet, maxInstDuration: Fraction): Fraction {
+        var maxDuration: Fraction = new Fraction(0, 1);
+        var instrumentsDurations: List<Fraction> = new List<Fraction>();
+        for (var i: number = 0; i < musicSheet.Instruments.Count; i++) {
+            var instrumentDuration: Fraction = new Fraction(0, 1);
+            var inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
+            for (var j: number = 0; j < musicSheet.Instruments[i].Staves.Count; j++) {
+                var lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
+                if (lastStaffEntry != null && !lastStaffEntry.hasTie()) {
+                    var verticalContainerIndex: number = this.verticalSourceStaffEntryContainers.IndexOf(lastStaffEntry.VerticalContainerParent);
+                    for (var m: number = verticalContainerIndex - 1; m >= 0; m--) {
+                        var previousStaffEntry: SourceStaffEntry = this.verticalSourceStaffEntryContainers[m][inSourceMeasureInstrumentIndex + j];
+                        if (previousStaffEntry != null && previousStaffEntry.hasTie()) {
+                            if (instrumentDuration < previousStaffEntry.Timestamp + previousStaffEntry.calculateMaxNoteLength()) {
+                                instrumentDuration = previousStaffEntry.Timestamp + previousStaffEntry.calculateMaxNoteLength();
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+            instrumentsDurations.Add(instrumentDuration);
+        }
+        for (var idx: number = 0, len = instrumentsDurations.Count; idx < len; ++idx) {
+            var instrumentsDuration: Fraction = instrumentsDurations[idx];
+            if (maxDuration < instrumentsDuration)
+                maxDuration = instrumentsDuration;
+        }
+        if (maxDuration > maxInstDuration)
+            return maxDuration;
+        return maxInstDuration;
+    }
+    public calculateInstrumentsDuration(musicSheet: MusicSheet, instrumentMaxTieNoteFractions: List<Fraction>): List<Fraction> {
+        var instrumentsDurations: List<Fraction> = new List<Fraction>();
+        for (var i: number = 0; i < musicSheet.Instruments.Count; i++) {
+            var instrumentDuration: Fraction = new Fraction(0, 1);
+            var inSourceMeasureInstrumentIndex: number = musicSheet.getGlobalStaffIndexOfFirstStaff(musicSheet.Instruments[i]);
+            for (var j: number = 0; j < musicSheet.Instruments[i].Staves.Count; j++) {
+                var lastStaffEntry: SourceStaffEntry = this.getLastSourceStaffEntryForInstrument(inSourceMeasureInstrumentIndex + j);
+                if (lastStaffEntry != null && lastStaffEntry.Timestamp != null) {
+                    if (instrumentDuration < lastStaffEntry.Timestamp + lastStaffEntry.calculateMaxNoteLength())
+                        instrumentDuration = new Fraction(lastStaffEntry.Timestamp + lastStaffEntry.calculateMaxNoteLength());
+                }
+            }
+            if (instrumentDuration < instrumentMaxTieNoteFractions[i])
+                instrumentDuration = instrumentMaxTieNoteFractions[i];
+            instrumentsDurations.Add(instrumentDuration);
+        }
+        return instrumentsDurations;
+    }
+    public getEntriesPerStaff(staffIndex: number): List<SourceStaffEntry> {
+        var sourceStaffEntries: List<SourceStaffEntry> = new List<SourceStaffEntry>();
+        for (var idx: number = 0, len = this.VerticalSourceStaffEntryContainers.Count; idx < len; ++idx) {
+            var container: VerticalSourceStaffEntryContainer = this.VerticalSourceStaffEntryContainers[idx];
+            var sse: SourceStaffEntry = container[staffIndex];
+            if (sse != null)
+                sourceStaffEntries.Add(sse);
+        }
+        return sourceStaffEntries;
+    }
+    private initialize(): void {
+        for (var i: number = 0; i < this.completeNumberOfStaves; i++) {
+            this.firstInstructionsStaffEntries.Add(null);
+            this.lastInstructionsStaffEntries.Add(null);
+            this.staffMeasureErrors.Add(false);
+            this.staffLinkedExpressions.Add(new List<MultiExpression>());
+        }
+        this.implicitMeasure = false;
+        this.breakSystemAfter = false;
+        this.EndsPiece = false;
+    }
+    private getLastSourceStaffEntryForInstrument(instrumentIndex: number): SourceStaffEntry {
+        for (var i: number = this.verticalSourceStaffEntryContainers.Count - 1; i >= 0; i--)
+            if (this.verticalSourceStaffEntryContainers[i][instrumentIndex] != null)
+                return this.verticalSourceStaffEntryContainers[i][instrumentIndex];
+        return null;
+    }
+}

+ 142 - 0
src/MusicalScore/VoiceData/SourceStaffEntry.ts

@@ -0,0 +1,142 @@
+export class SourceStaffEntry {
+    constructor(verticalContainerParent: VerticalSourceStaffEntryContainer, parentStaff: Staff) {
+        this.verticalContainerParent = verticalContainerParent;
+        this.parentStaff = parentStaff;
+    }
+    private parentStaff: Staff;
+    private verticalContainerParent: VerticalSourceStaffEntryContainer;
+    private voiceEntries: List<VoiceEntry> = new List<VoiceEntry>();
+    private staffEntryLink: StaffEntryLink;
+    private instructions: List<AbstractNotationInstruction> = new List<AbstractNotationInstruction>();
+    private graceVoiceEntriesBefore: List<VoiceEntry> = new List<VoiceEntry>();
+    private graceVoiceEntriesAfter: List<VoiceEntry> = new List<VoiceEntry>();
+    private chordSymbolContainer: ChordSymbolContainer;
+    public get ParentStaff(): Staff {
+        return this.parentStaff;
+    }
+    public get VerticalContainerParent(): VerticalSourceStaffEntryContainer {
+        return this.verticalContainerParent;
+    }
+    public get Timestamp(): Fraction {
+        if (this.VerticalContainerParent != null)
+            return this.VerticalContainerParent.Timestamp;
+        return null;
+    }
+    public get AbsoluteTimestamp(): Fraction {
+        if (this.VerticalContainerParent != null)
+            return this.VerticalContainerParent.ParentMeasure.AbsoluteTimestamp + this.VerticalContainerParent.Timestamp;
+        return null;
+    }
+    public get VoiceEntries(): List<VoiceEntry> {
+        return this.voiceEntries;
+    }
+    public set VoiceEntries(value: List<VoiceEntry>) {
+        this.voiceEntries = value;
+    }
+    public get Link(): StaffEntryLink {
+        return this.staffEntryLink;
+    }
+    public set Link(value: StaffEntryLink) {
+        this.staffEntryLink = value;
+    }
+    public get Instructions(): List<AbstractNotationInstruction> {
+        return this.instructions;
+    }
+    public set Instructions(value: List<AbstractNotationInstruction>) {
+        this.instructions = value;
+    }
+    public get ChordContainer(): ChordSymbolContainer {
+        return this.chordSymbolContainer;
+    }
+    public set ChordContainer(value: ChordSymbolContainer) {
+        this.chordSymbolContainer = value;
+    }
+    public removeAllInstructionsOfType<T>(): number {
+        var i: number = 0;
+        var ret: number = 0;
+        while (i < this.instructions.Count) {
+            if (this.instructions[i] instanceof T) {
+                this.instructions.RemoveAt(i);
+                ret++;
+            }
+            else i++;
+        }
+        return ret;
+    }
+    public removeFirstInstructionOfType<T>(): boolean {
+        for (var i: number = 0; i < this.instructions.Count; i++) {
+            if (this.instructions[i] instanceof T) {
+                this.instructions.RemoveAt(i);
+                return true;
+            }
+        }
+        return false;
+    }
+    public calculateMinNoteLength(): Fraction {
+        var duration: Fraction = new Fraction(number.MaxValue, 1);
+        for (var idx: number = 0, len = this.VoiceEntries.Count; idx < len; ++idx) {
+            var voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            for (var idx2: number = 0, len2 = voiceEntry.Notes.Count; idx2 < len2; ++idx2) {
+                var note: Note = voiceEntry.Notes[idx2];
+                if (note.NoteTie != null) {
+                    if (duration > note.calculateNoteLengthWithoutTie())
+                        duration = note.calculateNoteLengthWithoutTie();
+                }
+                else {
+                    if (duration > note.Length)
+                        duration = note.Length;
+                }
+            }
+        }
+        return duration;
+    }
+    public calculateMaxNoteLength(): Fraction {
+        var duration: Fraction = new Fraction(0, 1);
+        for (var idx: number = 0, len = this.VoiceEntries.Count; idx < len; ++idx) {
+            var voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            for (var idx2: number = 0, len2 = voiceEntry.Notes.Count; idx2 < len2; ++idx2) {
+                var note: Note = voiceEntry.Notes[idx2];
+                if (note.NoteTie != null) {
+                    if (duration < note.calculateNoteLengthWithoutTie()) {
+                        duration = note.calculateNoteLengthWithoutTie();
+                        for (var idx3: number = 0, len3 = note.NoteTie.Fractions.Count; idx3 < len3; ++idx3) {
+                            var fraction: Fraction = note.NoteTie.Fractions[idx3];
+                            duration.Add(fraction);
+                        }
+                    }
+                }
+                else {
+                    if (duration < note.Length)
+                        duration = note.Length;
+                }
+            }
+        }
+        return duration;
+    }
+    public hasNotes(): boolean {
+        for (var idx: number = 0, len = this.VoiceEntries.Count; idx < len; ++idx) {
+            var voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            if (voiceEntry.Notes.Count > 0)
+                return true;
+        }
+        return false;
+    }
+    public hasTie(): boolean {
+        for (var idx: number = 0, len = this.VoiceEntries.Count; idx < len; ++idx) {
+            var voiceEntry: VoiceEntry = this.VoiceEntries[idx];
+            if (voiceEntry.hasTie())
+                return true;
+        }
+        return false;
+    }
+    public findLinkedNotes(linkedNotes: List<Note>): void {
+        for (var idx: number = 0, len = this.voiceEntries.Count; idx < len; ++idx) {
+            var voiceEntry: VoiceEntry = this.voiceEntries[idx];
+            for (var idx2: number = 0, len2 = voiceEntry.Notes.Count; idx2 < len2; ++idx2) {
+                var note: Note = voiceEntry.Notes[idx2];
+                if (note.ParentStaffEntry == this)
+                    linkedNotes.Add(note);
+            }
+        }
+    }
+}

+ 33 - 0
src/MusicalScore/VoiceData/Staff.ts

@@ -0,0 +1,33 @@
+export class Staff {
+    constructor(parentInstrument: Instrument, instrumentStaffId: number) {
+        this.parentInstrument = parentInstrument;
+        this.id = instrumentStaffId;
+        this.Audible = true;
+        this.Following = true;
+    }
+    public IdInMusicSheet: number;
+    public Audible: boolean;
+    public Following: boolean;
+    private parentInstrument: Instrument;
+    private voices: List<Voice> = new List<Voice>();
+    private volume: number = 1;
+    private id: number;
+    public get ParentInstrument(): Instrument {
+        return this.parentInstrument;
+    }
+    public set ParentInstrument(value: Instrument) {
+        this.parentInstrument = value;
+    }
+    public get Voices(): List<Voice> {
+        return this.voices;
+    }
+    public get Id(): number {
+        return this.id;
+    }
+    public get Volume(): number {
+        return this.volume;
+    }
+    public set Volume(value: number) {
+        this.volume = value;
+    }
+}

+ 16 - 0
src/MusicalScore/VoiceData/StaffEntryLink.ts

@@ -0,0 +1,16 @@
+export class StaffEntryLink {
+    constructor(voiceEntry: VoiceEntry) {
+        this.voiceEntry = voiceEntry;
+    }
+    private voiceEntry: VoiceEntry;
+    private linkStaffEntries: List<SourceStaffEntry> = new List<SourceStaffEntry>();
+    public get GetVoiceEntry(): VoiceEntry {
+        return this.voiceEntry;
+    }
+    public get LinkStaffEntries(): List<SourceStaffEntry> {
+        return this.linkStaffEntries;
+    }
+    public set LinkStaffEntries(value: List<SourceStaffEntry>) {
+        this.linkStaffEntries = value;
+    }
+}

+ 83 - 0
src/MusicalScore/VoiceData/Tie.ts

@@ -0,0 +1,83 @@
+export class Tie {
+    constructor(note: Note) {
+        this.start = note;
+    }
+    private start: Note;
+    private tieBeam: Beam;
+    private beamStartTimestamp: Fraction;
+    private tieTuplet: Tuplet;
+    private tieEndingSlur: Slur;
+    private tieStartingSlur: Slur;
+    private fractions: List<Fraction> = new List<Fraction>();
+    private noteHasBeenCreated: List<boolean> = new List<boolean>();
+    private baseNoteYPosition: number;
+    public get Start(): Note {
+        return this.start;
+    }
+    public set Start(value: Note) {
+        this.start = value;
+    }
+    public get TieBeam(): Beam {
+        return this.tieBeam;
+    }
+    public set TieBeam(value: Beam) {
+        this.tieBeam = value;
+    }
+    public get BeamStartTimestamp(): Fraction {
+        return this.beamStartTimestamp;
+    }
+    public set BeamStartTimestamp(value: Fraction) {
+        this.beamStartTimestamp = value;
+    }
+    public get TieTuplet(): Tuplet {
+        return this.tieTuplet;
+    }
+    public set TieTuplet(value: Tuplet) {
+        this.tieTuplet = value;
+    }
+    public get TieEndingSlur(): Slur {
+        return this.tieEndingSlur;
+    }
+    public set TieEndingSlur(value: Slur) {
+        this.tieEndingSlur = value;
+    }
+    public get TieStartingSlur(): Slur {
+        return this.tieStartingSlur;
+    }
+    public set TieStartingSlur(value: Slur) {
+        this.tieStartingSlur = value;
+    }
+    public get Fractions(): List<Fraction> {
+        return this.fractions;
+    }
+    public set Fractions(value: List<Fraction>) {
+        this.fractions = value;
+    }
+    public get NoteHasBeenCreated(): List<boolean> {
+        return this.noteHasBeenCreated;
+    }
+    public set NoteHasBeenCreated(value: List<boolean>) {
+        this.noteHasBeenCreated = value;
+    }
+    public get BaseNoteYPosition(): number {
+        return this.baseNoteYPosition;
+    }
+    public set BaseNoteYPosition(value: number) {
+        this.baseNoteYPosition = value;
+    }
+    public initializeBoolList(): void {
+        this.noteHasBeenCreated.Clear();
+        for (var idx: number = 0, len = this.fractions.Count; idx < len; ++idx) {
+            var fraction: Fraction = this.fractions[idx];
+            this.noteHasBeenCreated.Add(false);
+        }
+    }
+    public allGraphicalNotesHaveBeenCreated(): boolean {
+        for (var idx: number = 0, len = this.noteHasBeenCreated.Count; idx < len; ++idx) {
+            var b: boolean = this.noteHasBeenCreated[idx];
+            if (!b)
+                return false;
+        }
+        return true;
+    }
+}

+ 34 - 0
src/MusicalScore/VoiceData/Tuplet.ts

@@ -0,0 +1,34 @@
+export class Tuplet {
+    constructor(tupletLabelNumber: number) {
+        this.tupletLabelNumber = tupletLabelNumber;
+    }
+    private tupletLabelNumber: number;
+    private notes: List<List<Note>> = new List<List<Note>>();
+    private fractions: List<Fraction> = new List<Fraction>();
+    public get TupletLabelNumber(): number {
+        return this.tupletLabelNumber;
+    }
+    public set TupletLabelNumber(value: number) {
+        this.tupletLabelNumber = value;
+    }
+    public get Notes(): List<List<Note>> {
+        return this.notes;
+    }
+    public set Notes(value: List<List<Note>>) {
+        this.notes = value;
+    }
+    public get Fractions(): List<Fraction> {
+        return this.fractions;
+    }
+    public set Fractions(value: List<Fraction>) {
+        this.fractions = value;
+    }
+    public getNoteIndex(note: Note): number {
+        var index: number = 0;
+        for (var i: number = 0; i < this.notes.Count; i++)
+            for (var j: number = 0; j < this.notes[i].Count; j++)
+                if (note == this.notes[i][j])
+                    index = i;
+        return index;
+    }
+}

+ 50 - 0
src/MusicalScore/VoiceData/VerticalSourceStaffEntryContainer.ts

@@ -0,0 +1,50 @@
+export class VerticalSourceStaffEntryContainer {
+    constructor(parentMeasure: SourceMeasure, timestamp: Fraction, size: number) {
+        this.timestamp = timestamp;
+        this.size = size;
+        this.initialize();
+        this.parentMeasure = parentMeasure;
+    }
+    private timestamp: Fraction;
+    private size: number;
+    private staffEntries: List<SourceStaffEntry> = new List<SourceStaffEntry>();
+    private comments: List<Comment> = new List<Comment>();
+    private parentMeasure: SourceMeasure;
+    public get Timestamp(): Fraction {
+        return this.timestamp;
+    }
+    public set Timestamp(value: Fraction) {
+        this.timestamp = value;
+    }
+    public get StaffEntries(): List<SourceStaffEntry> {
+        return this.staffEntries;
+    }
+    public set StaffEntries(value: List<SourceStaffEntry>) {
+        this.staffEntries = value;
+    }
+    public get Comments(): List<Comment> {
+        return this.comments;
+    }
+    public set Comments(value: List<Comment>) {
+        this.comments = value;
+    }
+    public get ParentMeasure(): SourceMeasure {
+        return this.parentMeasure;
+    }
+    public set ParentMeasure(value: SourceMeasure) {
+        this.parentMeasure = value;
+    }
+    public getAbsoluteTimestamp(): Fraction {
+        return new Fraction(this.timestamp + this.parentMeasure.AbsoluteTimestamp);
+    }
+    private initialize(): void {
+        for (var i: number = 0; i < this.size; i++)
+            this.staffEntries.Add(null);
+    }
+    public $get$(index: number): SourceStaffEntry {
+        return this.staffEntries[index];
+    }
+    public $set$(index: number, value: SourceStaffEntry): void {
+        this.staffEntries[index] = value;
+    }
+}

+ 49 - 0
src/MusicalScore/VoiceData/Voice.ts

@@ -0,0 +1,49 @@
+export class Voice {
+    constructor(parent: Instrument, voiceId: number) {
+        this.parent = parent;
+        this.visible = true;
+        this.audible = true;
+        this.following = true;
+        this.voiceId = voiceId;
+    }
+    private voiceEntries: List<VoiceEntry> = new List<VoiceEntry>();
+    private parent: Instrument;
+    private visible: boolean;
+    private audible: boolean;
+    private following: boolean;
+    private voiceId: number;
+    private volume: number = 1;
+    public get VoiceEntries(): List<VoiceEntry> {
+        return this.voiceEntries;
+    }
+    public get Parent(): Instrument {
+        return this.parent;
+    }
+    public get Visible(): boolean {
+        return this.visible;
+    }
+    public set Visible(value: boolean) {
+        this.visible = value;
+    }
+    public get Audible(): boolean {
+        return this.audible;
+    }
+    public set Audible(value: boolean) {
+        this.audible = value;
+    }
+    public get Following(): boolean {
+        return this.following;
+    }
+    public set Following(value: boolean) {
+        this.following = value;
+    }
+    public get VoiceId(): number {
+        return this.voiceId;
+    }
+    public get Volume(): number {
+        return this.volume;
+    }
+    public set Volume(value: number) {
+        this.volume = value;
+    }
+}

+ 332 - 0
src/MusicalScore/VoiceData/VoiceEntry.ts

@@ -0,0 +1,332 @@
+export class VoiceEntry {
+    constructor(timestamp: Fraction, parentVoice: Voice, parentSourceStaffEntry: SourceStaffEntry) {
+        this.timestamp = timestamp;
+        this.parentVoice = parentVoice;
+        this.parentSourceStaffEntry = parentSourceStaffEntry;
+    }
+    public GraceVoiceEntriesBefore: List<VoiceEntry>;
+    public GraceVoiceEntriesAfter: List<VoiceEntry>;
+    private parentVoice: Voice;
+    private parentSourceStaffEntry: SourceStaffEntry;
+    private timestamp: Fraction;
+    private notes: List<Note> = new List<Note>();
+    private articulations: List<ArticulationEnum> = new List<ArticulationEnum>();
+    private technicalInstructions: List<TechnicalInstruction> = new List<TechnicalInstruction>();
+    private lyricsEntries: Dictionary<number, LyricsEntry> = new Dictionary<number, LyricsEntry>();
+    private arpeggiosNotesIndices: List<number> = new List<number>();
+    private ornamentContainer: OrnamentContainer;
+    public get ParentSourceStaffEntry(): SourceStaffEntry {
+        return this.parentSourceStaffEntry;
+    }
+    public get ParentVoice(): Voice {
+        return this.parentVoice;
+    }
+    public get Timestamp(): Fraction {
+        return this.timestamp;
+    }
+    public set Timestamp(value: Fraction) {
+        this.timestamp = value;
+    }
+    public get Notes(): List<Note> {
+        return this.notes;
+    }
+    public get Articulations(): List<ArticulationEnum> {
+        return this.articulations;
+    }
+    public get TechnicalInstructions(): List<TechnicalInstruction> {
+        return this.technicalInstructions;
+    }
+    public get LyricsEntries(): Dictionary<number, LyricsEntry> {
+        return this.lyricsEntries;
+    }
+    public set LyricsEntries(value: Dictionary<number, LyricsEntry>) {
+        this.lyricsEntries = value;
+    }
+    public get ArpeggiosNotesIndices(): List<number> {
+        return this.arpeggiosNotesIndices;
+    }
+    public set ArpeggiosNotesIndices(value: List<number>) {
+        this.arpeggiosNotesIndices = value;
+    }
+    public get OrnamentContainer(): OrnamentContainer {
+        return this.ornamentContainer;
+    }
+    public set OrnamentContainer(value: OrnamentContainer) {
+        this.ornamentContainer = value;
+    }
+    public static isSupportedArticulation(articulation: ArticulationEnum): boolean {
+        switch (articulation) {
+            case ArticulationEnum.accent:
+            case ArticulationEnum.strongaccent:
+            case ArticulationEnum.invertedstrongaccent:
+            case ArticulationEnum.staccato:
+            case ArticulationEnum.staccatissimo:
+            case ArticulationEnum.spiccato:
+            case ArticulationEnum.tenuto:
+            case ArticulationEnum.fermata:
+            case ArticulationEnum.invertedfermata:
+            case ArticulationEnum.breathmark:
+            case ArticulationEnum.caesura:
+            case ArticulationEnum.lefthandpizzicato:
+            case ArticulationEnum.naturalharmonic:
+            case ArticulationEnum.snappizzicato:
+            case ArticulationEnum.upbow:
+            case ArticulationEnum.downbow:
+                return true;
+            default:
+                return false;
+        }
+    }
+    public hasTie(): boolean {
+        for (var idx: number = 0, len = this.Notes.Count; idx < len; ++idx) {
+            var note: Note = this.Notes[idx];
+            if (note.NoteTie != null)
+                return true;
+        }
+        return false;
+    }
+    public hasSlur(): boolean {
+        for (var idx: number = 0, len = this.Notes.Count; idx < len; ++idx) {
+            var note: Note = this.Notes[idx];
+            if (note.NoteSlurs.Count > 0)
+                return true;
+        }
+        return false;
+    }
+    public isStaccato(): boolean {
+        for (var idx: number = 0, len = this.Articulations.Count; idx < len; ++idx) {
+            var articulation: ArticulationEnum = this.Articulations[idx];
+            if (articulation == ArticulationEnum.staccato)
+                return true;
+        }
+        return false;
+    }
+    public isAccent(): boolean {
+        for (var idx: number = 0, len = this.Articulations.Count; idx < len; ++idx) {
+            var articulation: ArticulationEnum = this.Articulations[idx];
+            if (articulation == ArticulationEnum.accent || articulation == ArticulationEnum.strongaccent)
+                return true;
+        }
+        return false;
+    }
+    public getVerseNumberForLyricEntry(lyricsEntry: LyricsEntry): number {
+        var key: number = 1;
+        var lyricsEntriesArr: KeyValuePair<number, LyricsEntry>[] = this.lyricsEntries.ToArray();
+        for (var idx: number = 0, len = lyricsEntriesArr.length; idx < len; ++idx) {
+            var keyValuePair: KeyValuePair<number, LyricsEntry> = lyricsEntriesArr[idx];
+            if (lyricsEntry == keyValuePair.Value)
+                key = keyValuePair.Key;
+        }
+        return key;
+    }
+    public createVoiceEntriesForOrnament(activeKey: KeyInstruction): List<VoiceEntry> {
+        return this.createVoiceEntriesForOrnament(this, activeKey);
+    }
+    public createVoiceEntriesForOrnament(voiceEntryWithOrnament: VoiceEntry,
+        activeKey: KeyInstruction): List<VoiceEntry> {
+        var voiceEntries: List<VoiceEntry> = new List<VoiceEntry>();
+        if (voiceEntryWithOrnament.ornamentContainer == null)
+            return null;
+        var baseNote: Note = this.notes[0];
+        var baselength: Fraction = baseNote.calculateNoteLengthWithoutTie();
+        var baseVoice: Voice = voiceEntryWithOrnament.ParentVoice;
+        var baseTimestamp: Fraction = voiceEntryWithOrnament.Timestamp;
+        var currentTimestamp: Fraction = new Fraction(baseTimestamp);
+        var length: Fraction;
+        switch (voiceEntryWithOrnament.ornamentContainer.GetOrnament) {
+            case OrnamentEnum.Trill:
+                {
+                    length = new Fraction(baselength.Numerator, baselength.Denominator * 8);
+                    var higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                    var alteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                    if (voiceEntryWithOrnament.OrnamentContainer.AccidentalAbove != AccEnum.NONE)
+                        alteration = <AccidentalEnum><number>voiceEntryWithOrnament.ornamentContainer.AccidentalAbove;
+                    for (var i: number = 0; i < 8; i++) {
+                        if ((i % 2) == 0) {
+                            currentTimestamp = baseTimestamp + new Fraction(i * length.Numerator, length.Denominator);
+                            this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                        }
+                        else {
+                            currentTimestamp = baseTimestamp + new Fraction(i * length.Numerator, length.Denominator);
+                            this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, alteration,
+                                voiceEntries);
+                        }
+                    }
+                    break;
+                }
+            case OrnamentEnum.Turn:
+                {
+                    length = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                    var lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                    var lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                    var higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                    var higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, higherAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp += length;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, lowerPitch, lowerAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    break;
+                }
+            case OrnamentEnum.InvertedTurn:
+                {
+                    length = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                    var lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                    var lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                    var higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                    var higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, lowerPitch, lowerAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp += length;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, higherAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    break;
+                }
+            case OrnamentEnum.DelayedTurn:
+                {
+                    length = new Fraction(baselength.Numerator, baselength.Denominator * 2);
+                    var lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                    var lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                    var higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                    var higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp = baseTimestamp + new Fraction(length);
+                    length.Denominator = baselength.Denominator * 8;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, higherAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp += length;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, lowerPitch, lowerAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    break;
+                }
+            case OrnamentEnum.DelayedInvertedTurn:
+                {
+                    length = new Fraction(baselength.Numerator, baselength.Denominator * 2);
+                    var lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                    var lowerAlteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                    var higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                    var higherAlteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp = baseTimestamp + new Fraction(length);
+                    length.Denominator = baselength.Denominator * 8;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, lowerPitch, lowerAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp += length;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, higherAlteration,
+                        voiceEntries);
+                    currentTimestamp += length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    break;
+                }
+            case OrnamentEnum.Mordent:
+                {
+                    length = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                    var higherPitch: Pitch = baseNote.Pitch.getTransposedPitch(1);
+                    var alteration: AccidentalEnum = activeKey.getAlterationForPitch(higherPitch);
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp += length;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, higherPitch, alteration,
+                        voiceEntries);
+                    length.Denominator = baselength.Denominator * 2;
+                    currentTimestamp = baseTimestamp + length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    break;
+                }
+            case OrnamentEnum.InvertedMordent:
+                {
+                    length = new Fraction(baselength.Numerator, baselength.Denominator * 4);
+                    var lowerPitch: Pitch = baseNote.Pitch.getTransposedPitch(-1);
+                    var alteration: AccidentalEnum = activeKey.getAlterationForPitch(lowerPitch);
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    currentTimestamp += length;
+                    this.createAlteratedVoiceEntry(currentTimestamp, length, baseVoice, lowerPitch, alteration, voiceEntries);
+                    length.Denominator = baselength.Denominator * 2;
+                    currentTimestamp = baseTimestamp + length;
+                    this.createBaseVoiceEntry(currentTimestamp, length, baseVoice, baseNote, voiceEntries);
+                    break;
+                }
+            default:
+                throw new ArgumentOutOfRangeException();
+        }
+        return voiceEntries;
+    }
+    private createBaseVoiceEntry(currentTimestamp: Fraction, length: Fraction, baseVoice: Voice, baseNote: Note,
+        voiceEntries: List<VoiceEntry>): void {
+        var voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, baseNote.ParentStaffEntry);
+        var pitch: Pitch = new Pitch(baseNote.Pitch.FundamentalNote, baseNote.Pitch.Octave, baseNote.Pitch.Accidental);
+        var note: Note = new Note(voiceEntry, null, length, pitch);
+        voiceEntry.Notes.Add(note);
+        voiceEntries.Add(voiceEntry);
+    }
+    private createAlteratedVoiceEntry(currentTimestamp: Fraction, length: Fraction, baseVoice: Voice,
+        higherPitch: Pitch, alteration: AccidentalEnum, voiceEntries: List<VoiceEntry>): void {
+        var voiceEntry: VoiceEntry = new VoiceEntry(currentTimestamp, baseVoice, null);
+        var pitch: Pitch = new Pitch(higherPitch.FundamentalNote, higherPitch.Octave, alteration);
+        var note: Note = new Note(voiceEntry, null, length, pitch);
+        voiceEntry.Notes.Add(note);
+        voiceEntries.Add(voiceEntry);
+    }
+}
+export enum ArticulationEnum {
+    accent,
+
+    strongaccent,
+
+    invertedstrongaccent,
+
+    staccato,
+
+    staccatissimo,
+
+    spiccato,
+
+    tenuto,
+
+    fermata,
+
+    invertedfermata,
+
+    breathmark,
+
+    caesura,
+
+    lefthandpizzicato,
+
+    naturalharmonic,
+
+    snappizzicato,
+
+    upbow,
+
+    downbow,
+
+    scoop,
+
+    plop,
+
+    doit,
+
+    falloff,
+
+    stress,
+
+    unstress,
+
+    detachedlegato,
+
+    otherarticulation
+}