|
@@ -19,6 +19,7 @@ import {IXmlAttribute} from "../../Common/FileIO/Xml";
|
|
|
import {ChordSymbolContainer} from "../VoiceData/ChordSymbolContainer";
|
|
|
import {Logging} from "../../Common/Logging";
|
|
|
import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
|
|
|
+import {ChordSymbolReader} from "./MusicSymbolModules/ChordSymbolReader";
|
|
|
//import Dictionary from "typescript-collections/dist/lib/Dictionary";
|
|
|
|
|
|
// FIXME: The following classes are missing
|
|
@@ -46,7 +47,7 @@ import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
|
|
|
/**
|
|
|
* To be implemented
|
|
|
*/
|
|
|
-export type repetitionInstructionReader = any;
|
|
|
+export type RepetitionInstructionReader = any;
|
|
|
|
|
|
/**
|
|
|
* An InstrumentReader is used during the reading phase to keep parsing new measures from the MusicXML file
|
|
@@ -54,1033 +55,1033 @@ export type repetitionInstructionReader = any;
|
|
|
*/
|
|
|
export class InstrumentReader {
|
|
|
|
|
|
- constructor(repetitionInstructionReader: repetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
|
|
|
- // (*) this.repetitionInstructionReader = repetitionInstructionReader;
|
|
|
- this.xmlMeasureList = xmlMeasureList;
|
|
|
- this.musicSheet = instrument.GetMusicSheet;
|
|
|
- this.instrument = instrument;
|
|
|
- this.activeClefs = new Array(instrument.Staves.length);
|
|
|
- this.activeClefsHaveBeenInitialized = new Array(instrument.Staves.length);
|
|
|
- for (let i: number = 0; i < instrument.Staves.length; i++) {
|
|
|
- this.activeClefsHaveBeenInitialized[i] = false;
|
|
|
- }
|
|
|
- // FIXME createExpressionGenerators(instrument.Staves.length);
|
|
|
- // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
|
|
|
- }
|
|
|
+ constructor(repetitionInstructionReader: RepetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
|
|
|
+ // this.repetitionInstructionReader = repetitionInstructionReader;
|
|
|
+ this.xmlMeasureList = xmlMeasureList;
|
|
|
+ this.musicSheet = instrument.GetMusicSheet;
|
|
|
+ this.instrument = instrument;
|
|
|
+ this.activeClefs = new Array(instrument.Staves.length);
|
|
|
+ this.activeClefsHaveBeenInitialized = new Array(instrument.Staves.length);
|
|
|
+ for (let i: number = 0; i < instrument.Staves.length; i++) {
|
|
|
+ this.activeClefsHaveBeenInitialized[i] = false;
|
|
|
+ }
|
|
|
+ // FIXME createExpressionGenerators(instrument.Staves.length);
|
|
|
+ // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
|
|
|
+ }
|
|
|
|
|
|
- // (*) private repetitionInstructionReader: RepetitionInstructionReader;
|
|
|
- private xmlMeasureList: IXmlElement[];
|
|
|
- private musicSheet: MusicSheet;
|
|
|
- private slurReader: any; // (*) SlurReader;
|
|
|
- private instrument: Instrument;
|
|
|
- private voiceGeneratorsDict: { [n: number]: VoiceGenerator; } = {};
|
|
|
- private staffMainVoiceGeneratorDict: { [staffId: number]: 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: [number, AbstractNotationInstruction][] = [];
|
|
|
- private openChordSymbolContainer: ChordSymbolContainer;
|
|
|
- // (*) private expressionReaders: ExpressionReader[];
|
|
|
- private currentVoiceGenerator: VoiceGenerator;
|
|
|
- //private openSlurDict: { [n: number]: Slur; } = {};
|
|
|
- private maxTieNoteFraction: Fraction;
|
|
|
+ // private repetitionInstructionReader: RepetitionInstructionReader;
|
|
|
+ private xmlMeasureList: IXmlElement[];
|
|
|
+ private musicSheet: MusicSheet;
|
|
|
+ private slurReader: any; // (*) SlurReader;
|
|
|
+ private instrument: Instrument;
|
|
|
+ private voiceGeneratorsDict: { [n: number]: VoiceGenerator; } = {};
|
|
|
+ private staffMainVoiceGeneratorDict: { [staffId: number]: 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: [number, AbstractNotationInstruction][] = [];
|
|
|
+ private openChordSymbolContainer: ChordSymbolContainer;
|
|
|
+ // (*) private expressionReaders: ExpressionReader[];
|
|
|
+ private currentVoiceGenerator: VoiceGenerator;
|
|
|
+ //private openSlurDict: { [n: number]: Slur; } = {};
|
|
|
+ private maxTieNoteFraction: Fraction;
|
|
|
|
|
|
- public get ActiveKey(): KeyInstruction {
|
|
|
- return this.activeKey;
|
|
|
- }
|
|
|
+ public get ActiveKey(): KeyInstruction {
|
|
|
+ return this.activeKey;
|
|
|
+ }
|
|
|
|
|
|
- public get MaxTieNoteFraction(): Fraction {
|
|
|
- return this.maxTieNoteFraction;
|
|
|
- }
|
|
|
+ public get MaxTieNoteFraction(): Fraction {
|
|
|
+ return this.maxTieNoteFraction;
|
|
|
+ }
|
|
|
|
|
|
- public get ActiveRhythm(): RhythmInstruction {
|
|
|
- return this.activeRhythm;
|
|
|
- }
|
|
|
+ public get ActiveRhythm(): RhythmInstruction {
|
|
|
+ return this.activeRhythm;
|
|
|
+ }
|
|
|
|
|
|
- public set ActiveRhythm(value: RhythmInstruction) {
|
|
|
- this.activeRhythm = value;
|
|
|
- }
|
|
|
+ public set ActiveRhythm(value: RhythmInstruction) {
|
|
|
+ this.activeRhythm = value;
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Main CreateSheet: read the next XML Measure and save all data to the given [[SourceMeasure]].
|
|
|
- * @param currentMeasure
|
|
|
- * @param measureStartAbsoluteTimestamp - Using this instead of currentMeasure.AbsoluteTimestamp as it isn't set yet
|
|
|
- * @param guitarPro
|
|
|
- * @returns {boolean}
|
|
|
- */
|
|
|
- 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 !== undefined) {
|
|
|
- // this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
|
|
|
- //}
|
|
|
- let currentFraction: Fraction = new Fraction(0, 1);
|
|
|
- let previousFraction: Fraction = new Fraction(0, 1);
|
|
|
- let divisionsException: boolean = false;
|
|
|
- this.maxTieNoteFraction = new Fraction(0, 1);
|
|
|
- let lastNoteWasGrace: boolean = false;
|
|
|
- try {
|
|
|
- let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[this.currentXmlMeasureIndex].elements();
|
|
|
- for (let xmlNode of xmlMeasureListArr) {
|
|
|
- if (xmlNode.name === "note") {
|
|
|
- if (xmlNode.hasAttributes && xmlNode.attribute("print-object") && xmlNode.attribute("print-spacing")) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- let noteStaff: number = 1;
|
|
|
- if (this.instrument.Staves.length > 1) {
|
|
|
- if (xmlNode.element("staff") !== undefined) {
|
|
|
- noteStaff = parseInt(xmlNode.element("staff").value, 10);
|
|
|
- if (isNaN(noteStaff)) {
|
|
|
- Logging.debug("InstrumentReader.readNextXmlMeasure.get staff number");
|
|
|
- noteStaff = 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- this.currentStaff = this.instrument.Staves[noteStaff - 1];
|
|
|
- let isChord: boolean = xmlNode.element("chord") !== undefined;
|
|
|
- if (xmlNode.element("voice") !== undefined) {
|
|
|
- let noteVoice: number = parseInt(xmlNode.element("voice").value, 10);
|
|
|
- this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(noteVoice, noteStaff - 1);
|
|
|
- } else {
|
|
|
- if (!isChord || this.currentVoiceGenerator === undefined) {
|
|
|
- this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(1, noteStaff - 1);
|
|
|
- }
|
|
|
- }
|
|
|
- let noteDivisions: number = 0;
|
|
|
- let noteDuration: Fraction = new Fraction(0, 1);
|
|
|
- let isTuplet: boolean = false;
|
|
|
- if (xmlNode.element("duration") !== undefined) {
|
|
|
- noteDivisions = parseInt(xmlNode.element("duration").value, 10);
|
|
|
- if (!isNaN(noteDivisions)) {
|
|
|
- noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
|
|
|
- if (noteDivisions === 0) {
|
|
|
- noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
|
|
|
- }
|
|
|
- if (xmlNode.element("time-modification") !== undefined) {
|
|
|
- noteDuration = this.getNoteDurationForTuplet(xmlNode);
|
|
|
- isTuplet = true;
|
|
|
- }
|
|
|
- } else {
|
|
|
- let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid Note Duration.");
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let restNote: boolean = xmlNode.element("rest") !== undefined;
|
|
|
- //Logging.log("New note found!", noteDivisions, noteDuration.toString(), restNote);
|
|
|
- let isGraceNote: boolean = xmlNode.element("grace") !== undefined || noteDivisions === 0 || isChord && lastNoteWasGrace;
|
|
|
- let musicTimestamp: Fraction = currentFraction.clone();
|
|
|
- if (isChord) {
|
|
|
- musicTimestamp = previousFraction.clone();
|
|
|
- }
|
|
|
- this.currentStaffEntry = this.currentMeasure.findOrCreateStaffEntry(
|
|
|
- musicTimestamp,
|
|
|
- this.inSourceMeasureInstrumentIndex + noteStaff - 1,
|
|
|
- this.currentStaff
|
|
|
- ).staffEntry;
|
|
|
- //Logging.log("currentStaffEntry", this.currentStaffEntry, this.currentMeasure.VerticalSourceStaffEntryContainers.length);
|
|
|
-
|
|
|
- if (!this.currentVoiceGenerator.hasVoiceEntry() || (!isChord && !isGraceNote && !lastNoteWasGrace) || (!lastNoteWasGrace && isGraceNote)) {
|
|
|
- this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote);
|
|
|
- }
|
|
|
- if (!isGraceNote && !isChord) {
|
|
|
- previousFraction = currentFraction.clone();
|
|
|
- currentFraction.Add(noteDuration);
|
|
|
- }
|
|
|
- if (
|
|
|
- isChord &&
|
|
|
- this.currentStaffEntry !== undefined &&
|
|
|
- this.currentStaffEntry.ParentStaff !== this.currentStaff
|
|
|
- ) {
|
|
|
- this.currentStaffEntry = this.currentVoiceGenerator.checkForStaffEntryLink(
|
|
|
- this.inSourceMeasureInstrumentIndex + noteStaff - 1, this.currentStaff, this.currentStaffEntry, this.currentMeasure
|
|
|
- );
|
|
|
- }
|
|
|
- let beginOfMeasure: boolean = (
|
|
|
- this.currentStaffEntry !== undefined &&
|
|
|
- this.currentStaffEntry.Timestamp !== undefined &&
|
|
|
- this.currentStaffEntry.Timestamp.Equals(new Fraction(0, 1)) && !this.currentStaffEntry.hasNotes()
|
|
|
- );
|
|
|
- this.saveAbstractInstructionList(this.instrument.Staves.length, beginOfMeasure);
|
|
|
- if (this.openChordSymbolContainer !== undefined) {
|
|
|
- this.currentStaffEntry.ChordContainer = this.openChordSymbolContainer;
|
|
|
- this.openChordSymbolContainer = undefined;
|
|
|
- }
|
|
|
- if (this.activeRhythm !== undefined) {
|
|
|
- // (*) 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
|
|
|
- );
|
|
|
- }
|
|
|
- let notationsNode: IXmlElement = xmlNode.element("notations");
|
|
|
- if (notationsNode !== undefined && notationsNode.element("dynamics") !== undefined) {
|
|
|
- // (*) let expressionReader: ExpressionReader = this.expressionReaders[this.readExpressionStaffNumber(xmlNode) - 1];
|
|
|
- //if (expressionReader !== undefined) {
|
|
|
- // 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") {
|
|
|
- let divisionsNode: IXmlElement = xmlNode.element("divisions");
|
|
|
- if (divisionsNode !== undefined) {
|
|
|
- this.divisions = parseInt(divisionsNode.value, 10);
|
|
|
- if (isNaN(this.divisions)) {
|
|
|
- let errorMsg: string = ITextTranslation.translateText( "ReaderErrorMessages/DivisionError",
|
|
|
- "Invalid divisions value at Instrument: ");
|
|
|
- Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
|
|
|
- this.divisions = this.readDivisionsFromNotes();
|
|
|
- if (this.divisions > 0) {
|
|
|
- this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
|
|
|
- } else {
|
|
|
- divisionsException = true;
|
|
|
- throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- if (
|
|
|
- xmlNode.element("divisions") === undefined &&
|
|
|
- this.divisions === 0 &&
|
|
|
- this.currentXmlMeasureIndex === 0
|
|
|
- ) {
|
|
|
- let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
|
|
|
- this.divisions = this.readDivisionsFromNotes();
|
|
|
- if (this.divisions > 0) {
|
|
|
- this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
|
|
|
- } else {
|
|
|
- divisionsException = true;
|
|
|
- throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
|
|
|
- }
|
|
|
- }
|
|
|
- this.addAbstractInstruction(xmlNode, guitarPro);
|
|
|
- if (currentFraction.Equals(new Fraction(0, 1)) &&
|
|
|
- this.isAttributesNodeAtBeginOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
|
|
|
- this.saveAbstractInstructionList(this.instrument.Staves.length, true);
|
|
|
- }
|
|
|
- if (this.isAttributesNodeAtEndOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
|
|
|
- this.saveClefInstructionAtEndOfMeasure();
|
|
|
- }
|
|
|
- } else if (xmlNode.name === "forward") {
|
|
|
- let forFraction: number = parseInt(xmlNode.element("duration").value, 10);
|
|
|
- currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
|
|
|
- } else if (xmlNode.name === "backup") {
|
|
|
- let backFraction: number = parseInt(xmlNode.element("duration").value, 10);
|
|
|
- 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") {
|
|
|
- // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
|
|
|
- // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
|
|
|
- let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
|
|
|
- if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
|
|
|
- relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
|
|
|
- }
|
|
|
- // unused: let handeled: boolean = false;
|
|
|
- // (*) if (this.repetitionInstructionReader !== undefined) {
|
|
|
- // handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
|
|
|
- // relativePositionInMeasure);
|
|
|
- //}
|
|
|
- //if (!handeled) {
|
|
|
- // let expressionReader: ExpressionReader = this.expressionReaders[0];
|
|
|
- // let staffIndex: number = this.readExpressionStaffNumber(xmlNode) - 1;
|
|
|
- // if (staffIndex < this.expressionReaders.length) {
|
|
|
- // expressionReader = this.expressionReaders[staffIndex];
|
|
|
- // }
|
|
|
- // if (expressionReader !== undefined) {
|
|
|
- // if (directionTypeNode.element("octave-shift") !== undefined) {
|
|
|
- // expressionReader.readExpressionParameters(
|
|
|
- // xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, true
|
|
|
- // );
|
|
|
- // expressionReader.addOctaveShift(xmlNode, this.currentMeasure, previousFraction.clone());
|
|
|
- // }
|
|
|
- // 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 !== undefined) {
|
|
|
- // let 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 (let j in this.voiceGeneratorsDict) {
|
|
|
- if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
|
|
|
- let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[j];
|
|
|
- voiceGenerator.checkForOpenBeam();
|
|
|
- voiceGenerator.checkForOpenGraceNotes();
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Main CreateSheet: read the next XML Measure and save all data to the given [[SourceMeasure]].
|
|
|
+ * @param currentMeasure
|
|
|
+ * @param measureStartAbsoluteTimestamp - Using this instead of currentMeasure.AbsoluteTimestamp as it isn't set yet
|
|
|
+ * @param guitarPro
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+ 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 !== undefined) {
|
|
|
+ // this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
|
|
|
+ //}
|
|
|
+ let currentFraction: Fraction = new Fraction(0, 1);
|
|
|
+ let previousFraction: Fraction = new Fraction(0, 1);
|
|
|
+ let divisionsException: boolean = false;
|
|
|
+ this.maxTieNoteFraction = new Fraction(0, 1);
|
|
|
+ let lastNoteWasGrace: boolean = false;
|
|
|
+ try {
|
|
|
+ const xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[this.currentXmlMeasureIndex].elements();
|
|
|
+ for (const xmlNode of xmlMeasureListArr) {
|
|
|
+ if (xmlNode.name === "note") {
|
|
|
+ if (xmlNode.hasAttributes && xmlNode.attribute("print-object") && xmlNode.attribute("print-spacing")) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ let noteStaff: number = 1;
|
|
|
+ if (this.instrument.Staves.length > 1) {
|
|
|
+ if (xmlNode.element("staff") !== undefined) {
|
|
|
+ noteStaff = parseInt(xmlNode.element("staff").value, 10);
|
|
|
+ if (isNaN(noteStaff)) {
|
|
|
+ Logging.debug("InstrumentReader.readNextXmlMeasure.get staff number");
|
|
|
+ noteStaff = 1;
|
|
|
+ }
|
|
|
}
|
|
|
- if (this.currentXmlMeasureIndex === this.xmlMeasureList.length - 1) {
|
|
|
- for (let i: number = 0; i < this.instrument.Staves.length; i++) {
|
|
|
- if (!this.activeClefsHaveBeenInitialized[i]) {
|
|
|
- this.createDefaultClefInstruction(this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument) + i);
|
|
|
- }
|
|
|
- }
|
|
|
- if (!this.activeKeyHasBeenInitialized) {
|
|
|
- this.createDefaultKeyInstruction();
|
|
|
- }
|
|
|
- // (*)
|
|
|
- //for (let i: number = 0; i < this.expressionReaders.length; i++) {
|
|
|
- // let reader: ExpressionReader = this.expressionReaders[i];
|
|
|
- // if (reader !== undefined) {
|
|
|
- // reader.checkForOpenExpressions(this.currentMeasure, currentFraction);
|
|
|
- // }
|
|
|
- //}
|
|
|
+ }
|
|
|
+
|
|
|
+ this.currentStaff = this.instrument.Staves[noteStaff - 1];
|
|
|
+ const isChord: boolean = xmlNode.element("chord") !== undefined;
|
|
|
+ if (xmlNode.element("voice") !== undefined) {
|
|
|
+ const noteVoice: number = parseInt(xmlNode.element("voice").value, 10);
|
|
|
+ this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(noteVoice, noteStaff - 1);
|
|
|
+ } else {
|
|
|
+ if (!isChord || this.currentVoiceGenerator === undefined) {
|
|
|
+ this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(1, noteStaff - 1);
|
|
|
}
|
|
|
- } catch (e) {
|
|
|
- if (divisionsException) {
|
|
|
- throw new MusicSheetReadingException(e.Message);
|
|
|
+ }
|
|
|
+ let noteDivisions: number = 0;
|
|
|
+ let noteDuration: Fraction = new Fraction(0, 1);
|
|
|
+ let isTuplet: boolean = false;
|
|
|
+ if (xmlNode.element("duration") !== undefined) {
|
|
|
+ noteDivisions = parseInt(xmlNode.element("duration").value, 10);
|
|
|
+ if (!isNaN(noteDivisions)) {
|
|
|
+ noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
|
|
|
+ if (noteDivisions === 0) {
|
|
|
+ noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
|
|
|
+ }
|
|
|
+ if (xmlNode.element("time-modification") !== undefined) {
|
|
|
+ noteDuration = this.getNoteDurationForTuplet(xmlNode);
|
|
|
+ isTuplet = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid Note Duration.");
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
|
|
|
+ continue;
|
|
|
}
|
|
|
- let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MeasureError", "Error while reading Measure.");
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg, e);
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- this.previousMeasure = this.currentMeasure;
|
|
|
- this.currentXmlMeasureIndex += 1;
|
|
|
- return true;
|
|
|
- }
|
|
|
+ const restNote: boolean = xmlNode.element("rest") !== undefined;
|
|
|
+ //Logging.log("New note found!", noteDivisions, noteDuration.toString(), restNote);
|
|
|
+ const isGraceNote: boolean = xmlNode.element("grace") !== undefined || noteDivisions === 0 || isChord && lastNoteWasGrace;
|
|
|
+ let musicTimestamp: Fraction = currentFraction.clone();
|
|
|
+ if (isChord) {
|
|
|
+ musicTimestamp = previousFraction.clone();
|
|
|
+ }
|
|
|
+ this.currentStaffEntry = this.currentMeasure.findOrCreateStaffEntry(
|
|
|
+ musicTimestamp,
|
|
|
+ this.inSourceMeasureInstrumentIndex + noteStaff - 1,
|
|
|
+ this.currentStaff
|
|
|
+ ).staffEntry;
|
|
|
+ //Logging.log("currentStaffEntry", this.currentStaffEntry, this.currentMeasure.VerticalSourceStaffEntryContainers.length);
|
|
|
|
|
|
- public doCalculationsAfterDurationHasBeenSet(): void {
|
|
|
- for (let j in this.voiceGeneratorsDict) {
|
|
|
- if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
|
|
|
- this.voiceGeneratorsDict[j].checkOpenTies();
|
|
|
+ if (!this.currentVoiceGenerator.hasVoiceEntry() || (!isChord && !isGraceNote && !lastNoteWasGrace) || (!lastNoteWasGrace && isGraceNote)) {
|
|
|
+ this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote);
|
|
|
+ }
|
|
|
+ if (!isGraceNote && !isChord) {
|
|
|
+ previousFraction = currentFraction.clone();
|
|
|
+ currentFraction.Add(noteDuration);
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ isChord &&
|
|
|
+ this.currentStaffEntry !== undefined &&
|
|
|
+ this.currentStaffEntry.ParentStaff !== this.currentStaff
|
|
|
+ ) {
|
|
|
+ this.currentStaffEntry = this.currentVoiceGenerator.checkForStaffEntryLink(
|
|
|
+ this.inSourceMeasureInstrumentIndex + noteStaff - 1, this.currentStaff, this.currentStaffEntry, this.currentMeasure
|
|
|
+ );
|
|
|
+ }
|
|
|
+ const beginOfMeasure: boolean = (
|
|
|
+ this.currentStaffEntry !== undefined &&
|
|
|
+ this.currentStaffEntry.Timestamp !== undefined &&
|
|
|
+ this.currentStaffEntry.Timestamp.Equals(new Fraction(0, 1)) && !this.currentStaffEntry.hasNotes()
|
|
|
+ );
|
|
|
+ this.saveAbstractInstructionList(this.instrument.Staves.length, beginOfMeasure);
|
|
|
+ if (this.openChordSymbolContainer !== undefined) {
|
|
|
+ this.currentStaffEntry.ChordContainer = this.openChordSymbolContainer;
|
|
|
+ this.openChordSymbolContainer = undefined;
|
|
|
+ }
|
|
|
+ if (this.activeRhythm !== undefined) {
|
|
|
+ // (*) this.musicSheet.SheetPlaybackSetting.Rhythm = this.activeRhythm.Rhythm;
|
|
|
+ }
|
|
|
+ if (isTuplet) {
|
|
|
+ this.currentVoiceGenerator.read(
|
|
|
+ xmlNode, noteDuration, restNote, isGraceNote,
|
|
|
+ this.currentStaffEntry, this.currentMeasure,
|
|
|
+ measureStartAbsoluteTimestamp,
|
|
|
+ this.maxTieNoteFraction, isChord, guitarPro
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ this.currentVoiceGenerator.read(
|
|
|
+ xmlNode, new Fraction(noteDivisions, 4 * this.divisions),
|
|
|
+ restNote, isGraceNote, this.currentStaffEntry,
|
|
|
+ this.currentMeasure, measureStartAbsoluteTimestamp,
|
|
|
+ this.maxTieNoteFraction, isChord, guitarPro
|
|
|
+ );
|
|
|
+ }
|
|
|
+ const notationsNode: IXmlElement = xmlNode.element("notations");
|
|
|
+ if (notationsNode !== undefined && notationsNode.element("dynamics") !== undefined) {
|
|
|
+ // (*) let expressionReader: ExpressionReader = this.expressionReaders[this.readExpressionStaffNumber(xmlNode) - 1];
|
|
|
+ //if (expressionReader !== undefined) {
|
|
|
+ // 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") {
|
|
|
+ const divisionsNode: IXmlElement = xmlNode.element("divisions");
|
|
|
+ if (divisionsNode !== undefined) {
|
|
|
+ this.divisions = parseInt(divisionsNode.value, 10);
|
|
|
+ if (isNaN(this.divisions)) {
|
|
|
+ const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError",
|
|
|
+ "Invalid divisions value at Instrument: ");
|
|
|
+ Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
|
|
|
+ this.divisions = this.readDivisionsFromNotes();
|
|
|
+ if (this.divisions > 0) {
|
|
|
+ this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
|
|
|
+ } else {
|
|
|
+ divisionsException = true;
|
|
|
+ throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- /**
|
|
|
- * Get or create the passing [[VoiceGenerator]].
|
|
|
- * @param voiceId
|
|
|
- * @param staffId
|
|
|
- * @returns {VoiceGenerator}
|
|
|
- */
|
|
|
- private getOrCreateVoiceGenerator(voiceId: number, staffId: number): VoiceGenerator {
|
|
|
- let staff: Staff = this.instrument.Staves[staffId];
|
|
|
- let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[voiceId];
|
|
|
- if (voiceGenerator !== undefined) {
|
|
|
- if (staff.Voices.indexOf(voiceGenerator.GetVoice) === -1) {
|
|
|
- staff.Voices.push(voiceGenerator.GetVoice);
|
|
|
- }
|
|
|
- } else {
|
|
|
- let mainVoiceGenerator: VoiceGenerator = this.staffMainVoiceGeneratorDict[staffId];
|
|
|
- if (mainVoiceGenerator !== undefined) {
|
|
|
- voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader, mainVoiceGenerator.GetVoice);
|
|
|
- staff.Voices.push(voiceGenerator.GetVoice);
|
|
|
- this.voiceGeneratorsDict[voiceId] = voiceGenerator;
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ xmlNode.element("divisions") === undefined &&
|
|
|
+ this.divisions === 0 &&
|
|
|
+ this.currentXmlMeasureIndex === 0
|
|
|
+ ) {
|
|
|
+ const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
|
|
|
+ this.divisions = this.readDivisionsFromNotes();
|
|
|
+ if (this.divisions > 0) {
|
|
|
+ this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
|
|
|
} else {
|
|
|
- voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader);
|
|
|
- staff.Voices.push(voiceGenerator.GetVoice);
|
|
|
- this.voiceGeneratorsDict[voiceId] = voiceGenerator;
|
|
|
- this.staffMainVoiceGeneratorDict[staffId] = voiceGenerator;
|
|
|
+ divisionsException = true;
|
|
|
+ throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
|
|
|
}
|
|
|
+ }
|
|
|
+ this.addAbstractInstruction(xmlNode, guitarPro);
|
|
|
+ if (currentFraction.Equals(new Fraction(0, 1)) &&
|
|
|
+ this.isAttributesNodeAtBeginOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
|
|
|
+ this.saveAbstractInstructionList(this.instrument.Staves.length, true);
|
|
|
+ }
|
|
|
+ if (this.isAttributesNodeAtEndOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
|
|
|
+ this.saveClefInstructionAtEndOfMeasure();
|
|
|
+ }
|
|
|
+ } else if (xmlNode.name === "forward") {
|
|
|
+ const forFraction: number = parseInt(xmlNode.element("duration").value, 10);
|
|
|
+ currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
|
|
|
+ } else if (xmlNode.name === "backup") {
|
|
|
+ const backFraction: number = parseInt(xmlNode.element("duration").value, 10);
|
|
|
+ currentFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
|
|
|
+ if (currentFraction.IsNegative()) {
|
|
|
+ currentFraction = new Fraction(0, 1);
|
|
|
+ }
|
|
|
+ previousFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
|
|
|
+ if (previousFraction.IsNegative()) {
|
|
|
+ previousFraction = new Fraction(0, 1);
|
|
|
+ }
|
|
|
+ } else if (xmlNode.name === "direction") {
|
|
|
+ // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
|
|
|
+ // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
|
|
|
+ // let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
|
|
|
+ // if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
|
|
|
+ // relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
|
|
|
+ // }
|
|
|
+ // unused:
|
|
|
+ // let handeled: boolean = false;
|
|
|
+ // if (this.repetitionInstructionReader !== undefined) {
|
|
|
+ // handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
|
|
|
+ // relativePositionInMeasure);
|
|
|
+ //}
|
|
|
+ //if (!handeled) {
|
|
|
+ // let expressionReader: ExpressionReader = this.expressionReaders[0];
|
|
|
+ // let staffIndex: number = this.readExpressionStaffNumber(xmlNode) - 1;
|
|
|
+ // if (staffIndex < this.expressionReaders.length) {
|
|
|
+ // expressionReader = this.expressionReaders[staffIndex];
|
|
|
+ // }
|
|
|
+ // if (expressionReader !== undefined) {
|
|
|
+ // if (directionTypeNode.element("octave-shift") !== undefined) {
|
|
|
+ // expressionReader.readExpressionParameters(
|
|
|
+ // xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, true
|
|
|
+ // );
|
|
|
+ // expressionReader.addOctaveShift(xmlNode, this.currentMeasure, previousFraction.clone());
|
|
|
+ // }
|
|
|
+ // 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 !== undefined) {
|
|
|
+ // let 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);
|
|
|
}
|
|
|
- return voiceGenerator;
|
|
|
+ }
|
|
|
+ for (const j in this.voiceGeneratorsDict) {
|
|
|
+ if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
|
|
|
+ const voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[j];
|
|
|
+ voiceGenerator.checkForOpenBeam();
|
|
|
+ voiceGenerator.checkForOpenGraceNotes();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (this.currentXmlMeasureIndex === this.xmlMeasureList.length - 1) {
|
|
|
+ for (let i: number = 0; i < this.instrument.Staves.length; i++) {
|
|
|
+ if (!this.activeClefsHaveBeenInitialized[i]) {
|
|
|
+ this.createDefaultClefInstruction(this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument) + i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!this.activeKeyHasBeenInitialized) {
|
|
|
+ this.createDefaultKeyInstruction();
|
|
|
+ }
|
|
|
+ // (*)
|
|
|
+ //for (let i: number = 0; i < this.expressionReaders.length; i++) {
|
|
|
+ // let reader: ExpressionReader = this.expressionReaders[i];
|
|
|
+ // if (reader !== undefined) {
|
|
|
+ // reader.checkForOpenExpressions(this.currentMeasure, currentFraction);
|
|
|
+ // }
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ if (divisionsException) {
|
|
|
+ throw new MusicSheetReadingException(e.Message);
|
|
|
+ }
|
|
|
+ const errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MeasureError", "Error while reading Measure.");
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg, e);
|
|
|
}
|
|
|
|
|
|
+ this.previousMeasure = this.currentMeasure;
|
|
|
+ this.currentXmlMeasureIndex += 1;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- //private createExpressionGenerators(numberOfStaves: number): void {
|
|
|
- // // (*)
|
|
|
- // //this.expressionReaders = new Array(numberOfStaves);
|
|
|
- // //for (let i: number = 0; i < numberOfStaves; i++) {
|
|
|
- // // this.expressionReaders[i] = MusicSymbolModuleFactory.createExpressionGenerator(this.musicSheet, this.instrument, i + 1);
|
|
|
- // //}
|
|
|
- //}
|
|
|
+ public doCalculationsAfterDurationHasBeenSet(): void {
|
|
|
+ for (const j in this.voiceGeneratorsDict) {
|
|
|
+ if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
|
|
|
+ this.voiceGeneratorsDict[j].checkOpenTies();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Create the default [[ClefInstruction]] for the given staff index.
|
|
|
- * @param staffIndex
|
|
|
- */
|
|
|
- private createDefaultClefInstruction(staffIndex: number): void {
|
|
|
- let first: SourceMeasure;
|
|
|
- if (this.musicSheet.SourceMeasures.length > 0) {
|
|
|
- first = this.musicSheet.SourceMeasures[0];
|
|
|
- } else {
|
|
|
- first = this.currentMeasure;
|
|
|
- }
|
|
|
- let clefInstruction: ClefInstruction = new ClefInstruction(ClefEnum.G, 0, 2);
|
|
|
- let firstStaffEntry: SourceStaffEntry;
|
|
|
- if (first.FirstInstructionsStaffEntries[staffIndex] === undefined) {
|
|
|
- firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- first.FirstInstructionsStaffEntries[staffIndex] = firstStaffEntry;
|
|
|
- } else {
|
|
|
- firstStaffEntry = first.FirstInstructionsStaffEntries[staffIndex];
|
|
|
- firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
- }
|
|
|
- clefInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.Instructions.splice(0, 0, clefInstruction);
|
|
|
+ /**
|
|
|
+ * Get or create the passing [[VoiceGenerator]].
|
|
|
+ * @param voiceId
|
|
|
+ * @param staffId
|
|
|
+ * @returns {VoiceGenerator}
|
|
|
+ */
|
|
|
+ private getOrCreateVoiceGenerator(voiceId: number, staffId: number): VoiceGenerator {
|
|
|
+ const staff: Staff = this.instrument.Staves[staffId];
|
|
|
+ let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[voiceId];
|
|
|
+ if (voiceGenerator !== undefined) {
|
|
|
+ if (staff.Voices.indexOf(voiceGenerator.GetVoice) === -1) {
|
|
|
+ staff.Voices.push(voiceGenerator.GetVoice);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const mainVoiceGenerator: VoiceGenerator = this.staffMainVoiceGeneratorDict[staffId];
|
|
|
+ if (mainVoiceGenerator !== undefined) {
|
|
|
+ voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader, mainVoiceGenerator.GetVoice);
|
|
|
+ staff.Voices.push(voiceGenerator.GetVoice);
|
|
|
+ this.voiceGeneratorsDict[voiceId] = voiceGenerator;
|
|
|
+ } else {
|
|
|
+ voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader);
|
|
|
+ staff.Voices.push(voiceGenerator.GetVoice);
|
|
|
+ this.voiceGeneratorsDict[voiceId] = voiceGenerator;
|
|
|
+ this.staffMainVoiceGeneratorDict[staffId] = voiceGenerator;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return voiceGenerator;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //private createExpressionGenerators(numberOfStaves: number): void {
|
|
|
+ // // (*)
|
|
|
+ // //this.expressionReaders = new Array(numberOfStaves);
|
|
|
+ // //for (let i: number = 0; i < numberOfStaves; i++) {
|
|
|
+ // // this.expressionReaders[i] = MusicSymbolModuleFactory.createExpressionGenerator(this.musicSheet, this.instrument, i + 1);
|
|
|
+ // //}
|
|
|
+ //}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Create the default [[ClefInstruction]] for the given staff index.
|
|
|
+ * @param staffIndex
|
|
|
+ */
|
|
|
+ private createDefaultClefInstruction(staffIndex: number): void {
|
|
|
+ let first: SourceMeasure;
|
|
|
+ if (this.musicSheet.SourceMeasures.length > 0) {
|
|
|
+ first = this.musicSheet.SourceMeasures[0];
|
|
|
+ } else {
|
|
|
+ first = this.currentMeasure;
|
|
|
+ }
|
|
|
+ const clefInstruction: ClefInstruction = new ClefInstruction(ClefEnum.G, 0, 2);
|
|
|
+ let firstStaffEntry: SourceStaffEntry;
|
|
|
+ if (first.FirstInstructionsStaffEntries[staffIndex] === undefined) {
|
|
|
+ firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ first.FirstInstructionsStaffEntries[staffIndex] = firstStaffEntry;
|
|
|
+ } else {
|
|
|
+ firstStaffEntry = first.FirstInstructionsStaffEntries[staffIndex];
|
|
|
+ firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
}
|
|
|
+ clefInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.Instructions.splice(0, 0, clefInstruction);
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Create the default [[KeyInstruction]] in case no [[KeyInstruction]] is given in the whole [[Instrument]].
|
|
|
- */
|
|
|
- private createDefaultKeyInstruction(): void {
|
|
|
- let first: SourceMeasure;
|
|
|
- if (this.musicSheet.SourceMeasures.length > 0) {
|
|
|
- first = this.musicSheet.SourceMeasures[0];
|
|
|
+ /**
|
|
|
+ * Create the default [[KeyInstruction]] in case no [[KeyInstruction]] is given in the whole [[Instrument]].
|
|
|
+ */
|
|
|
+ private createDefaultKeyInstruction(): void {
|
|
|
+ let first: SourceMeasure;
|
|
|
+ if (this.musicSheet.SourceMeasures.length > 0) {
|
|
|
+ first = this.musicSheet.SourceMeasures[0];
|
|
|
+ } else {
|
|
|
+ first = this.currentMeasure;
|
|
|
+ }
|
|
|
+ const keyInstruction: KeyInstruction = new KeyInstruction(undefined, 0, KeyEnum.major);
|
|
|
+ for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + this.instrument.Staves.length; j++) {
|
|
|
+ if (first.FirstInstructionsStaffEntries[j] === undefined) {
|
|
|
+ const firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
|
|
|
+ keyInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.Instructions.push(keyInstruction);
|
|
|
+ } else {
|
|
|
+ const firstStaffEntry: SourceStaffEntry = first.FirstInstructionsStaffEntries[j];
|
|
|
+ keyInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
|
|
|
+ if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
|
|
|
+ firstStaffEntry.Instructions.splice(1, 0, keyInstruction);
|
|
|
} else {
|
|
|
- first = this.currentMeasure;
|
|
|
- }
|
|
|
- let keyInstruction: KeyInstruction = new KeyInstruction(undefined, 0, KeyEnum.major);
|
|
|
- for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + this.instrument.Staves.length; j++) {
|
|
|
- if (first.FirstInstructionsStaffEntries[j] === undefined) {
|
|
|
- let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
|
|
|
- keyInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.Instructions.push(keyInstruction);
|
|
|
- } else {
|
|
|
- let firstStaffEntry: SourceStaffEntry = first.FirstInstructionsStaffEntries[j];
|
|
|
- keyInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
|
|
|
- if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
|
|
|
- firstStaffEntry.Instructions.splice(1, 0, keyInstruction);
|
|
|
- } else {
|
|
|
- firstStaffEntry.Instructions.splice(0, 0, keyInstruction);
|
|
|
- }
|
|
|
- }
|
|
|
+ firstStaffEntry.Instructions.splice(0, 0, keyInstruction);
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Check if the given attributesNode is at the begin of a XmlMeasure.
|
|
|
- * @param parentNode
|
|
|
- * @param attributesNode
|
|
|
- * @returns {boolean}
|
|
|
- */
|
|
|
- private isAttributesNodeAtBeginOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
|
|
|
- let children: IXmlElement[] = parentNode.elements();
|
|
|
- let attributesNodeIndex: number = children.indexOf(attributesNode); // FIXME | 0
|
|
|
- if (attributesNodeIndex > 0 && children[attributesNodeIndex - 1].name === "backup") {
|
|
|
- return true;
|
|
|
- }
|
|
|
- let firstNoteNodeIndex: number = -1;
|
|
|
- for (let i: number = 0; i < children.length; i++) {
|
|
|
- if (children[i].name === "note") {
|
|
|
- firstNoteNodeIndex = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return (attributesNodeIndex < firstNoteNodeIndex && firstNoteNodeIndex > 0) || (firstNoteNodeIndex < 0);
|
|
|
+ /**
|
|
|
+ * Check if the given attributesNode is at the begin of a XmlMeasure.
|
|
|
+ * @param parentNode
|
|
|
+ * @param attributesNode
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+ private isAttributesNodeAtBeginOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
|
|
|
+ const children: IXmlElement[] = parentNode.elements();
|
|
|
+ const attributesNodeIndex: number = children.indexOf(attributesNode); // FIXME | 0
|
|
|
+ if (attributesNodeIndex > 0 && children[attributesNodeIndex - 1].name === "backup") {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ let firstNoteNodeIndex: number = -1;
|
|
|
+ for (let i: number = 0; i < children.length; i++) {
|
|
|
+ if (children[i].name === "note") {
|
|
|
+ firstNoteNodeIndex = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+ return (attributesNodeIndex < firstNoteNodeIndex && firstNoteNodeIndex > 0) || (firstNoteNodeIndex < 0);
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Check if the given attributesNode is at the end of a XmlMeasure.
|
|
|
- * @param parentNode
|
|
|
- * @param attributesNode
|
|
|
- * @returns {boolean}
|
|
|
- */
|
|
|
- private isAttributesNodeAtEndOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
|
|
|
- let childs: IXmlElement[] = parentNode.elements().slice();
|
|
|
- let attributesNodeIndex: number = 0;
|
|
|
- for (let i: number = 0; i < childs.length; i++) {
|
|
|
- if (childs[i] === attributesNode) {
|
|
|
- attributesNodeIndex = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- let nextNoteNodeIndex: number = 0;
|
|
|
- for (let i: number = attributesNodeIndex; i < childs.length; i++) {
|
|
|
- if (childs[i].name === "note") {
|
|
|
- nextNoteNodeIndex = i;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return attributesNodeIndex > nextNoteNodeIndex;
|
|
|
+ /**
|
|
|
+ * Check if the given attributesNode is at the end of a XmlMeasure.
|
|
|
+ * @param parentNode
|
|
|
+ * @param attributesNode
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+ private isAttributesNodeAtEndOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
|
|
|
+ const childs: IXmlElement[] = parentNode.elements().slice();
|
|
|
+ let attributesNodeIndex: number = 0;
|
|
|
+ for (let i: number = 0; i < childs.length; i++) {
|
|
|
+ if (childs[i] === attributesNode) {
|
|
|
+ attributesNodeIndex = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let nextNoteNodeIndex: number = 0;
|
|
|
+ for (let i: number = attributesNodeIndex; i < childs.length; i++) {
|
|
|
+ if (childs[i].name === "note") {
|
|
|
+ nextNoteNodeIndex = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+ return attributesNodeIndex > nextNoteNodeIndex;
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Called only when no noteDuration is given in XML.
|
|
|
- * @param xmlNode
|
|
|
- * @returns {Fraction}
|
|
|
- */
|
|
|
- private getNoteDurationFromTypeNode(xmlNode: IXmlElement): Fraction {
|
|
|
- if (xmlNode.element("type") !== undefined) {
|
|
|
- let typeNode: IXmlElement = xmlNode.element("type");
|
|
|
- if (typeNode !== undefined) {
|
|
|
- let type: string = typeNode.value;
|
|
|
- return this.currentVoiceGenerator.getNoteDurationFromType(type);
|
|
|
- }
|
|
|
- }
|
|
|
- return new Fraction(0, 4 * this.divisions);
|
|
|
+ /**
|
|
|
+ * Called only when no noteDuration is given in XML.
|
|
|
+ * @param xmlNode
|
|
|
+ * @returns {Fraction}
|
|
|
+ */
|
|
|
+ private getNoteDurationFromTypeNode(xmlNode: IXmlElement): Fraction {
|
|
|
+ if (xmlNode.element("type") !== undefined) {
|
|
|
+ const typeNode: IXmlElement = xmlNode.element("type");
|
|
|
+ if (typeNode !== undefined) {
|
|
|
+ const type: string = typeNode.value;
|
|
|
+ return this.currentVoiceGenerator.getNoteDurationFromType(type);
|
|
|
+ }
|
|
|
}
|
|
|
+ return new Fraction(0, 4 * this.divisions);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Add (the three basic) Notation Instructions to a list
|
|
|
+ * @param node
|
|
|
+ * @param guitarPro
|
|
|
+ */
|
|
|
+ private addAbstractInstruction(node: IXmlElement, guitarPro: boolean): void {
|
|
|
+ if (node.element("divisions") !== undefined) {
|
|
|
+ if (node.elements().length === 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const transposeNode: IXmlElement = node.element("transpose");
|
|
|
+ if (transposeNode !== undefined) {
|
|
|
+ const chromaticNode: IXmlElement = transposeNode.element("chromatic");
|
|
|
+ if (chromaticNode !== undefined) {
|
|
|
+ this.instrument.PlaybackTranspose = parseInt(chromaticNode.value, 10);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const clefList: IXmlElement[] = node.elements("clef");
|
|
|
+ let errorMsg: string;
|
|
|
+ if (clefList.length > 0) {
|
|
|
+ for (let idx: number = 0, len: number = clefList.length; idx < len; ++idx) {
|
|
|
+ const nodeList: IXmlElement = clefList[idx];
|
|
|
+ let clefEnum: ClefEnum = ClefEnum.G;
|
|
|
+ let line: number = 2;
|
|
|
+ let staffNumber: number = 1;
|
|
|
+ let clefOctaveOffset: number = 0;
|
|
|
+ const lineNode: IXmlElement = nodeList.element("line");
|
|
|
+ if (lineNode !== undefined) {
|
|
|
+ try {
|
|
|
+ line = parseInt(lineNode.value, 10);
|
|
|
+ } catch (ex) {
|
|
|
+ errorMsg = ITextTranslation.translateText(
|
|
|
+ "ReaderErrorMessages/ClefLineError",
|
|
|
+ "Invalid clef line given -> using default clef line."
|
|
|
+ );
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ line = 2;
|
|
|
+ Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Add (the three basic) Notation Instructions to a list
|
|
|
- * @param node
|
|
|
- * @param guitarPro
|
|
|
- */
|
|
|
- private addAbstractInstruction(node: IXmlElement, guitarPro: boolean): void {
|
|
|
- if (node.element("divisions") !== undefined) {
|
|
|
- if (node.elements().length === 1) {
|
|
|
- return;
|
|
|
- }
|
|
|
}
|
|
|
- let transposeNode: IXmlElement = node.element("transpose");
|
|
|
- if (transposeNode !== undefined) {
|
|
|
- let chromaticNode: IXmlElement = transposeNode.element("chromatic");
|
|
|
- if (chromaticNode !== undefined) {
|
|
|
- this.instrument.PlaybackTranspose = parseInt(chromaticNode.value, 10);
|
|
|
+ const signNode: IXmlElement = nodeList.element("sign");
|
|
|
+ if (signNode !== undefined) {
|
|
|
+ try {
|
|
|
+ clefEnum = ClefEnum[signNode.value];
|
|
|
+ if (!ClefInstruction.isSupportedClef(clefEnum)) {
|
|
|
+ if (clefEnum === ClefEnum.TAB && guitarPro) {
|
|
|
+ clefOctaveOffset = -1;
|
|
|
+ }
|
|
|
+ errorMsg = ITextTranslation.translateText(
|
|
|
+ "ReaderErrorMessages/ClefError",
|
|
|
+ "Unsupported clef found -> using default clef."
|
|
|
+ );
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ clefEnum = ClefEnum.G;
|
|
|
+ line = 2;
|
|
|
}
|
|
|
- }
|
|
|
- let clefList: IXmlElement[] = node.elements("clef");
|
|
|
- let errorMsg: string;
|
|
|
- if (clefList.length > 0) {
|
|
|
- for (let idx: number = 0, len: number = clefList.length; idx < len; ++idx) {
|
|
|
- let nodeList: IXmlElement = clefList[idx];
|
|
|
- let clefEnum: ClefEnum = ClefEnum.G;
|
|
|
- let line: number = 2;
|
|
|
- let staffNumber: number = 1;
|
|
|
- let clefOctaveOffset: number = 0;
|
|
|
- let lineNode: IXmlElement = nodeList.element("line");
|
|
|
- if (lineNode !== undefined) {
|
|
|
- try {
|
|
|
- line = parseInt(lineNode.value, 10);
|
|
|
- } catch (ex) {
|
|
|
- errorMsg = ITextTranslation.translateText(
|
|
|
- "ReaderErrorMessages/ClefLineError",
|
|
|
- "Invalid clef line given -> using default clef line."
|
|
|
- );
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- line = 2;
|
|
|
- Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- let signNode: IXmlElement = nodeList.element("sign");
|
|
|
- if (signNode !== undefined) {
|
|
|
- try {
|
|
|
- clefEnum = ClefEnum[signNode.value];
|
|
|
- if (!ClefInstruction.isSupportedClef(clefEnum)) {
|
|
|
- if (clefEnum === ClefEnum.TAB && guitarPro) {
|
|
|
- clefOctaveOffset = -1;
|
|
|
- }
|
|
|
- errorMsg = ITextTranslation.translateText(
|
|
|
- "ReaderErrorMessages/ClefError",
|
|
|
- "Unsupported clef found -> using default clef."
|
|
|
- );
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- clefEnum = ClefEnum.G;
|
|
|
- line = 2;
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- errorMsg = ITextTranslation.translateText(
|
|
|
- "ReaderErrorMessages/ClefError",
|
|
|
- "Invalid clef found -> using default clef."
|
|
|
- );
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- clefEnum = ClefEnum.G;
|
|
|
- line = 2;
|
|
|
- Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, e);
|
|
|
- }
|
|
|
+ } catch (e) {
|
|
|
+ errorMsg = ITextTranslation.translateText(
|
|
|
+ "ReaderErrorMessages/ClefError",
|
|
|
+ "Invalid clef found -> using default clef."
|
|
|
+ );
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ clefEnum = ClefEnum.G;
|
|
|
+ line = 2;
|
|
|
+ Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, e);
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
- let clefOctaveNode: IXmlElement = nodeList.element("clef-octave-change");
|
|
|
- if (clefOctaveNode !== undefined) {
|
|
|
- try {
|
|
|
- clefOctaveOffset = parseInt(clefOctaveNode.value, 10);
|
|
|
- } catch (e) {
|
|
|
- errorMsg = ITextTranslation.translateText(
|
|
|
- "ReaderErrorMessages/ClefOctaveError",
|
|
|
- "Invalid clef octave found -> using default clef octave."
|
|
|
- );
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- clefOctaveOffset = 0;
|
|
|
- }
|
|
|
+ }
|
|
|
+ const clefOctaveNode: IXmlElement = nodeList.element("clef-octave-change");
|
|
|
+ if (clefOctaveNode !== undefined) {
|
|
|
+ try {
|
|
|
+ clefOctaveOffset = parseInt(clefOctaveNode.value, 10);
|
|
|
+ } catch (e) {
|
|
|
+ errorMsg = ITextTranslation.translateText(
|
|
|
+ "ReaderErrorMessages/ClefOctaveError",
|
|
|
+ "Invalid clef octave found -> using default clef octave."
|
|
|
+ );
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ clefOctaveOffset = 0;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
- if (nodeList.hasAttributes && nodeList.attributes()[0].name === "number") {
|
|
|
- try {
|
|
|
- staffNumber = parseInt(nodeList.attributes()[0].value, 10);
|
|
|
- } catch (err) {
|
|
|
- errorMsg = ITextTranslation.translateText(
|
|
|
- "ReaderErrorMessages/ClefError",
|
|
|
- "Invalid clef found -> using default clef."
|
|
|
- );
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- staffNumber = 1;
|
|
|
- }
|
|
|
- }
|
|
|
+ }
|
|
|
+ if (nodeList.hasAttributes && nodeList.attributes()[0].name === "number") {
|
|
|
+ try {
|
|
|
+ staffNumber = parseInt(nodeList.attributes()[0].value, 10);
|
|
|
+ } catch (err) {
|
|
|
+ errorMsg = ITextTranslation.translateText(
|
|
|
+ "ReaderErrorMessages/ClefError",
|
|
|
+ "Invalid clef found -> using default clef."
|
|
|
+ );
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ staffNumber = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- let clefInstruction: ClefInstruction = new ClefInstruction(clefEnum, clefOctaveOffset, line);
|
|
|
- this.abstractInstructions.push([staffNumber, clefInstruction]);
|
|
|
- }
|
|
|
+ const clefInstruction: ClefInstruction = new ClefInstruction(clefEnum, clefOctaveOffset, line);
|
|
|
+ this.abstractInstructions.push([staffNumber, clefInstruction]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (node.element("key") !== undefined && this.instrument.MidiInstrumentId !== MidiInstrument.Percussion) {
|
|
|
+ let key: number = 0;
|
|
|
+ const keyNode: IXmlElement = node.element("key").element("fifths");
|
|
|
+ if (keyNode !== undefined) {
|
|
|
+ try {
|
|
|
+ key = parseInt(keyNode.value, 10);
|
|
|
+ } catch (ex) {
|
|
|
+ errorMsg = ITextTranslation.translateText(
|
|
|
+ "ReaderErrorMessages/KeyError",
|
|
|
+ "Invalid key found -> set to default."
|
|
|
+ );
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ key = 0;
|
|
|
+ Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
}
|
|
|
- if (node.element("key") !== undefined && this.instrument.MidiInstrumentId !== MidiInstrument.Percussion) {
|
|
|
- let key: number = 0;
|
|
|
- let keyNode: IXmlElement = node.element("key").element("fifths");
|
|
|
- if (keyNode !== undefined) {
|
|
|
- try {
|
|
|
- key = parseInt(keyNode.value, 10);
|
|
|
- } catch (ex) {
|
|
|
- errorMsg = ITextTranslation.translateText(
|
|
|
- "ReaderErrorMessages/KeyError",
|
|
|
- "Invalid key found -> set to default."
|
|
|
- );
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- key = 0;
|
|
|
- Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
- }
|
|
|
|
|
|
- }
|
|
|
- let keyEnum: KeyEnum = KeyEnum.none;
|
|
|
- let modeNode: IXmlElement = node.element("key");
|
|
|
- if (modeNode !== undefined) {
|
|
|
- modeNode = modeNode.element("mode");
|
|
|
- }
|
|
|
- if (modeNode !== undefined) {
|
|
|
- try {
|
|
|
- keyEnum = KeyEnum[modeNode.value];
|
|
|
- } catch (ex) {
|
|
|
- errorMsg = ITextTranslation.translateText(
|
|
|
- "ReaderErrorMessages/KeyError",
|
|
|
- "Invalid key found -> set to default."
|
|
|
- );
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- keyEnum = KeyEnum.major;
|
|
|
- Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
- }
|
|
|
+ }
|
|
|
+ let keyEnum: KeyEnum = KeyEnum.none;
|
|
|
+ let modeNode: IXmlElement = node.element("key");
|
|
|
+ if (modeNode !== undefined) {
|
|
|
+ modeNode = modeNode.element("mode");
|
|
|
+ }
|
|
|
+ if (modeNode !== undefined) {
|
|
|
+ try {
|
|
|
+ keyEnum = KeyEnum[modeNode.value];
|
|
|
+ } catch (ex) {
|
|
|
+ errorMsg = ITextTranslation.translateText(
|
|
|
+ "ReaderErrorMessages/KeyError",
|
|
|
+ "Invalid key found -> set to default."
|
|
|
+ );
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ keyEnum = KeyEnum.major;
|
|
|
+ Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
- let keyInstruction: KeyInstruction = new KeyInstruction(undefined, key, keyEnum);
|
|
|
- this.abstractInstructions.push([1, keyInstruction]);
|
|
|
+ }
|
|
|
+ const keyInstruction: KeyInstruction = new KeyInstruction(undefined, key, keyEnum);
|
|
|
+ this.abstractInstructions.push([1, keyInstruction]);
|
|
|
+ }
|
|
|
+ if (node.element("time") !== undefined) {
|
|
|
+ let symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
|
|
|
+ const timeNode: IXmlElement = node.element("time");
|
|
|
+ if (timeNode !== undefined && timeNode.hasAttributes) {
|
|
|
+ const firstAttr: IXmlAttribute = timeNode.firstAttribute;
|
|
|
+ if (firstAttr.name === "symbol") {
|
|
|
+ if (firstAttr.value === "common") {
|
|
|
+ symbolEnum = RhythmSymbolEnum.COMMON;
|
|
|
+ } else if (firstAttr.value === "cut") {
|
|
|
+ symbolEnum = RhythmSymbolEnum.CUT;
|
|
|
+ }
|
|
|
}
|
|
|
- if (node.element("time") !== undefined) {
|
|
|
- let symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
|
|
|
- let timeNode: IXmlElement = node.element("time");
|
|
|
- if (timeNode !== undefined && timeNode.hasAttributes) {
|
|
|
- let firstAttr: IXmlAttribute = timeNode.firstAttribute;
|
|
|
- if (firstAttr.name === "symbol") {
|
|
|
- if (firstAttr.value === "common") {
|
|
|
- symbolEnum = RhythmSymbolEnum.COMMON;
|
|
|
- } else if (firstAttr.value === "cut") {
|
|
|
- symbolEnum = RhythmSymbolEnum.CUT;
|
|
|
- }
|
|
|
+ }
|
|
|
+ let num: number = 0;
|
|
|
+ let denom: number = 0;
|
|
|
+ const senzaMisura: boolean = (timeNode !== undefined && timeNode.element("senza-misura") !== undefined);
|
|
|
+ const timeList: IXmlElement[] = node.elements("time");
|
|
|
+ const beatsList: IXmlElement[] = [];
|
|
|
+ const typeList: IXmlElement[] = [];
|
|
|
+ for (let idx: number = 0, len: number = timeList.length; idx < len; ++idx) {
|
|
|
+ const xmlNode: IXmlElement = timeList[idx];
|
|
|
+ beatsList.push.apply(beatsList, xmlNode.elements("beats"));
|
|
|
+ typeList.push.apply(typeList, xmlNode.elements("beat-type"));
|
|
|
+ }
|
|
|
+ if (!senzaMisura) {
|
|
|
+ try {
|
|
|
+ if (beatsList !== undefined && beatsList.length > 0 && typeList !== undefined && beatsList.length === typeList.length) {
|
|
|
+ const length: number = beatsList.length;
|
|
|
+ const fractions: Fraction[] = new Array(length);
|
|
|
+ let maxDenom: number = 0;
|
|
|
+ for (let i: number = 0; i < length; i++) {
|
|
|
+ const s: string = beatsList[i].value;
|
|
|
+ let n: number = 0;
|
|
|
+ let d: number = 0;
|
|
|
+ if (s.indexOf("+") !== -1) {
|
|
|
+ const numbers: string[] = s.split("+");
|
|
|
+ for (let idx: number = 0, len: number = numbers.length; idx < len; ++idx) {
|
|
|
+ n += parseInt(numbers[idx], 10);
|
|
|
}
|
|
|
+ } else {
|
|
|
+ n = parseInt(s, 10);
|
|
|
+ }
|
|
|
+ d = parseInt(typeList[i].value, 10);
|
|
|
+ maxDenom = Math.max(maxDenom, d);
|
|
|
+ fractions[i] = new Fraction(n, d, 0, false);
|
|
|
}
|
|
|
- let num: number = 0;
|
|
|
- let denom: number = 0;
|
|
|
- let senzaMisura: boolean = (timeNode !== undefined && timeNode.element("senza-misura") !== undefined);
|
|
|
- let timeList: IXmlElement[] = node.elements("time");
|
|
|
- let beatsList: IXmlElement[] = [];
|
|
|
- let typeList: IXmlElement[] = [];
|
|
|
- for (let idx: number = 0, len: number = timeList.length; idx < len; ++idx) {
|
|
|
- let xmlNode: IXmlElement = timeList[idx];
|
|
|
- beatsList.push.apply(beatsList, xmlNode.elements("beats"));
|
|
|
- typeList.push.apply(typeList, xmlNode.elements("beat-type"));
|
|
|
+ for (let i: number = 0; i < length; i++) {
|
|
|
+ if (fractions[i].Denominator === maxDenom) {
|
|
|
+ num += fractions[i].Numerator;
|
|
|
+ } else {
|
|
|
+ num += (maxDenom / fractions[i].Denominator) * fractions[i].Numerator;
|
|
|
+ }
|
|
|
}
|
|
|
- if (!senzaMisura) {
|
|
|
- try {
|
|
|
- if (beatsList !== undefined && beatsList.length > 0 && typeList !== undefined && beatsList.length === typeList.length) {
|
|
|
- let length: number = beatsList.length;
|
|
|
- let fractions: Fraction[] = new Array(length);
|
|
|
- let maxDenom: number = 0;
|
|
|
- for (let i: number = 0; i < length; i++) {
|
|
|
- let s: string = beatsList[i].value;
|
|
|
- let n: number = 0;
|
|
|
- let d: number = 0;
|
|
|
- if (s.indexOf("+") !== -1) {
|
|
|
- let numbers: string[] = s.split("+");
|
|
|
- for (let idx: number = 0, len: number = numbers.length; idx < len; ++idx) {
|
|
|
- n += parseInt(numbers[idx], 10);
|
|
|
- }
|
|
|
- } else {
|
|
|
- n = parseInt(s, 10);
|
|
|
- }
|
|
|
- d = parseInt(typeList[i].value, 10);
|
|
|
- maxDenom = Math.max(maxDenom, d);
|
|
|
- fractions[i] = new Fraction(n, d, false);
|
|
|
- }
|
|
|
- for (let 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 = parseInt(node.element("time").element("beats").value, 10);
|
|
|
- denom = parseInt(node.element("time").element("beat-type").value, 10);
|
|
|
- }
|
|
|
- } catch (ex) {
|
|
|
- errorMsg = ITextTranslation.translateText("ReaderErrorMessages/RhythmError", "Invalid rhythm found -> set to default.");
|
|
|
- this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
- num = 4;
|
|
|
- denom = 4;
|
|
|
- Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
- }
|
|
|
+ denom = maxDenom;
|
|
|
+ } else {
|
|
|
+ num = parseInt(node.element("time").element("beats").value, 10);
|
|
|
+ denom = parseInt(node.element("time").element("beat-type").value, 10);
|
|
|
+ }
|
|
|
+ } catch (ex) {
|
|
|
+ errorMsg = ITextTranslation.translateText("ReaderErrorMessages/RhythmError", "Invalid rhythm found -> set to default.");
|
|
|
+ this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
|
|
|
+ num = 4;
|
|
|
+ denom = 4;
|
|
|
+ Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
|
|
|
+ }
|
|
|
|
|
|
- if ((num === 4 && denom === 4) || (num === 2 && denom === 2)) {
|
|
|
- symbolEnum = RhythmSymbolEnum.NONE;
|
|
|
- }
|
|
|
- this.abstractInstructions.push([1, new RhythmInstruction(
|
|
|
- new Fraction(num, denom, false), num, denom, symbolEnum
|
|
|
- )]);
|
|
|
- } else {
|
|
|
- this.abstractInstructions.push([1, new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE)]);
|
|
|
- }
|
|
|
+ if ((num === 4 && denom === 4) || (num === 2 && denom === 2)) {
|
|
|
+ symbolEnum = RhythmSymbolEnum.NONE;
|
|
|
}
|
|
|
+ this.abstractInstructions.push([1, new RhythmInstruction(
|
|
|
+ new Fraction(num, denom, 0, false), symbolEnum
|
|
|
+ )]);
|
|
|
+ } else {
|
|
|
+ this.abstractInstructions.push([1, new RhythmInstruction(new Fraction(4, 4, 0, false), RhythmSymbolEnum.NONE)]);
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Save the current AbstractInstructions to the corresponding [[StaffEntry]]s.
|
|
|
- * @param numberOfStaves
|
|
|
- * @param beginOfMeasure
|
|
|
- */
|
|
|
- private saveAbstractInstructionList(numberOfStaves: number, beginOfMeasure: boolean): void {
|
|
|
- for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
|
|
|
- let pair: [number, AbstractNotationInstruction] = this.abstractInstructions[i];
|
|
|
- let key: number = pair[0];
|
|
|
- let value: AbstractNotationInstruction = pair[1];
|
|
|
- if (value instanceof ClefInstruction) {
|
|
|
- let clefInstruction: ClefInstruction = <ClefInstruction>value;
|
|
|
- if (this.currentXmlMeasureIndex === 0 || (key <= this.activeClefs.length && clefInstruction !== this.activeClefs[key - 1])) {
|
|
|
- if (!beginOfMeasure && this.currentStaffEntry !== undefined && !this.currentStaffEntry.hasNotes() && key - 1
|
|
|
- === this.instrument.Staves.indexOf(this.currentStaffEntry.ParentStaff)) {
|
|
|
- let newClefInstruction: ClefInstruction = clefInstruction;
|
|
|
- newClefInstruction.Parent = this.currentStaffEntry;
|
|
|
- this.currentStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
- this.currentStaffEntry.Instructions.push(newClefInstruction);
|
|
|
- this.activeClefs[key - 1] = clefInstruction;
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
- } else if (beginOfMeasure) {
|
|
|
- let firstStaffEntry: SourceStaffEntry;
|
|
|
- if (this.currentMeasure !== undefined) {
|
|
|
- let newClefInstruction: ClefInstruction = clefInstruction;
|
|
|
- let sseIndex: number = this.inSourceMeasureInstrumentIndex + key - 1;
|
|
|
- let firstSse: SourceStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[sseIndex];
|
|
|
- if (this.currentXmlMeasureIndex === 0) {
|
|
|
- if (firstSse === undefined) {
|
|
|
- firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- this.currentMeasure.FirstInstructionsStaffEntries[sseIndex] = firstStaffEntry;
|
|
|
- newClefInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.Instructions.push(newClefInstruction);
|
|
|
- this.activeClefsHaveBeenInitialized[key - 1] = true;
|
|
|
- } else if (this.currentMeasure.FirstInstructionsStaffEntries[sseIndex]
|
|
|
- !==
|
|
|
- undefined && !(firstSse.Instructions[0] instanceof ClefInstruction)) {
|
|
|
- firstStaffEntry = firstSse;
|
|
|
- newClefInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
- firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
|
|
|
- this.activeClefsHaveBeenInitialized[key - 1] = true;
|
|
|
- } else {
|
|
|
- let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- this.currentMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
|
|
|
- newClefInstruction.Parent = lastStaffEntry;
|
|
|
- lastStaffEntry.Instructions.push(newClefInstruction);
|
|
|
- }
|
|
|
- } else if (!this.activeClefsHaveBeenInitialized[key - 1]) {
|
|
|
- let first: SourceMeasure = this.musicSheet.SourceMeasures[0];
|
|
|
- if (first.FirstInstructionsStaffEntries[sseIndex] === undefined) {
|
|
|
- firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- } else {
|
|
|
- firstStaffEntry = first.FirstInstructionsStaffEntries[sseIndex];
|
|
|
- firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
- }
|
|
|
- newClefInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
|
|
|
- this.activeClefsHaveBeenInitialized[key - 1] = true;
|
|
|
- } else {
|
|
|
- let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- this.previousMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
|
|
|
- newClefInstruction.Parent = lastStaffEntry;
|
|
|
- lastStaffEntry.Instructions.push(newClefInstruction);
|
|
|
- }
|
|
|
- this.activeClefs[key - 1] = clefInstruction;
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
- }
|
|
|
- }
|
|
|
- } else if (key <= this.activeClefs.length && clefInstruction === this.activeClefs[key - 1]) {
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
+ /**
|
|
|
+ * Save the current AbstractInstructions to the corresponding [[StaffEntry]]s.
|
|
|
+ * @param numberOfStaves
|
|
|
+ * @param beginOfMeasure
|
|
|
+ */
|
|
|
+ private saveAbstractInstructionList(numberOfStaves: number, beginOfMeasure: boolean): void {
|
|
|
+ for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
|
|
|
+ const pair: [number, AbstractNotationInstruction] = this.abstractInstructions[i];
|
|
|
+ const key: number = pair[0];
|
|
|
+ const value: AbstractNotationInstruction = pair[1];
|
|
|
+ if (value instanceof ClefInstruction) {
|
|
|
+ const clefInstruction: ClefInstruction = <ClefInstruction>value;
|
|
|
+ if (this.currentXmlMeasureIndex === 0 || (key <= this.activeClefs.length && clefInstruction !== this.activeClefs[key - 1])) {
|
|
|
+ if (!beginOfMeasure && this.currentStaffEntry !== undefined && !this.currentStaffEntry.hasNotes() && key - 1
|
|
|
+ === this.instrument.Staves.indexOf(this.currentStaffEntry.ParentStaff)) {
|
|
|
+ const newClefInstruction: ClefInstruction = clefInstruction;
|
|
|
+ newClefInstruction.Parent = this.currentStaffEntry;
|
|
|
+ this.currentStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
+ this.currentStaffEntry.Instructions.push(newClefInstruction);
|
|
|
+ this.activeClefs[key - 1] = clefInstruction;
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
+ } else if (beginOfMeasure) {
|
|
|
+ let firstStaffEntry: SourceStaffEntry;
|
|
|
+ if (this.currentMeasure !== undefined) {
|
|
|
+ const newClefInstruction: ClefInstruction = clefInstruction;
|
|
|
+ const sseIndex: number = this.inSourceMeasureInstrumentIndex + key - 1;
|
|
|
+ const firstSse: SourceStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[sseIndex];
|
|
|
+ if (this.currentXmlMeasureIndex === 0) {
|
|
|
+ if (firstSse === undefined) {
|
|
|
+ firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ this.currentMeasure.FirstInstructionsStaffEntries[sseIndex] = firstStaffEntry;
|
|
|
+ newClefInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.Instructions.push(newClefInstruction);
|
|
|
+ this.activeClefsHaveBeenInitialized[key - 1] = true;
|
|
|
+ } else if (this.currentMeasure.FirstInstructionsStaffEntries[sseIndex]
|
|
|
+ !==
|
|
|
+ undefined && !(firstSse.Instructions[0] instanceof ClefInstruction)) {
|
|
|
+ firstStaffEntry = firstSse;
|
|
|
+ newClefInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
+ firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
|
|
|
+ this.activeClefsHaveBeenInitialized[key - 1] = true;
|
|
|
+ } else {
|
|
|
+ const lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ this.currentMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
|
|
|
+ newClefInstruction.Parent = lastStaffEntry;
|
|
|
+ lastStaffEntry.Instructions.push(newClefInstruction);
|
|
|
}
|
|
|
- }
|
|
|
- if (value instanceof KeyInstruction) {
|
|
|
- let keyInstruction: KeyInstruction = <KeyInstruction>value;
|
|
|
- if (this.activeKey === undefined || this.activeKey.Key !== keyInstruction.Key) {
|
|
|
- this.activeKey = keyInstruction;
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
- let 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 !== undefined) {
|
|
|
- for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
|
|
|
- let newKeyInstruction: KeyInstruction = keyInstruction;
|
|
|
- if (sourceMeasure.FirstInstructionsStaffEntries[j] === undefined) {
|
|
|
- let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
|
|
|
- newKeyInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.Instructions.push(newKeyInstruction);
|
|
|
- } else {
|
|
|
- let firstStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[j];
|
|
|
- newKeyInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
|
|
|
- if (firstStaffEntry.Instructions.length === 0) {
|
|
|
- firstStaffEntry.Instructions.push(newKeyInstruction);
|
|
|
- } else {
|
|
|
- if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
|
|
|
- firstStaffEntry.Instructions.splice(1, 0, newKeyInstruction);
|
|
|
- } else {
|
|
|
- firstStaffEntry.Instructions.splice(0, 0, newKeyInstruction);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ } else if (!this.activeClefsHaveBeenInitialized[key - 1]) {
|
|
|
+ const first: SourceMeasure = this.musicSheet.SourceMeasures[0];
|
|
|
+ if (first.FirstInstructionsStaffEntries[sseIndex] === undefined) {
|
|
|
+ firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
} else {
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
+ firstStaffEntry = first.FirstInstructionsStaffEntries[sseIndex];
|
|
|
+ firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
|
|
|
}
|
|
|
+ newClefInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
|
|
|
+ this.activeClefsHaveBeenInitialized[key - 1] = true;
|
|
|
+ } else {
|
|
|
+ const lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ this.previousMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
|
|
|
+ newClefInstruction.Parent = lastStaffEntry;
|
|
|
+ lastStaffEntry.Instructions.push(newClefInstruction);
|
|
|
+ }
|
|
|
+ this.activeClefs[key - 1] = clefInstruction;
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
}
|
|
|
- if (value instanceof RhythmInstruction) {
|
|
|
- let rhythmInstruction: RhythmInstruction = <RhythmInstruction>value;
|
|
|
- if (this.activeRhythm === undefined || this.activeRhythm !== rhythmInstruction) {
|
|
|
- this.activeRhythm = rhythmInstruction;
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
- if (this.currentMeasure !== undefined) {
|
|
|
- for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
|
|
|
- let newRhythmInstruction: RhythmInstruction = rhythmInstruction;
|
|
|
- let firstStaffEntry: SourceStaffEntry;
|
|
|
- if (this.currentMeasure.FirstInstructionsStaffEntries[j] === undefined) {
|
|
|
- firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- this.currentMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
|
|
|
- } else {
|
|
|
- firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[j];
|
|
|
- firstStaffEntry.removeFirstInstructionOfTypeRhythmInstruction();
|
|
|
- }
|
|
|
- newRhythmInstruction.Parent = firstStaffEntry;
|
|
|
- firstStaffEntry.Instructions.push(newRhythmInstruction);
|
|
|
- }
|
|
|
- }
|
|
|
+ }
|
|
|
+ } else if (key <= this.activeClefs.length && clefInstruction === this.activeClefs[key - 1]) {
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (value instanceof KeyInstruction) {
|
|
|
+ const keyInstruction: KeyInstruction = <KeyInstruction>value;
|
|
|
+ if (this.activeKey === undefined || this.activeKey.Key !== keyInstruction.Key) {
|
|
|
+ this.activeKey = keyInstruction;
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
+ let 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 !== undefined) {
|
|
|
+ for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
|
|
|
+ const newKeyInstruction: KeyInstruction = keyInstruction;
|
|
|
+ if (sourceMeasure.FirstInstructionsStaffEntries[j] === undefined) {
|
|
|
+ const firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
|
|
|
+ newKeyInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.Instructions.push(newKeyInstruction);
|
|
|
+ } else {
|
|
|
+ const firstStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[j];
|
|
|
+ newKeyInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
|
|
|
+ if (firstStaffEntry.Instructions.length === 0) {
|
|
|
+ firstStaffEntry.Instructions.push(newKeyInstruction);
|
|
|
} else {
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
+ if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
|
|
|
+ firstStaffEntry.Instructions.splice(1, 0, newKeyInstruction);
|
|
|
+ } else {
|
|
|
+ firstStaffEntry.Instructions.splice(0, 0, newKeyInstruction);
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
}
|
|
|
+ }
|
|
|
+ if (value instanceof RhythmInstruction) {
|
|
|
+ const rhythmInstruction: RhythmInstruction = <RhythmInstruction>value;
|
|
|
+ if (this.activeRhythm === undefined || this.activeRhythm !== rhythmInstruction) {
|
|
|
+ this.activeRhythm = rhythmInstruction;
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
+ if (this.currentMeasure !== undefined) {
|
|
|
+ for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
|
|
|
+ const newRhythmInstruction: RhythmInstruction = rhythmInstruction;
|
|
|
+ let firstStaffEntry: SourceStaffEntry;
|
|
|
+ if (this.currentMeasure.FirstInstructionsStaffEntries[j] === undefined) {
|
|
|
+ firstStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ this.currentMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
|
|
|
+ } else {
|
|
|
+ firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[j];
|
|
|
+ firstStaffEntry.removeFirstInstructionOfTypeRhythmInstruction();
|
|
|
+ }
|
|
|
+ newRhythmInstruction.Parent = firstStaffEntry;
|
|
|
+ firstStaffEntry.Instructions.push(newRhythmInstruction);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * Save any ClefInstruction given - exceptionally - at the end of the currentMeasure.
|
|
|
- */
|
|
|
- private saveClefInstructionAtEndOfMeasure(): void {
|
|
|
- for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
|
|
|
- let key: number = this.abstractInstructions[i][0];
|
|
|
- let value: AbstractNotationInstruction = this.abstractInstructions[i][1];
|
|
|
- if (value instanceof ClefInstruction) {
|
|
|
- let clefInstruction: ClefInstruction = <ClefInstruction>value;
|
|
|
- if (
|
|
|
- (this.activeClefs[key - 1] === undefined) ||
|
|
|
- (clefInstruction.ClefType !== this.activeClefs[key - 1].ClefType || (
|
|
|
- clefInstruction.ClefType === this.activeClefs[key - 1].ClefType &&
|
|
|
- clefInstruction.Line !== this.activeClefs[key - 1].Line
|
|
|
- ))) {
|
|
|
- let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
- this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
|
|
|
- let newClefInstruction: ClefInstruction = clefInstruction;
|
|
|
- newClefInstruction.Parent = lastStaffEntry;
|
|
|
- lastStaffEntry.Instructions.push(newClefInstruction);
|
|
|
- this.activeClefs[key - 1] = clefInstruction;
|
|
|
- this.abstractInstructions.splice(i, 1);
|
|
|
- }
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Save any ClefInstruction given - exceptionally - at the end of the currentMeasure.
|
|
|
+ */
|
|
|
+ private saveClefInstructionAtEndOfMeasure(): void {
|
|
|
+ for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
|
|
|
+ const key: number = this.abstractInstructions[i][0];
|
|
|
+ const value: AbstractNotationInstruction = this.abstractInstructions[i][1];
|
|
|
+ if (value instanceof ClefInstruction) {
|
|
|
+ const clefInstruction: ClefInstruction = <ClefInstruction>value;
|
|
|
+ if (
|
|
|
+ (this.activeClefs[key - 1] === undefined) ||
|
|
|
+ (clefInstruction.ClefType !== this.activeClefs[key - 1].ClefType || (
|
|
|
+ clefInstruction.ClefType === this.activeClefs[key - 1].ClefType &&
|
|
|
+ clefInstruction.Line !== this.activeClefs[key - 1].Line
|
|
|
+ ))) {
|
|
|
+ const lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
|
|
|
+ this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
|
|
|
+ const newClefInstruction: ClefInstruction = clefInstruction;
|
|
|
+ newClefInstruction.Parent = lastStaffEntry;
|
|
|
+ lastStaffEntry.Instructions.push(newClefInstruction);
|
|
|
+ this.activeClefs[key - 1] = clefInstruction;
|
|
|
+ this.abstractInstructions.splice(i, 1);
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
- * In case of a [[Tuplet]], read NoteDuration from type.
|
|
|
- * @param xmlNode
|
|
|
- * @returns {Fraction}
|
|
|
- */
|
|
|
- private getNoteDurationForTuplet(xmlNode: IXmlElement): Fraction {
|
|
|
- let duration: Fraction = new Fraction(0, 1);
|
|
|
- let typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
|
|
|
- if (xmlNode.element("time-modification") !== undefined) {
|
|
|
- let time: IXmlElement = xmlNode.element("time-modification");
|
|
|
- if (time !== undefined) {
|
|
|
- if (time.element("actual-notes") !== undefined && time.element("normal-notes") !== undefined) {
|
|
|
- let actualNotes: IXmlElement = time.element("actual-notes");
|
|
|
- let normalNotes: IXmlElement = time.element("normal-notes");
|
|
|
- if (actualNotes !== undefined && normalNotes !== undefined) {
|
|
|
- let actual: number = parseInt(actualNotes.value, 10);
|
|
|
- let normal: number = parseInt(normalNotes.value, 10);
|
|
|
- duration = new Fraction(normal * typeDuration.Numerator, actual * typeDuration.Denominator);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * In case of a [[Tuplet]], read NoteDuration from type.
|
|
|
+ * @param xmlNode
|
|
|
+ * @returns {Fraction}
|
|
|
+ */
|
|
|
+ private getNoteDurationForTuplet(xmlNode: IXmlElement): Fraction {
|
|
|
+ let duration: Fraction = new Fraction(0, 1);
|
|
|
+ const typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
|
|
|
+ if (xmlNode.element("time-modification") !== undefined) {
|
|
|
+ const time: IXmlElement = xmlNode.element("time-modification");
|
|
|
+ if (time !== undefined) {
|
|
|
+ if (time.element("actual-notes") !== undefined && time.element("normal-notes") !== undefined) {
|
|
|
+ const actualNotes: IXmlElement = time.element("actual-notes");
|
|
|
+ const normalNotes: IXmlElement = time.element("normal-notes");
|
|
|
+ if (actualNotes !== undefined && normalNotes !== undefined) {
|
|
|
+ const actual: number = parseInt(actualNotes.value, 10);
|
|
|
+ const normal: number = parseInt(normalNotes.value, 10);
|
|
|
+ duration = new Fraction(normal * typeDuration.Numerator, actual * typeDuration.Denominator);
|
|
|
+ }
|
|
|
}
|
|
|
- return duration;
|
|
|
+ }
|
|
|
}
|
|
|
+ return duration;
|
|
|
+ }
|
|
|
|
|
|
- //private readExpressionStaffNumber(xmlNode: IXmlElement): number {
|
|
|
- // let directionStaffNumber: number = 1;
|
|
|
- // if (xmlNode.element("staff") !== undefined) {
|
|
|
- // let staffNode: IXmlElement = xmlNode.element("staff");
|
|
|
- // if (staffNode !== undefined) {
|
|
|
- // try {
|
|
|
- // directionStaffNumber = parseInt(staffNode.value, 10);
|
|
|
- // } catch (ex) {
|
|
|
- // let errorMsg: string = ITextTranslation.translateText(
|
|
|
- // "ReaderErrorMessages/ExpressionStaffError", "Invalid Expression staff number -> set to default."
|
|
|
- // );
|
|
|
- // this.musicSheet.SheetErrors.pushTemp(errorMsg);
|
|
|
- // directionStaffNumber = 1;
|
|
|
- // logging.debug("InstrumentReader.readExpressionStaffNumber", errorMsg, ex);
|
|
|
- // }
|
|
|
- //
|
|
|
- // }
|
|
|
- // }
|
|
|
- // return directionStaffNumber;
|
|
|
- //}
|
|
|
+ //private readExpressionStaffNumber(xmlNode: IXmlElement): number {
|
|
|
+ // let directionStaffNumber: number = 1;
|
|
|
+ // if (xmlNode.element("staff") !== undefined) {
|
|
|
+ // let staffNode: IXmlElement = xmlNode.element("staff");
|
|
|
+ // if (staffNode !== undefined) {
|
|
|
+ // try {
|
|
|
+ // directionStaffNumber = parseInt(staffNode.value, 10);
|
|
|
+ // } catch (ex) {
|
|
|
+ // let errorMsg: string = ITextTranslation.translateText(
|
|
|
+ // "ReaderErrorMessages/ExpressionStaffError", "Invalid Expression staff number -> set to default."
|
|
|
+ // );
|
|
|
+ // this.musicSheet.SheetErrors.pushTemp(errorMsg);
|
|
|
+ // directionStaffNumber = 1;
|
|
|
+ // logging.debug("InstrumentReader.readExpressionStaffNumber", errorMsg, ex);
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // return directionStaffNumber;
|
|
|
+ //}
|
|
|
|
|
|
- /**
|
|
|
- * Calculate the divisions value from the type and duration of the first MeasureNote that makes sense
|
|
|
- * (meaning itself hasn't any errors and it doesn't belong to a [[Tuplet]]).
|
|
|
- *
|
|
|
- * If all the MeasureNotes belong to a [[Tuplet]], then we read the next XmlMeasure (and so on...).
|
|
|
- * If we have reached the end of the [[Instrument]] and still the divisions aren't set, we throw an exception
|
|
|
- * @returns {number}
|
|
|
- */
|
|
|
- private readDivisionsFromNotes(): number {
|
|
|
- let divisionsFromNote: number = 0;
|
|
|
- let xmlMeasureIndex: number = this.currentXmlMeasureIndex;
|
|
|
- let read: boolean = false;
|
|
|
- while (!read) {
|
|
|
- let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].elements();
|
|
|
- for (let idx: number = 0, len: number = xmlMeasureListArr.length; idx < len; ++idx) {
|
|
|
- let xmlNode: IXmlElement = xmlMeasureListArr[idx];
|
|
|
- if (xmlNode.name === "note" && xmlNode.element("time-modification") === undefined) {
|
|
|
- if (xmlNode.element("duration") !== undefined && xmlNode.element("type") !== undefined) {
|
|
|
- let durationNode: IXmlElement = xmlNode.element("duration");
|
|
|
- let typeNode: IXmlElement = xmlNode.element("type");
|
|
|
- if (durationNode !== undefined && typeNode !== undefined) {
|
|
|
- let type: string = typeNode.value;
|
|
|
- let noteDuration: number = 0;
|
|
|
- try {
|
|
|
- noteDuration = parseInt(durationNode.value, 10);
|
|
|
- } catch (ex) {
|
|
|
- Logging.debug("InstrumentReader.readDivisionsFromNotes", ex);
|
|
|
- continue;
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Calculate the divisions value from the type and duration of the first MeasureNote that makes sense
|
|
|
+ * (meaning itself hasn't any errors and it doesn't belong to a [[Tuplet]]).
|
|
|
+ *
|
|
|
+ * If all the MeasureNotes belong to a [[Tuplet]], then we read the next XmlMeasure (and so on...).
|
|
|
+ * If we have reached the end of the [[Instrument]] and still the divisions aren't set, we throw an exception
|
|
|
+ * @returns {number}
|
|
|
+ */
|
|
|
+ private readDivisionsFromNotes(): number {
|
|
|
+ let divisionsFromNote: number = 0;
|
|
|
+ let xmlMeasureIndex: number = this.currentXmlMeasureIndex;
|
|
|
+ let read: boolean = false;
|
|
|
+ while (!read) {
|
|
|
+ const xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].elements();
|
|
|
+ for (let idx: number = 0, len: number = xmlMeasureListArr.length; idx < len; ++idx) {
|
|
|
+ const xmlNode: IXmlElement = xmlMeasureListArr[idx];
|
|
|
+ if (xmlNode.name === "note" && xmlNode.element("time-modification") === undefined) {
|
|
|
+ if (xmlNode.element("duration") !== undefined && xmlNode.element("type") !== undefined) {
|
|
|
+ const durationNode: IXmlElement = xmlNode.element("duration");
|
|
|
+ const typeNode: IXmlElement = xmlNode.element("type");
|
|
|
+ if (durationNode !== undefined && typeNode !== undefined) {
|
|
|
+ const type: string = typeNode.value;
|
|
|
+ let noteDuration: number = 0;
|
|
|
+ try {
|
|
|
+ noteDuration = parseInt(durationNode.value, 10);
|
|
|
+ } catch (ex) {
|
|
|
+ Logging.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) {
|
|
|
- let errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
|
|
|
- throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
|
|
|
- }
|
|
|
+ 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) {
|
|
|
+ const errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
|
|
|
+ throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
|
|
|
}
|
|
|
- return divisionsFromNote;
|
|
|
+ }
|
|
|
}
|
|
|
+ return divisionsFromNote;
|
|
|
+ }
|
|
|
}
|