InstrumentReader.ts 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. import {Instrument} from "../Instrument";
  2. import {MusicSheet} from "../MusicSheet";
  3. import {VoiceGenerator} from "./VoiceGenerator";
  4. import {Staff} from "../VoiceData/Staff";
  5. import {SourceMeasure} from "../VoiceData/SourceMeasure";
  6. import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
  7. import {ClefInstruction} from "../VoiceData/Instructions/ClefInstruction";
  8. import {KeyInstruction} from "../VoiceData/Instructions/KeyInstruction";
  9. import {RhythmInstruction} from "../VoiceData/Instructions/RhythmInstruction";
  10. import {AbstractNotationInstruction} from "../VoiceData/Instructions/AbstractNotationInstruction";
  11. import {Fraction} from "../../Common/DataObjects/fraction";
  12. import {IXmlElement} from "../../Common/FileIO/Xml";
  13. import {ITextTranslation} from "../Interfaces/ITextTranslation";
  14. import {MusicSheetReadingException} from "../Exceptions";
  15. import {ClefEnum} from "../VoiceData/Instructions/ClefInstruction";
  16. import {RhythmSymbolEnum} from "../VoiceData/Instructions/RhythmInstruction";
  17. import {KeyEnum} from "../VoiceData/Instructions/KeyInstruction";
  18. import {IXmlAttribute} from "../../Common/FileIO/Xml";
  19. import {ChordSymbolContainer} from "../VoiceData/ChordSymbolContainer";
  20. import {Logging} from "../../Common/logging";
  21. import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
  22. //import Dictionary from "typescript-collections/dist/lib/Dictionary";
  23. // FIXME: The following classes are missing
  24. //type repetitionInstructionReader = any;
  25. //type ChordSymbolContainer = any;
  26. //type SlurReader = any;
  27. //type RepetitionInstructionReader = any;
  28. //type ExpressionReader = any;
  29. //declare class MusicSymbolModuleFactory {
  30. // public static createSlurReader(x: any): any;
  31. // public static createExpressionGenerator(musicSheet: MusicSheet, instrument: Instrument, n: number);
  32. //}
  33. //
  34. //class MetronomeReader {
  35. // public static addMetronomeSettings(xmlNode: IXmlElement, musicSheet: MusicSheet): void { }
  36. // public static readMetronomeInstructions(xmlNode: IXmlElement, musicSheet: MusicSheet, currentXmlMeasureIndex: number): void { }
  37. // public static readTempoInstruction(soundNode: IXmlElement, musicSheet: MusicSheet, currentXmlMeasureIndex: number): void { }
  38. //}
  39. //
  40. //class ChordSymbolReader {
  41. // public static readChordSymbol(xmlNode:IXmlElement, musicSheet:MusicSheet, activeKey:any): void {
  42. // }
  43. //}
  44. type repetitionInstructionReader = any;
  45. export class InstrumentReader {
  46. constructor(repetitionInstructionReader: repetitionInstructionReader, xmlMeasureList: IXmlElement[], instrument: Instrument) {
  47. // (*) this.repetitionInstructionReader = repetitionInstructionReader;
  48. this.xmlMeasureList = xmlMeasureList;
  49. this.musicSheet = instrument.GetMusicSheet;
  50. this.instrument = instrument;
  51. this.activeClefs = new Array(instrument.Staves.length);
  52. this.activeClefsHaveBeenInitialized = new Array(instrument.Staves.length);
  53. for (let i: number = 0; i < instrument.Staves.length; i++) {
  54. this.activeClefsHaveBeenInitialized[i] = false;
  55. }
  56. // FIXME createExpressionGenerators(instrument.Staves.length);
  57. // (*) this.slurReader = MusicSymbolModuleFactory.createSlurReader(this.musicSheet);
  58. }
  59. // (*) private repetitionInstructionReader: RepetitionInstructionReader;
  60. private xmlMeasureList: IXmlElement[];
  61. private musicSheet: MusicSheet;
  62. private slurReader: any; // (*) SlurReader;
  63. private instrument: Instrument;
  64. private voiceGeneratorsDict: { [n: number]: VoiceGenerator; } = {};
  65. private staffMainVoiceGeneratorDict: { [staffId: number]: VoiceGenerator } = {};
  66. private inSourceMeasureInstrumentIndex: number;
  67. private divisions: number = 0;
  68. private currentMeasure: SourceMeasure;
  69. private previousMeasure: SourceMeasure;
  70. private currentXmlMeasureIndex: number = 0;
  71. private currentStaff: Staff;
  72. private currentStaffEntry: SourceStaffEntry;
  73. private activeClefs: ClefInstruction[];
  74. private activeKey: KeyInstruction;
  75. private activeRhythm: RhythmInstruction;
  76. private activeClefsHaveBeenInitialized: boolean[];
  77. private activeKeyHasBeenInitialized: boolean = false;
  78. private abstractInstructions: [number, AbstractNotationInstruction][] = [];
  79. private openChordSymbolContainer: ChordSymbolContainer;
  80. // (*) private expressionReaders: ExpressionReader[];
  81. private currentVoiceGenerator: VoiceGenerator;
  82. //private openSlurDict: { [n: number]: Slur; } = {};
  83. private maxTieNoteFraction: Fraction;
  84. public get ActiveKey(): KeyInstruction {
  85. return this.activeKey;
  86. }
  87. public get MaxTieNoteFraction(): Fraction {
  88. return this.maxTieNoteFraction;
  89. }
  90. public get ActiveRhythm(): RhythmInstruction {
  91. return this.activeRhythm;
  92. }
  93. public set ActiveRhythm(value: RhythmInstruction) {
  94. this.activeRhythm = value;
  95. }
  96. public readNextXmlMeasure(currentMeasure: SourceMeasure, measureStartAbsoluteTimestamp: Fraction, guitarPro: boolean): boolean {
  97. if (this.currentXmlMeasureIndex >= this.xmlMeasureList.length) {
  98. return false;
  99. }
  100. this.currentMeasure = currentMeasure;
  101. this.inSourceMeasureInstrumentIndex = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument);
  102. // (*) if (this.repetitionInstructionReader !== undefined) {
  103. // this.repetitionInstructionReader.prepareReadingMeasure(currentMeasure, this.currentXmlMeasureIndex);
  104. //}
  105. let currentFraction: Fraction = new Fraction(0, 1);
  106. let previousFraction: Fraction = new Fraction(0, 1);
  107. let divisionsException: boolean = false;
  108. this.maxTieNoteFraction = new Fraction(0, 1);
  109. let lastNoteWasGrace: boolean = false;
  110. try {
  111. let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[this.currentXmlMeasureIndex].elements();
  112. for (let xmlNode of xmlMeasureListArr) {
  113. if (xmlNode.name === "note") {
  114. if (xmlNode.hasAttributes && xmlNode.attribute("print-object") && xmlNode.attribute("print-spacing")) {
  115. continue;
  116. }
  117. let noteStaff: number = 1;
  118. if (this.instrument.Staves.length > 1) {
  119. if (xmlNode.element("staff") !== undefined) {
  120. noteStaff = parseInt(xmlNode.element("staff").value, 10);
  121. if (isNaN(noteStaff)) {
  122. Logging.debug("InstrumentReader.readNextXmlMeasure.get staff number");
  123. noteStaff = 1;
  124. }
  125. }
  126. }
  127. this.currentStaff = this.instrument.Staves[noteStaff - 1];
  128. let isChord: boolean = xmlNode.element("chord") !== undefined;
  129. if (xmlNode.element("voice") !== undefined) {
  130. let noteVoice: number = parseInt(xmlNode.element("voice").value, 10);
  131. this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(noteVoice, noteStaff - 1);
  132. } else {
  133. if (!isChord || this.currentVoiceGenerator === undefined) {
  134. this.currentVoiceGenerator = this.getOrCreateVoiceGenerator(1, noteStaff - 1);
  135. }
  136. }
  137. let noteDivisions: number = 0;
  138. let noteDuration: Fraction = new Fraction(0, 1);
  139. let isTuplet: boolean = false;
  140. if (xmlNode.element("duration") !== undefined) {
  141. noteDivisions = parseInt(xmlNode.element("duration").value, 10);
  142. if (!isNaN(noteDivisions)) {
  143. noteDuration = new Fraction(noteDivisions, 4 * this.divisions);
  144. if (noteDivisions === 0) {
  145. noteDuration = this.getNoteDurationFromTypeNode(xmlNode);
  146. }
  147. if (xmlNode.element("time-modification") !== undefined) {
  148. noteDuration = this.getNoteDurationForTuplet(xmlNode);
  149. isTuplet = true;
  150. }
  151. } else {
  152. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/NoteDurationError", "Invalid Note Duration.");
  153. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  154. Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
  155. continue;
  156. }
  157. }
  158. let restNote: boolean = xmlNode.element("rest") !== undefined;
  159. //Logging.log("New note found!", noteDivisions, noteDuration.toString(), restNote);
  160. let isGraceNote: boolean = xmlNode.element("grace") !== undefined || noteDivisions === 0 || isChord && lastNoteWasGrace;
  161. let musicTimestamp: Fraction = currentFraction.clone();
  162. if (isChord) {
  163. musicTimestamp = previousFraction.clone();
  164. }
  165. this.currentStaffEntry = this.currentMeasure.findOrCreateStaffEntry(
  166. musicTimestamp,
  167. this.inSourceMeasureInstrumentIndex + noteStaff - 1,
  168. this.currentStaff
  169. ).staffEntry;
  170. //Logging.log("currentStaffEntry", this.currentStaffEntry, this.currentMeasure.VerticalSourceStaffEntryContainers.length);
  171. if (!this.currentVoiceGenerator.hasVoiceEntry() || (!isChord && !isGraceNote && !lastNoteWasGrace) || (!lastNoteWasGrace && isGraceNote)) {
  172. this.currentVoiceGenerator.createVoiceEntry(musicTimestamp, this.currentStaffEntry, !restNote);
  173. }
  174. if (!isGraceNote && !isChord) {
  175. previousFraction = currentFraction.clone();
  176. currentFraction.Add(noteDuration);
  177. }
  178. if (
  179. isChord &&
  180. this.currentStaffEntry !== undefined &&
  181. this.currentStaffEntry.ParentStaff !== this.currentStaff
  182. ) {
  183. this.currentStaffEntry = this.currentVoiceGenerator.checkForStaffEntryLink(
  184. this.inSourceMeasureInstrumentIndex + noteStaff - 1, this.currentStaff, this.currentStaffEntry, this.currentMeasure
  185. );
  186. }
  187. let beginOfMeasure: boolean = (
  188. this.currentStaffEntry !== undefined &&
  189. this.currentStaffEntry.Timestamp !== undefined &&
  190. this.currentStaffEntry.Timestamp.Equals(new Fraction(0, 1)) && !this.currentStaffEntry.hasNotes()
  191. );
  192. this.saveAbstractInstructionList(this.instrument.Staves.length, beginOfMeasure);
  193. if (this.openChordSymbolContainer !== undefined) {
  194. this.currentStaffEntry.ChordContainer = this.openChordSymbolContainer;
  195. this.openChordSymbolContainer = undefined;
  196. }
  197. if (this.activeRhythm !== undefined) {
  198. // (*) this.musicSheet.SheetPlaybackSetting.Rhythm = this.activeRhythm.Rhythm;
  199. }
  200. if (isTuplet) {
  201. this.currentVoiceGenerator.read(
  202. xmlNode, noteDuration.Numerator,
  203. noteDuration.Denominator, restNote, isGraceNote,
  204. this.currentStaffEntry, this.currentMeasure,
  205. measureStartAbsoluteTimestamp,
  206. this.maxTieNoteFraction, isChord, guitarPro
  207. );
  208. } else {
  209. this.currentVoiceGenerator.read(
  210. xmlNode, noteDivisions, 4 * this.divisions,
  211. restNote, isGraceNote, this.currentStaffEntry,
  212. this.currentMeasure, measureStartAbsoluteTimestamp,
  213. this.maxTieNoteFraction, isChord, guitarPro
  214. );
  215. }
  216. let notationsNode: IXmlElement = xmlNode.element("notations");
  217. if (notationsNode !== undefined && notationsNode.element("dynamics") !== undefined) {
  218. // (*) let expressionReader: ExpressionReader = this.expressionReaders[this.readExpressionStaffNumber(xmlNode) - 1];
  219. //if (expressionReader !== undefined) {
  220. // expressionReader.readExpressionParameters(
  221. // xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false
  222. // );
  223. // expressionReader.read(
  224. // xmlNode, this.currentMeasure, previousFraction
  225. // );
  226. //}
  227. }
  228. lastNoteWasGrace = isGraceNote;
  229. } else if (xmlNode.name === "attributes") {
  230. let divisionsNode: IXmlElement = xmlNode.element("divisions");
  231. if (divisionsNode !== undefined) {
  232. this.divisions = parseInt(divisionsNode.value, 10);
  233. if (isNaN(this.divisions)) {
  234. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
  235. Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
  236. this.divisions = this.readDivisionsFromNotes();
  237. if (this.divisions > 0) {
  238. this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
  239. } else {
  240. divisionsException = true;
  241. throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
  242. }
  243. }
  244. }
  245. if (
  246. xmlNode.element("divisions") === undefined &&
  247. this.divisions === 0 &&
  248. this.currentXmlMeasureIndex === 0
  249. ) {
  250. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
  251. this.divisions = this.readDivisionsFromNotes();
  252. if (this.divisions > 0) {
  253. this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
  254. } else {
  255. divisionsException = true;
  256. throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
  257. }
  258. }
  259. this.addAbstractInstruction(xmlNode, guitarPro);
  260. if (currentFraction.Equals(new Fraction(0, 1)) && this.isAttributesNodeAtBeginOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
  261. this.saveAbstractInstructionList(this.instrument.Staves.length, true);
  262. }
  263. if (this.isAttributesNodeAtEndOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
  264. this.saveClefInstructionAtEndOfMeasure();
  265. }
  266. } else if (xmlNode.name === "forward") {
  267. let forFraction: number = parseInt(xmlNode.element("duration").value, 10);
  268. currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
  269. } else if (xmlNode.name === "backup") {
  270. let backFraction: number = parseInt(xmlNode.element("duration").value, 10);
  271. currentFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
  272. if (currentFraction.Numerator < 0) {
  273. currentFraction = new Fraction(0, 1);
  274. }
  275. previousFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
  276. if (previousFraction.Numerator < 0) {
  277. previousFraction = new Fraction(0, 1);
  278. }
  279. } else if (xmlNode.name === "direction") {
  280. // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
  281. // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
  282. let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
  283. if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
  284. relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
  285. }
  286. // unused: let handeled: boolean = false;
  287. // (*) if (this.repetitionInstructionReader !== undefined) {
  288. // handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode, relativePositionInMeasure);
  289. //}
  290. //if (!handeled) {
  291. // let expressionReader: ExpressionReader = this.expressionReaders[0];
  292. // let staffIndex: number = this.readExpressionStaffNumber(xmlNode) - 1;
  293. // if (staffIndex < this.expressionReaders.length) {
  294. // expressionReader = this.expressionReaders[staffIndex];
  295. // }
  296. // if (expressionReader !== undefined) {
  297. // if (directionTypeNode.element("octave-shift") !== undefined) {
  298. // expressionReader.readExpressionParameters(
  299. // xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, true
  300. // );
  301. // expressionReader.addOctaveShift(xmlNode, this.currentMeasure, previousFraction.clone());
  302. // }
  303. // expressionReader.readExpressionParameters(
  304. // xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false
  305. // );
  306. // expressionReader.read(xmlNode, this.currentMeasure, currentFraction);
  307. // }
  308. //}
  309. } else if (xmlNode.name === "barline") {
  310. // (*)
  311. //if (this.repetitionInstructionReader !== undefined) {
  312. // let measureEndsSystem: boolean = false;
  313. // this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
  314. // if (measureEndsSystem) {
  315. // this.currentMeasure.BreakSystemAfter = true;
  316. // this.currentMeasure.endsPiece = true;
  317. // }
  318. //}
  319. } else if (xmlNode.name === "sound") {
  320. // (*) MetronomeReader.readTempoInstruction(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
  321. } else if (xmlNode.name === "harmony") {
  322. // (*) this.openChordSymbolContainer = ChordSymbolReader.readChordSymbol(xmlNode, this.musicSheet, this.activeKey);
  323. }
  324. }
  325. for (let j in this.voiceGeneratorsDict) {
  326. if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
  327. let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[j];
  328. voiceGenerator.checkForOpenBeam();
  329. voiceGenerator.checkForOpenGraceNotes();
  330. }
  331. }
  332. if (this.currentXmlMeasureIndex === this.xmlMeasureList.length - 1) {
  333. for (let i: number = 0; i < this.instrument.Staves.length; i++) {
  334. if (!this.activeClefsHaveBeenInitialized[i]) {
  335. this.createDefaultClefInstruction(this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument) + i);
  336. }
  337. }
  338. if (!this.activeKeyHasBeenInitialized) {
  339. this.createDefaultKeyInstruction();
  340. }
  341. // (*)
  342. //for (let i: number = 0; i < this.expressionReaders.length; i++) {
  343. // let reader: ExpressionReader = this.expressionReaders[i];
  344. // if (reader !== undefined) {
  345. // reader.checkForOpenExpressions(this.currentMeasure, currentFraction);
  346. // }
  347. //}
  348. }
  349. } catch (e) {
  350. if (divisionsException) {
  351. throw new MusicSheetReadingException(e.Message);
  352. }
  353. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MeasureError", "Error while reading Measure.");
  354. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  355. Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg, e);
  356. }
  357. this.previousMeasure = this.currentMeasure;
  358. this.currentXmlMeasureIndex += 1;
  359. return true;
  360. }
  361. public doCalculationsAfterDurationHasBeenSet(): void {
  362. for (let j in this.voiceGeneratorsDict) {
  363. if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
  364. this.voiceGeneratorsDict[j].checkOpenTies();
  365. }
  366. }
  367. }
  368. private getOrCreateVoiceGenerator(voiceId: number, staffId: number): VoiceGenerator {
  369. let staff: Staff = this.instrument.Staves[staffId];
  370. let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[voiceId];
  371. if (voiceGenerator !== undefined) {
  372. if (staff.Voices.indexOf(voiceGenerator.GetVoice) === -1) {
  373. staff.Voices.push(voiceGenerator.GetVoice);
  374. }
  375. } else {
  376. let mainVoiceGenerator: VoiceGenerator = this.staffMainVoiceGeneratorDict[staffId];
  377. if (mainVoiceGenerator !== undefined) {
  378. voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader, mainVoiceGenerator.GetVoice);
  379. staff.Voices.push(voiceGenerator.GetVoice);
  380. this.voiceGeneratorsDict[voiceId] = voiceGenerator;
  381. } else {
  382. voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader);
  383. staff.Voices.push(voiceGenerator.GetVoice);
  384. this.voiceGeneratorsDict[voiceId] = voiceGenerator;
  385. this.staffMainVoiceGeneratorDict[staffId] = voiceGenerator;
  386. }
  387. }
  388. return voiceGenerator;
  389. }
  390. //private createExpressionGenerators(numberOfStaves: number): void {
  391. // // (*)
  392. // //this.expressionReaders = new Array(numberOfStaves);
  393. // //for (let i: number = 0; i < numberOfStaves; i++) {
  394. // // this.expressionReaders[i] = MusicSymbolModuleFactory.createExpressionGenerator(this.musicSheet, this.instrument, i + 1);
  395. // //}
  396. //}
  397. private createDefaultClefInstruction(staffIndex: number): void {
  398. let first: SourceMeasure;
  399. if (this.musicSheet.SourceMeasures.length > 0) {
  400. first = this.musicSheet.SourceMeasures[0];
  401. } else {
  402. first = this.currentMeasure;
  403. }
  404. let clefInstruction: ClefInstruction = new ClefInstruction(ClefEnum.G, 0, 2);
  405. let firstStaffEntry: SourceStaffEntry;
  406. if (first.FirstInstructionsStaffEntries[staffIndex] === undefined) {
  407. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  408. first.FirstInstructionsStaffEntries[staffIndex] = firstStaffEntry;
  409. } else {
  410. firstStaffEntry = first.FirstInstructionsStaffEntries[staffIndex];
  411. firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
  412. }
  413. clefInstruction.Parent = firstStaffEntry;
  414. firstStaffEntry.Instructions.splice(0, 0, clefInstruction);
  415. }
  416. private createDefaultKeyInstruction(): void {
  417. let first: SourceMeasure;
  418. if (this.musicSheet.SourceMeasures.length > 0) {
  419. first = this.musicSheet.SourceMeasures[0];
  420. } else {
  421. first = this.currentMeasure;
  422. }
  423. let keyInstruction: KeyInstruction = new KeyInstruction(undefined, 0, KeyEnum.major);
  424. for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + this.instrument.Staves.length; j++) {
  425. if (first.FirstInstructionsStaffEntries[j] === undefined) {
  426. let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  427. first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
  428. keyInstruction.Parent = firstStaffEntry;
  429. firstStaffEntry.Instructions.push(keyInstruction);
  430. } else {
  431. let firstStaffEntry: SourceStaffEntry = first.FirstInstructionsStaffEntries[j];
  432. keyInstruction.Parent = firstStaffEntry;
  433. firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
  434. if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
  435. firstStaffEntry.Instructions.splice(1, 0, keyInstruction);
  436. } else {
  437. firstStaffEntry.Instructions.splice(0, 0, keyInstruction);
  438. }
  439. }
  440. }
  441. }
  442. private isAttributesNodeAtBeginOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
  443. let children: IXmlElement[] = parentNode.elements();
  444. let attributesNodeIndex: number = children.indexOf(attributesNode); // FIXME | 0
  445. if (attributesNodeIndex > 0 && children[attributesNodeIndex - 1].name === "backup") {
  446. return true;
  447. }
  448. let firstNoteNodeIndex: number = -1;
  449. for (let i: number = 0; i < children.length; i++) {
  450. if (children[i].name === "note") {
  451. firstNoteNodeIndex = i;
  452. break;
  453. }
  454. }
  455. return (attributesNodeIndex < firstNoteNodeIndex && firstNoteNodeIndex > 0) || (firstNoteNodeIndex < 0);
  456. }
  457. private isAttributesNodeAtEndOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
  458. let childs: IXmlElement[] = parentNode.elements().slice();
  459. let attributesNodeIndex: number = 0;
  460. for (let i: number = 0; i < childs.length; i++) {
  461. if (childs[i] === attributesNode) {
  462. attributesNodeIndex = i;
  463. break;
  464. }
  465. }
  466. let nextNoteNodeIndex: number = 0;
  467. for (let i: number = attributesNodeIndex; i < childs.length; i++) {
  468. if (childs[i].name === "note") {
  469. nextNoteNodeIndex = i;
  470. break;
  471. }
  472. }
  473. return attributesNodeIndex > nextNoteNodeIndex;
  474. }
  475. private getNoteDurationFromTypeNode(xmlNode: IXmlElement): Fraction {
  476. if (xmlNode.element("type") !== undefined) {
  477. let typeNode: IXmlElement = xmlNode.element("type");
  478. if (typeNode !== undefined) {
  479. let type: string = typeNode.value;
  480. return this.currentVoiceGenerator.getNoteDurationFromType(type);
  481. }
  482. }
  483. return new Fraction(0, 4 * this.divisions);
  484. }
  485. private addAbstractInstruction(node: IXmlElement, guitarPro: boolean): void {
  486. if (node.element("divisions") !== undefined) {
  487. if (node.elements().length === 1) {
  488. return;
  489. }
  490. }
  491. let transposeNode: IXmlElement = node.element("transpose");
  492. if (transposeNode !== undefined) {
  493. let chromaticNode: IXmlElement = transposeNode.element("chromatic");
  494. if (chromaticNode !== undefined) {
  495. this.instrument.PlaybackTranspose = parseInt(chromaticNode.value, 10);
  496. }
  497. }
  498. let clefList: IXmlElement[] = node.elements("clef");
  499. let errorMsg: string;
  500. if (clefList.length > 0) {
  501. for (let idx: number = 0, len: number = clefList.length; idx < len; ++idx) {
  502. let nodeList: IXmlElement = clefList[idx];
  503. let clefEnum: ClefEnum = ClefEnum.G;
  504. let line: number = 2;
  505. let staffNumber: number = 1;
  506. let clefOctaveOffset: number = 0;
  507. let lineNode: IXmlElement = nodeList.element("line");
  508. if (lineNode !== undefined) {
  509. try {
  510. line = parseInt(lineNode.value, 10);
  511. } catch (ex) {
  512. errorMsg = ITextTranslation.translateText(
  513. "ReaderErrorMessages/ClefLineError",
  514. "Invalid clef line given -> using default clef line."
  515. );
  516. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  517. line = 2;
  518. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  519. }
  520. }
  521. let signNode: IXmlElement = nodeList.element("sign");
  522. if (signNode !== undefined) {
  523. try {
  524. clefEnum = ClefEnum[signNode.value];
  525. if (!ClefInstruction.isSupportedClef(clefEnum)) {
  526. if (clefEnum === ClefEnum.TAB && guitarPro) {
  527. clefOctaveOffset = -1;
  528. }
  529. errorMsg = ITextTranslation.translateText(
  530. "ReaderErrorMessages/ClefError",
  531. "Unsupported clef found -> using default clef."
  532. );
  533. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  534. clefEnum = ClefEnum.G;
  535. line = 2;
  536. }
  537. } catch (e) {
  538. errorMsg = ITextTranslation.translateText(
  539. "ReaderErrorMessages/ClefError",
  540. "Invalid clef found -> using default clef."
  541. );
  542. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  543. clefEnum = ClefEnum.G;
  544. line = 2;
  545. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, e);
  546. }
  547. }
  548. let clefOctaveNode: IXmlElement = nodeList.element("clef-octave-change");
  549. if (clefOctaveNode !== undefined) {
  550. try {
  551. clefOctaveOffset = parseInt(clefOctaveNode.value, 10);
  552. } catch (e) {
  553. errorMsg = ITextTranslation.translateText(
  554. "ReaderErrorMessages/ClefOctaveError",
  555. "Invalid clef octave found -> using default clef octave."
  556. );
  557. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  558. clefOctaveOffset = 0;
  559. }
  560. }
  561. if (nodeList.hasAttributes && nodeList.attributes()[0].name === "number") {
  562. try {
  563. staffNumber = parseInt(nodeList.attributes()[0].value, 10);
  564. } catch (err) {
  565. errorMsg = ITextTranslation.translateText(
  566. "ReaderErrorMessages/ClefError",
  567. "Invalid clef found -> using default clef."
  568. );
  569. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  570. staffNumber = 1;
  571. }
  572. }
  573. let clefInstruction: ClefInstruction = new ClefInstruction(clefEnum, clefOctaveOffset, line);
  574. this.abstractInstructions.push([staffNumber, clefInstruction]);
  575. }
  576. }
  577. if (node.element("key") !== undefined && this.instrument.MidiInstrumentId !== MidiInstrument.Percussion) {
  578. let key: number = 0;
  579. let keyNode: IXmlElement = node.element("key").element("fifths");
  580. if (keyNode !== undefined) {
  581. try {
  582. key = parseInt(keyNode.value, 10);
  583. } catch (ex) {
  584. errorMsg = ITextTranslation.translateText(
  585. "ReaderErrorMessages/KeyError",
  586. "Invalid key found -> set to default."
  587. );
  588. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  589. key = 0;
  590. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  591. }
  592. }
  593. let keyEnum: KeyEnum = KeyEnum.none;
  594. let modeNode: IXmlElement = node.element("key");
  595. if (modeNode !== undefined) {
  596. modeNode = modeNode.element("mode");
  597. }
  598. if (modeNode !== undefined) {
  599. try {
  600. keyEnum = KeyEnum[modeNode.value];
  601. } catch (ex) {
  602. errorMsg = ITextTranslation.translateText(
  603. "ReaderErrorMessages/KeyError",
  604. "Invalid key found -> set to default."
  605. );
  606. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  607. keyEnum = KeyEnum.major;
  608. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  609. }
  610. }
  611. let keyInstruction: KeyInstruction = new KeyInstruction(undefined, key, keyEnum);
  612. this.abstractInstructions.push([1, keyInstruction]);
  613. }
  614. if (node.element("time") !== undefined) {
  615. let symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
  616. let timeNode: IXmlElement = node.element("time");
  617. if (timeNode !== undefined && timeNode.hasAttributes) {
  618. let firstAttr: IXmlAttribute = timeNode.firstAttribute;
  619. if (firstAttr.name === "symbol") {
  620. if (firstAttr.value === "common") {
  621. symbolEnum = RhythmSymbolEnum.COMMON;
  622. } else if (firstAttr.value === "cut") {
  623. symbolEnum = RhythmSymbolEnum.CUT;
  624. }
  625. }
  626. }
  627. let num: number = 0;
  628. let denom: number = 0;
  629. let senzaMisura: boolean = (timeNode !== undefined && timeNode.element("senza-misura") !== undefined);
  630. let timeList: IXmlElement[] = node.elements("time");
  631. let beatsList: IXmlElement[] = [];
  632. let typeList: IXmlElement[] = [];
  633. for (let idx: number = 0, len: number = timeList.length; idx < len; ++idx) {
  634. let xmlNode: IXmlElement = timeList[idx];
  635. beatsList.push.apply(beatsList, xmlNode.elements("beats"));
  636. typeList.push.apply(typeList, xmlNode.elements("beat-type"));
  637. }
  638. if (!senzaMisura) {
  639. try {
  640. if (beatsList !== undefined && beatsList.length > 0 && typeList !== undefined && beatsList.length === typeList.length) {
  641. let length: number = beatsList.length;
  642. let fractions: Fraction[] = new Array(length);
  643. let maxDenom: number = 0;
  644. for (let i: number = 0; i < length; i++) {
  645. let s: string = beatsList[i].value;
  646. let n: number = 0;
  647. let d: number = 0;
  648. if (s.indexOf("+") !== -1) {
  649. let numbers: string[] = s.split("+");
  650. for (let idx: number = 0, len: number = numbers.length; idx < len; ++idx) {
  651. n += parseInt(numbers[idx], 10);
  652. }
  653. } else {
  654. n = parseInt(s, 10);
  655. }
  656. d = parseInt(typeList[i].value, 10);
  657. maxDenom = Math.max(maxDenom, d);
  658. fractions[i] = new Fraction(n, d, false);
  659. }
  660. for (let i: number = 0; i < length; i++) {
  661. if (fractions[i].Denominator === maxDenom) {
  662. num += fractions[i].Numerator;
  663. } else {
  664. num += (maxDenom / fractions[i].Denominator) * fractions[i].Numerator;
  665. }
  666. }
  667. denom = maxDenom;
  668. } else {
  669. num = parseInt(node.element("time").element("beats").value, 10);
  670. denom = parseInt(node.element("time").element("beat-type").value, 10);
  671. }
  672. } catch (ex) {
  673. errorMsg = ITextTranslation.translateText("ReaderErrorMessages/RhythmError", "Invalid rhythm found -> set to default.");
  674. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  675. num = 4;
  676. denom = 4;
  677. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  678. }
  679. if ((num === 4 && denom === 4) || (num === 2 && denom === 2)) {
  680. symbolEnum = RhythmSymbolEnum.NONE;
  681. }
  682. this.abstractInstructions.push([1, new RhythmInstruction(
  683. new Fraction(num, denom, false), num, denom, symbolEnum
  684. )]);
  685. } else {
  686. this.abstractInstructions.push([1, new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE)]);
  687. }
  688. }
  689. }
  690. private saveAbstractInstructionList(numberOfStaves: number, beginOfMeasure: boolean): void {
  691. for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
  692. let pair: [number, AbstractNotationInstruction] = this.abstractInstructions[i];
  693. let key: number = pair[0];
  694. let value: AbstractNotationInstruction = pair[1];
  695. if (value instanceof ClefInstruction) {
  696. let clefInstruction: ClefInstruction = <ClefInstruction>value;
  697. if (this.currentXmlMeasureIndex === 0 || (key <= this.activeClefs.length && clefInstruction !== this.activeClefs[key - 1])) {
  698. if (!beginOfMeasure && this.currentStaffEntry !== undefined && !this.currentStaffEntry.hasNotes() && key - 1
  699. === this.instrument.Staves.indexOf(this.currentStaffEntry.ParentStaff)) {
  700. let newClefInstruction: ClefInstruction = clefInstruction;
  701. newClefInstruction.Parent = this.currentStaffEntry;
  702. this.currentStaffEntry.removeFirstInstructionOfType<ClefInstruction>();
  703. this.currentStaffEntry.Instructions.push(newClefInstruction);
  704. this.activeClefs[key - 1] = clefInstruction;
  705. this.abstractInstructions.splice(i, 1);
  706. } else if (beginOfMeasure) {
  707. let firstStaffEntry: SourceStaffEntry;
  708. if (this.currentMeasure !== undefined) {
  709. let newClefInstruction: ClefInstruction = clefInstruction;
  710. if (this.currentXmlMeasureIndex === 0) {
  711. if (this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] === undefined) {
  712. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  713. this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = firstStaffEntry;
  714. newClefInstruction.Parent = firstStaffEntry;
  715. firstStaffEntry.Instructions.push(newClefInstruction);
  716. this.activeClefsHaveBeenInitialized[key - 1] = true;
  717. } else if (this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1]
  718. !==
  719. undefined && !(this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1].Instructions[0] instanceof ClefInstruction)) {
  720. firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1];
  721. newClefInstruction.Parent = firstStaffEntry;
  722. firstStaffEntry.removeFirstInstructionOfType<ClefInstruction>();
  723. firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
  724. this.activeClefsHaveBeenInitialized[key - 1] = true;
  725. } else {
  726. let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  727. this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
  728. newClefInstruction.Parent = lastStaffEntry;
  729. lastStaffEntry.Instructions.push(newClefInstruction);
  730. }
  731. } else if (!this.activeClefsHaveBeenInitialized[key - 1]) {
  732. let first: SourceMeasure = this.musicSheet.SourceMeasures[0];
  733. if (first.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] === undefined) {
  734. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  735. } else {
  736. firstStaffEntry = first.FirstInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1];
  737. firstStaffEntry.removeFirstInstructionOfType<ClefInstruction>();
  738. }
  739. newClefInstruction.Parent = firstStaffEntry;
  740. firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
  741. this.activeClefsHaveBeenInitialized[key - 1] = true;
  742. } else {
  743. let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  744. this.previousMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
  745. newClefInstruction.Parent = lastStaffEntry;
  746. lastStaffEntry.Instructions.push(newClefInstruction);
  747. }
  748. this.activeClefs[key - 1] = clefInstruction;
  749. this.abstractInstructions.splice(i, 1);
  750. }
  751. }
  752. }
  753. if (key <= this.activeClefs.length && clefInstruction === this.activeClefs[key - 1]) {
  754. this.abstractInstructions.splice(i, 1);
  755. }
  756. }
  757. if (value instanceof KeyInstruction) {
  758. let keyInstruction: KeyInstruction = <KeyInstruction>value;
  759. if (this.activeKey === undefined || this.activeKey.Key !== keyInstruction.Key) {
  760. this.activeKey = keyInstruction;
  761. this.abstractInstructions.splice(i, 1);
  762. let sourceMeasure: SourceMeasure;
  763. if (!this.activeKeyHasBeenInitialized) {
  764. this.activeKeyHasBeenInitialized = true;
  765. if (this.currentXmlMeasureIndex > 0) {
  766. sourceMeasure = this.musicSheet.SourceMeasures[0];
  767. } else {
  768. sourceMeasure = this.currentMeasure;
  769. }
  770. } else {
  771. sourceMeasure = this.currentMeasure;
  772. }
  773. if (sourceMeasure !== undefined) {
  774. for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
  775. let newKeyInstruction: KeyInstruction = keyInstruction;
  776. if (sourceMeasure.FirstInstructionsStaffEntries[j] === undefined) {
  777. let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  778. sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
  779. newKeyInstruction.Parent = firstStaffEntry;
  780. firstStaffEntry.Instructions.push(newKeyInstruction);
  781. } else {
  782. let firstStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[j];
  783. newKeyInstruction.Parent = firstStaffEntry;
  784. firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
  785. if (firstStaffEntry.Instructions.length === 0) {
  786. firstStaffEntry.Instructions.push(newKeyInstruction);
  787. } else {
  788. if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
  789. firstStaffEntry.Instructions.splice(1, 0, newKeyInstruction);
  790. } else {
  791. firstStaffEntry.Instructions.splice(0, 0, newKeyInstruction);
  792. }
  793. }
  794. }
  795. }
  796. }
  797. }
  798. if (this.activeKey !== undefined && this.activeKey === keyInstruction) {
  799. this.abstractInstructions.splice(i, 1);
  800. }
  801. }
  802. if (value instanceof RhythmInstruction) {
  803. let rhythmInstruction: RhythmInstruction = <RhythmInstruction>value;
  804. if (this.activeRhythm === undefined || this.activeRhythm !== rhythmInstruction) {
  805. this.activeRhythm = rhythmInstruction;
  806. this.abstractInstructions.splice(i, 1);
  807. if (this.currentMeasure !== undefined) {
  808. for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
  809. let newRhythmInstruction: RhythmInstruction = rhythmInstruction;
  810. let firstStaffEntry: SourceStaffEntry;
  811. if (this.currentMeasure.FirstInstructionsStaffEntries[j] === undefined) {
  812. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  813. this.currentMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
  814. } else {
  815. firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[j];
  816. firstStaffEntry.removeFirstInstructionOfType<RhythmInstruction>();
  817. }
  818. newRhythmInstruction.Parent = firstStaffEntry;
  819. firstStaffEntry.Instructions.push(newRhythmInstruction);
  820. }
  821. }
  822. }
  823. if (this.activeRhythm !== undefined && this.activeRhythm === rhythmInstruction) {
  824. this.abstractInstructions.splice(i, 1);
  825. }
  826. }
  827. }
  828. }
  829. private saveClefInstructionAtEndOfMeasure(): void {
  830. for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
  831. let key: number = this.abstractInstructions[i][0];
  832. let value: AbstractNotationInstruction = this.abstractInstructions[i][1];
  833. if (value instanceof ClefInstruction) {
  834. let clefInstruction: ClefInstruction = <ClefInstruction>value;
  835. if (
  836. (this.activeClefs[key - 1] === undefined) ||
  837. (clefInstruction.ClefType !== this.activeClefs[key - 1].ClefType || (
  838. clefInstruction.ClefType === this.activeClefs[key - 1].ClefType &&
  839. clefInstruction.Line !== this.activeClefs[key - 1].Line
  840. ))) {
  841. let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  842. this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
  843. let newClefInstruction: ClefInstruction = clefInstruction;
  844. newClefInstruction.Parent = lastStaffEntry;
  845. lastStaffEntry.Instructions.push(newClefInstruction);
  846. this.activeClefs[key - 1] = clefInstruction;
  847. this.abstractInstructions.splice(i, 1);
  848. }
  849. }
  850. }
  851. }
  852. private getNoteDurationForTuplet(xmlNode: IXmlElement): Fraction {
  853. let duration: Fraction = new Fraction(0, 1);
  854. let typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
  855. if (xmlNode.element("time-modification") !== undefined) {
  856. let time: IXmlElement = xmlNode.element("time-modification");
  857. if (time !== undefined) {
  858. if (time.element("actual-notes") !== undefined && time.element("normal-notes") !== undefined) {
  859. let actualNotes: IXmlElement = time.element("actual-notes");
  860. let normalNotes: IXmlElement = time.element("normal-notes");
  861. if (actualNotes !== undefined && normalNotes !== undefined) {
  862. let actual: number = parseInt(actualNotes.value, 10);
  863. let normal: number = parseInt(normalNotes.value, 10);
  864. duration = new Fraction(normal * typeDuration.Numerator, actual * typeDuration.Denominator);
  865. }
  866. }
  867. }
  868. }
  869. return duration;
  870. }
  871. //private readExpressionStaffNumber(xmlNode: IXmlElement): number {
  872. // let directionStaffNumber: number = 1;
  873. // if (xmlNode.element("staff") !== undefined) {
  874. // let staffNode: IXmlElement = xmlNode.element("staff");
  875. // if (staffNode !== undefined) {
  876. // try {
  877. // directionStaffNumber = parseInt(staffNode.value, 10);
  878. // } catch (ex) {
  879. // let errorMsg: string = ITextTranslation.translateText(
  880. // "ReaderErrorMessages/ExpressionStaffError", "Invalid Expression staff number -> set to default."
  881. // );
  882. // this.musicSheet.SheetErrors.pushTemp(errorMsg);
  883. // directionStaffNumber = 1;
  884. // logging.debug("InstrumentReader.readExpressionStaffNumber", errorMsg, ex);
  885. // }
  886. //
  887. // }
  888. // }
  889. // return directionStaffNumber;
  890. //}
  891. private readDivisionsFromNotes(): number {
  892. let divisionsFromNote: number = 0;
  893. let xmlMeasureIndex: number = this.currentXmlMeasureIndex;
  894. let read: boolean = false;
  895. while (!read) {
  896. let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].elements();
  897. for (let idx: number = 0, len: number = xmlMeasureListArr.length; idx < len; ++idx) {
  898. let xmlNode: IXmlElement = xmlMeasureListArr[idx];
  899. if (xmlNode.name === "note" && xmlNode.element("time-modification") === undefined) {
  900. if (xmlNode.element("duration") !== undefined && xmlNode.element("type") !== undefined) {
  901. let durationNode: IXmlElement = xmlNode.element("duration");
  902. let typeNode: IXmlElement = xmlNode.element("type");
  903. if (durationNode !== undefined && typeNode !== undefined) {
  904. let type: string = typeNode.value;
  905. let noteDuration: number = 0;
  906. try {
  907. noteDuration = parseInt(durationNode.value, 10);
  908. } catch (ex) {
  909. Logging.debug("InstrumentReader.readDivisionsFromNotes", ex);
  910. continue;
  911. }
  912. switch (type) {
  913. case "1024th":
  914. divisionsFromNote = (noteDuration / 4) * 1024;
  915. break;
  916. case "512th":
  917. divisionsFromNote = (noteDuration / 4) * 512;
  918. break;
  919. case "256th":
  920. divisionsFromNote = (noteDuration / 4) * 256;
  921. break;
  922. case "128th":
  923. divisionsFromNote = (noteDuration / 4) * 128;
  924. break;
  925. case "64th":
  926. divisionsFromNote = (noteDuration / 4) * 64;
  927. break;
  928. case "32nd":
  929. divisionsFromNote = (noteDuration / 4) * 32;
  930. break;
  931. case "16th":
  932. divisionsFromNote = (noteDuration / 4) * 16;
  933. break;
  934. case "eighth":
  935. divisionsFromNote = (noteDuration / 4) * 8;
  936. break;
  937. case "quarter":
  938. divisionsFromNote = (noteDuration / 4) * 4;
  939. break;
  940. case "half":
  941. divisionsFromNote = (noteDuration / 4) * 2;
  942. break;
  943. case "whole":
  944. divisionsFromNote = (noteDuration / 4);
  945. break;
  946. case "breve":
  947. divisionsFromNote = (noteDuration / 4) / 2;
  948. break;
  949. case "long":
  950. divisionsFromNote = (noteDuration / 4) / 4;
  951. break;
  952. case "maxima":
  953. divisionsFromNote = (noteDuration / 4) / 8;
  954. break;
  955. default:
  956. break;
  957. }
  958. }
  959. }
  960. }
  961. if (divisionsFromNote > 0) {
  962. read = true;
  963. break;
  964. }
  965. }
  966. if (divisionsFromNote === 0) {
  967. xmlMeasureIndex++;
  968. if (xmlMeasureIndex === this.xmlMeasureList.length) {
  969. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
  970. throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
  971. }
  972. }
  973. }
  974. return divisionsFromNote;
  975. }
  976. }