InstrumentReader.ts 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  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",
  235. "Invalid divisions value at Instrument: ");
  236. Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg);
  237. this.divisions = this.readDivisionsFromNotes();
  238. if (this.divisions > 0) {
  239. this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
  240. } else {
  241. divisionsException = true;
  242. throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
  243. }
  244. }
  245. }
  246. if (
  247. xmlNode.element("divisions") === undefined &&
  248. this.divisions === 0 &&
  249. this.currentXmlMeasureIndex === 0
  250. ) {
  251. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/DivisionError", "Invalid divisions value at Instrument: ");
  252. this.divisions = this.readDivisionsFromNotes();
  253. if (this.divisions > 0) {
  254. this.musicSheet.SheetErrors.push(errorMsg + this.instrument.Name);
  255. } else {
  256. divisionsException = true;
  257. throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
  258. }
  259. }
  260. this.addAbstractInstruction(xmlNode, guitarPro);
  261. if (currentFraction.Equals(new Fraction(0, 1)) &&
  262. this.isAttributesNodeAtBeginOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
  263. this.saveAbstractInstructionList(this.instrument.Staves.length, true);
  264. }
  265. if (this.isAttributesNodeAtEndOfMeasure(this.xmlMeasureList[this.currentXmlMeasureIndex], xmlNode)) {
  266. this.saveClefInstructionAtEndOfMeasure();
  267. }
  268. } else if (xmlNode.name === "forward") {
  269. let forFraction: number = parseInt(xmlNode.element("duration").value, 10);
  270. currentFraction.Add(new Fraction(forFraction, 4 * this.divisions));
  271. } else if (xmlNode.name === "backup") {
  272. let backFraction: number = parseInt(xmlNode.element("duration").value, 10);
  273. currentFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
  274. if (currentFraction.Numerator < 0) {
  275. currentFraction = new Fraction(0, 1);
  276. }
  277. previousFraction.Sub(new Fraction(backFraction, 4 * this.divisions));
  278. if (previousFraction.Numerator < 0) {
  279. previousFraction = new Fraction(0, 1);
  280. }
  281. } else if (xmlNode.name === "direction") {
  282. // unused let directionTypeNode: IXmlElement = xmlNode.element("direction-type");
  283. // (*) MetronomeReader.readMetronomeInstructions(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
  284. let relativePositionInMeasure: number = Math.min(1, currentFraction.RealValue);
  285. if (this.activeRhythm !== undefined && this.activeRhythm.Rhythm !== undefined) {
  286. relativePositionInMeasure /= this.activeRhythm.Rhythm.RealValue;
  287. }
  288. // unused: let handeled: boolean = false;
  289. // (*) if (this.repetitionInstructionReader !== undefined) {
  290. // handeled = this.repetitionInstructionReader.handleRepetitionInstructionsFromWordsOrSymbols(directionTypeNode,
  291. // relativePositionInMeasure);
  292. //}
  293. //if (!handeled) {
  294. // let expressionReader: ExpressionReader = this.expressionReaders[0];
  295. // let staffIndex: number = this.readExpressionStaffNumber(xmlNode) - 1;
  296. // if (staffIndex < this.expressionReaders.length) {
  297. // expressionReader = this.expressionReaders[staffIndex];
  298. // }
  299. // if (expressionReader !== undefined) {
  300. // if (directionTypeNode.element("octave-shift") !== undefined) {
  301. // expressionReader.readExpressionParameters(
  302. // xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, true
  303. // );
  304. // expressionReader.addOctaveShift(xmlNode, this.currentMeasure, previousFraction.clone());
  305. // }
  306. // expressionReader.readExpressionParameters(
  307. // xmlNode, this.instrument, this.divisions, currentFraction, previousFraction, this.currentMeasure.MeasureNumber, false
  308. // );
  309. // expressionReader.read(xmlNode, this.currentMeasure, currentFraction);
  310. // }
  311. //}
  312. } else if (xmlNode.name === "barline") {
  313. // (*)
  314. //if (this.repetitionInstructionReader !== undefined) {
  315. // let measureEndsSystem: boolean = false;
  316. // this.repetitionInstructionReader.handleLineRepetitionInstructions(xmlNode, measureEndsSystem);
  317. // if (measureEndsSystem) {
  318. // this.currentMeasure.BreakSystemAfter = true;
  319. // this.currentMeasure.endsPiece = true;
  320. // }
  321. //}
  322. } else if (xmlNode.name === "sound") {
  323. // (*) MetronomeReader.readTempoInstruction(xmlNode, this.musicSheet, this.currentXmlMeasureIndex);
  324. } else if (xmlNode.name === "harmony") {
  325. // (*) this.openChordSymbolContainer = ChordSymbolReader.readChordSymbol(xmlNode, this.musicSheet, this.activeKey);
  326. }
  327. }
  328. for (let j in this.voiceGeneratorsDict) {
  329. if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
  330. let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[j];
  331. voiceGenerator.checkForOpenBeam();
  332. voiceGenerator.checkForOpenGraceNotes();
  333. }
  334. }
  335. if (this.currentXmlMeasureIndex === this.xmlMeasureList.length - 1) {
  336. for (let i: number = 0; i < this.instrument.Staves.length; i++) {
  337. if (!this.activeClefsHaveBeenInitialized[i]) {
  338. this.createDefaultClefInstruction(this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.instrument) + i);
  339. }
  340. }
  341. if (!this.activeKeyHasBeenInitialized) {
  342. this.createDefaultKeyInstruction();
  343. }
  344. // (*)
  345. //for (let i: number = 0; i < this.expressionReaders.length; i++) {
  346. // let reader: ExpressionReader = this.expressionReaders[i];
  347. // if (reader !== undefined) {
  348. // reader.checkForOpenExpressions(this.currentMeasure, currentFraction);
  349. // }
  350. //}
  351. }
  352. } catch (e) {
  353. if (divisionsException) {
  354. throw new MusicSheetReadingException(e.Message);
  355. }
  356. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MeasureError", "Error while reading Measure.");
  357. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  358. Logging.debug("InstrumentReader.readNextXmlMeasure", errorMsg, e);
  359. }
  360. this.previousMeasure = this.currentMeasure;
  361. this.currentXmlMeasureIndex += 1;
  362. return true;
  363. }
  364. public doCalculationsAfterDurationHasBeenSet(): void {
  365. for (let j in this.voiceGeneratorsDict) {
  366. if (this.voiceGeneratorsDict.hasOwnProperty(j)) {
  367. this.voiceGeneratorsDict[j].checkOpenTies();
  368. }
  369. }
  370. }
  371. private getOrCreateVoiceGenerator(voiceId: number, staffId: number): VoiceGenerator {
  372. let staff: Staff = this.instrument.Staves[staffId];
  373. let voiceGenerator: VoiceGenerator = this.voiceGeneratorsDict[voiceId];
  374. if (voiceGenerator !== undefined) {
  375. if (staff.Voices.indexOf(voiceGenerator.GetVoice) === -1) {
  376. staff.Voices.push(voiceGenerator.GetVoice);
  377. }
  378. } else {
  379. let mainVoiceGenerator: VoiceGenerator = this.staffMainVoiceGeneratorDict[staffId];
  380. if (mainVoiceGenerator !== undefined) {
  381. voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader, mainVoiceGenerator.GetVoice);
  382. staff.Voices.push(voiceGenerator.GetVoice);
  383. this.voiceGeneratorsDict[voiceId] = voiceGenerator;
  384. } else {
  385. voiceGenerator = new VoiceGenerator(this.instrument, voiceId, this.slurReader);
  386. staff.Voices.push(voiceGenerator.GetVoice);
  387. this.voiceGeneratorsDict[voiceId] = voiceGenerator;
  388. this.staffMainVoiceGeneratorDict[staffId] = voiceGenerator;
  389. }
  390. }
  391. return voiceGenerator;
  392. }
  393. //private createExpressionGenerators(numberOfStaves: number): void {
  394. // // (*)
  395. // //this.expressionReaders = new Array(numberOfStaves);
  396. // //for (let i: number = 0; i < numberOfStaves; i++) {
  397. // // this.expressionReaders[i] = MusicSymbolModuleFactory.createExpressionGenerator(this.musicSheet, this.instrument, i + 1);
  398. // //}
  399. //}
  400. private createDefaultClefInstruction(staffIndex: number): void {
  401. let first: SourceMeasure;
  402. if (this.musicSheet.SourceMeasures.length > 0) {
  403. first = this.musicSheet.SourceMeasures[0];
  404. } else {
  405. first = this.currentMeasure;
  406. }
  407. let clefInstruction: ClefInstruction = new ClefInstruction(ClefEnum.G, 0, 2);
  408. let firstStaffEntry: SourceStaffEntry;
  409. if (first.FirstInstructionsStaffEntries[staffIndex] === undefined) {
  410. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  411. first.FirstInstructionsStaffEntries[staffIndex] = firstStaffEntry;
  412. } else {
  413. firstStaffEntry = first.FirstInstructionsStaffEntries[staffIndex];
  414. firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
  415. }
  416. clefInstruction.Parent = firstStaffEntry;
  417. firstStaffEntry.Instructions.splice(0, 0, clefInstruction);
  418. }
  419. private createDefaultKeyInstruction(): void {
  420. let first: SourceMeasure;
  421. if (this.musicSheet.SourceMeasures.length > 0) {
  422. first = this.musicSheet.SourceMeasures[0];
  423. } else {
  424. first = this.currentMeasure;
  425. }
  426. let keyInstruction: KeyInstruction = new KeyInstruction(undefined, 0, KeyEnum.major);
  427. for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + this.instrument.Staves.length; j++) {
  428. if (first.FirstInstructionsStaffEntries[j] === undefined) {
  429. let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  430. first.FirstInstructionsStaffEntries[j] = firstStaffEntry;
  431. keyInstruction.Parent = firstStaffEntry;
  432. firstStaffEntry.Instructions.push(keyInstruction);
  433. } else {
  434. let firstStaffEntry: SourceStaffEntry = first.FirstInstructionsStaffEntries[j];
  435. keyInstruction.Parent = firstStaffEntry;
  436. firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
  437. if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
  438. firstStaffEntry.Instructions.splice(1, 0, keyInstruction);
  439. } else {
  440. firstStaffEntry.Instructions.splice(0, 0, keyInstruction);
  441. }
  442. }
  443. }
  444. }
  445. private isAttributesNodeAtBeginOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
  446. let children: IXmlElement[] = parentNode.elements();
  447. let attributesNodeIndex: number = children.indexOf(attributesNode); // FIXME | 0
  448. if (attributesNodeIndex > 0 && children[attributesNodeIndex - 1].name === "backup") {
  449. return true;
  450. }
  451. let firstNoteNodeIndex: number = -1;
  452. for (let i: number = 0; i < children.length; i++) {
  453. if (children[i].name === "note") {
  454. firstNoteNodeIndex = i;
  455. break;
  456. }
  457. }
  458. return (attributesNodeIndex < firstNoteNodeIndex && firstNoteNodeIndex > 0) || (firstNoteNodeIndex < 0);
  459. }
  460. private isAttributesNodeAtEndOfMeasure(parentNode: IXmlElement, attributesNode: IXmlElement): boolean {
  461. let childs: IXmlElement[] = parentNode.elements().slice();
  462. let attributesNodeIndex: number = 0;
  463. for (let i: number = 0; i < childs.length; i++) {
  464. if (childs[i] === attributesNode) {
  465. attributesNodeIndex = i;
  466. break;
  467. }
  468. }
  469. let nextNoteNodeIndex: number = 0;
  470. for (let i: number = attributesNodeIndex; i < childs.length; i++) {
  471. if (childs[i].name === "note") {
  472. nextNoteNodeIndex = i;
  473. break;
  474. }
  475. }
  476. return attributesNodeIndex > nextNoteNodeIndex;
  477. }
  478. private getNoteDurationFromTypeNode(xmlNode: IXmlElement): Fraction {
  479. if (xmlNode.element("type") !== undefined) {
  480. let typeNode: IXmlElement = xmlNode.element("type");
  481. if (typeNode !== undefined) {
  482. let type: string = typeNode.value;
  483. return this.currentVoiceGenerator.getNoteDurationFromType(type);
  484. }
  485. }
  486. return new Fraction(0, 4 * this.divisions);
  487. }
  488. private addAbstractInstruction(node: IXmlElement, guitarPro: boolean): void {
  489. if (node.element("divisions") !== undefined) {
  490. if (node.elements().length === 1) {
  491. return;
  492. }
  493. }
  494. let transposeNode: IXmlElement = node.element("transpose");
  495. if (transposeNode !== undefined) {
  496. let chromaticNode: IXmlElement = transposeNode.element("chromatic");
  497. if (chromaticNode !== undefined) {
  498. this.instrument.PlaybackTranspose = parseInt(chromaticNode.value, 10);
  499. }
  500. }
  501. let clefList: IXmlElement[] = node.elements("clef");
  502. let errorMsg: string;
  503. if (clefList.length > 0) {
  504. for (let idx: number = 0, len: number = clefList.length; idx < len; ++idx) {
  505. let nodeList: IXmlElement = clefList[idx];
  506. let clefEnum: ClefEnum = ClefEnum.G;
  507. let line: number = 2;
  508. let staffNumber: number = 1;
  509. let clefOctaveOffset: number = 0;
  510. let lineNode: IXmlElement = nodeList.element("line");
  511. if (lineNode !== undefined) {
  512. try {
  513. line = parseInt(lineNode.value, 10);
  514. } catch (ex) {
  515. errorMsg = ITextTranslation.translateText(
  516. "ReaderErrorMessages/ClefLineError",
  517. "Invalid clef line given -> using default clef line."
  518. );
  519. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  520. line = 2;
  521. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  522. }
  523. }
  524. let signNode: IXmlElement = nodeList.element("sign");
  525. if (signNode !== undefined) {
  526. try {
  527. clefEnum = ClefEnum[signNode.value];
  528. if (!ClefInstruction.isSupportedClef(clefEnum)) {
  529. if (clefEnum === ClefEnum.TAB && guitarPro) {
  530. clefOctaveOffset = -1;
  531. }
  532. errorMsg = ITextTranslation.translateText(
  533. "ReaderErrorMessages/ClefError",
  534. "Unsupported clef found -> using default clef."
  535. );
  536. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  537. clefEnum = ClefEnum.G;
  538. line = 2;
  539. }
  540. } catch (e) {
  541. errorMsg = ITextTranslation.translateText(
  542. "ReaderErrorMessages/ClefError",
  543. "Invalid clef found -> using default clef."
  544. );
  545. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  546. clefEnum = ClefEnum.G;
  547. line = 2;
  548. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, e);
  549. }
  550. }
  551. let clefOctaveNode: IXmlElement = nodeList.element("clef-octave-change");
  552. if (clefOctaveNode !== undefined) {
  553. try {
  554. clefOctaveOffset = parseInt(clefOctaveNode.value, 10);
  555. } catch (e) {
  556. errorMsg = ITextTranslation.translateText(
  557. "ReaderErrorMessages/ClefOctaveError",
  558. "Invalid clef octave found -> using default clef octave."
  559. );
  560. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  561. clefOctaveOffset = 0;
  562. }
  563. }
  564. if (nodeList.hasAttributes && nodeList.attributes()[0].name === "number") {
  565. try {
  566. staffNumber = parseInt(nodeList.attributes()[0].value, 10);
  567. } catch (err) {
  568. errorMsg = ITextTranslation.translateText(
  569. "ReaderErrorMessages/ClefError",
  570. "Invalid clef found -> using default clef."
  571. );
  572. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  573. staffNumber = 1;
  574. }
  575. }
  576. let clefInstruction: ClefInstruction = new ClefInstruction(clefEnum, clefOctaveOffset, line);
  577. this.abstractInstructions.push([staffNumber, clefInstruction]);
  578. }
  579. }
  580. if (node.element("key") !== undefined && this.instrument.MidiInstrumentId !== MidiInstrument.Percussion) {
  581. let key: number = 0;
  582. let keyNode: IXmlElement = node.element("key").element("fifths");
  583. if (keyNode !== undefined) {
  584. try {
  585. key = parseInt(keyNode.value, 10);
  586. } catch (ex) {
  587. errorMsg = ITextTranslation.translateText(
  588. "ReaderErrorMessages/KeyError",
  589. "Invalid key found -> set to default."
  590. );
  591. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  592. key = 0;
  593. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  594. }
  595. }
  596. let keyEnum: KeyEnum = KeyEnum.none;
  597. let modeNode: IXmlElement = node.element("key");
  598. if (modeNode !== undefined) {
  599. modeNode = modeNode.element("mode");
  600. }
  601. if (modeNode !== undefined) {
  602. try {
  603. keyEnum = KeyEnum[modeNode.value];
  604. } catch (ex) {
  605. errorMsg = ITextTranslation.translateText(
  606. "ReaderErrorMessages/KeyError",
  607. "Invalid key found -> set to default."
  608. );
  609. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  610. keyEnum = KeyEnum.major;
  611. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  612. }
  613. }
  614. let keyInstruction: KeyInstruction = new KeyInstruction(undefined, key, keyEnum);
  615. this.abstractInstructions.push([1, keyInstruction]);
  616. }
  617. if (node.element("time") !== undefined) {
  618. let symbolEnum: RhythmSymbolEnum = RhythmSymbolEnum.NONE;
  619. let timeNode: IXmlElement = node.element("time");
  620. if (timeNode !== undefined && timeNode.hasAttributes) {
  621. let firstAttr: IXmlAttribute = timeNode.firstAttribute;
  622. if (firstAttr.name === "symbol") {
  623. if (firstAttr.value === "common") {
  624. symbolEnum = RhythmSymbolEnum.COMMON;
  625. } else if (firstAttr.value === "cut") {
  626. symbolEnum = RhythmSymbolEnum.CUT;
  627. }
  628. }
  629. }
  630. let num: number = 0;
  631. let denom: number = 0;
  632. let senzaMisura: boolean = (timeNode !== undefined && timeNode.element("senza-misura") !== undefined);
  633. let timeList: IXmlElement[] = node.elements("time");
  634. let beatsList: IXmlElement[] = [];
  635. let typeList: IXmlElement[] = [];
  636. for (let idx: number = 0, len: number = timeList.length; idx < len; ++idx) {
  637. let xmlNode: IXmlElement = timeList[idx];
  638. beatsList.push.apply(beatsList, xmlNode.elements("beats"));
  639. typeList.push.apply(typeList, xmlNode.elements("beat-type"));
  640. }
  641. if (!senzaMisura) {
  642. try {
  643. if (beatsList !== undefined && beatsList.length > 0 && typeList !== undefined && beatsList.length === typeList.length) {
  644. let length: number = beatsList.length;
  645. let fractions: Fraction[] = new Array(length);
  646. let maxDenom: number = 0;
  647. for (let i: number = 0; i < length; i++) {
  648. let s: string = beatsList[i].value;
  649. let n: number = 0;
  650. let d: number = 0;
  651. if (s.indexOf("+") !== -1) {
  652. let numbers: string[] = s.split("+");
  653. for (let idx: number = 0, len: number = numbers.length; idx < len; ++idx) {
  654. n += parseInt(numbers[idx], 10);
  655. }
  656. } else {
  657. n = parseInt(s, 10);
  658. }
  659. d = parseInt(typeList[i].value, 10);
  660. maxDenom = Math.max(maxDenom, d);
  661. fractions[i] = new Fraction(n, d, false);
  662. }
  663. for (let i: number = 0; i < length; i++) {
  664. if (fractions[i].Denominator === maxDenom) {
  665. num += fractions[i].Numerator;
  666. } else {
  667. num += (maxDenom / fractions[i].Denominator) * fractions[i].Numerator;
  668. }
  669. }
  670. denom = maxDenom;
  671. } else {
  672. num = parseInt(node.element("time").element("beats").value, 10);
  673. denom = parseInt(node.element("time").element("beat-type").value, 10);
  674. }
  675. } catch (ex) {
  676. errorMsg = ITextTranslation.translateText("ReaderErrorMessages/RhythmError", "Invalid rhythm found -> set to default.");
  677. this.musicSheet.SheetErrors.pushMeasureError(errorMsg);
  678. num = 4;
  679. denom = 4;
  680. Logging.debug("InstrumentReader.addAbstractInstruction", errorMsg, ex);
  681. }
  682. if ((num === 4 && denom === 4) || (num === 2 && denom === 2)) {
  683. symbolEnum = RhythmSymbolEnum.NONE;
  684. }
  685. this.abstractInstructions.push([1, new RhythmInstruction(
  686. new Fraction(num, denom, false), num, denom, symbolEnum
  687. )]);
  688. } else {
  689. this.abstractInstructions.push([1, new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE)]);
  690. }
  691. }
  692. }
  693. private saveAbstractInstructionList(numberOfStaves: number, beginOfMeasure: boolean): void {
  694. for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
  695. let pair: [number, AbstractNotationInstruction] = this.abstractInstructions[i];
  696. let key: number = pair[0];
  697. let value: AbstractNotationInstruction = pair[1];
  698. if (value instanceof ClefInstruction) {
  699. let clefInstruction: ClefInstruction = <ClefInstruction>value;
  700. if (this.currentXmlMeasureIndex === 0 || (key <= this.activeClefs.length && clefInstruction !== this.activeClefs[key - 1])) {
  701. if (!beginOfMeasure && this.currentStaffEntry !== undefined && !this.currentStaffEntry.hasNotes() && key - 1
  702. === this.instrument.Staves.indexOf(this.currentStaffEntry.ParentStaff)) {
  703. let newClefInstruction: ClefInstruction = clefInstruction;
  704. newClefInstruction.Parent = this.currentStaffEntry;
  705. this.currentStaffEntry.removeFirstInstructionOfTypeClefInstruction();
  706. this.currentStaffEntry.Instructions.push(newClefInstruction);
  707. this.activeClefs[key - 1] = clefInstruction;
  708. this.abstractInstructions.splice(i, 1);
  709. } else if (beginOfMeasure) {
  710. let firstStaffEntry: SourceStaffEntry;
  711. if (this.currentMeasure !== undefined) {
  712. let newClefInstruction: ClefInstruction = clefInstruction;
  713. let sseIndex: number = this.inSourceMeasureInstrumentIndex + key - 1;
  714. let firstSse: SourceStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[sseIndex];
  715. if (this.currentXmlMeasureIndex === 0) {
  716. if (firstSse === undefined) {
  717. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  718. this.currentMeasure.FirstInstructionsStaffEntries[sseIndex] = firstStaffEntry;
  719. newClefInstruction.Parent = firstStaffEntry;
  720. firstStaffEntry.Instructions.push(newClefInstruction);
  721. this.activeClefsHaveBeenInitialized[key - 1] = true;
  722. } else if (this.currentMeasure.FirstInstructionsStaffEntries[sseIndex]
  723. !==
  724. undefined && !(firstSse.Instructions[0] instanceof ClefInstruction)) {
  725. firstStaffEntry = firstSse;
  726. newClefInstruction.Parent = firstStaffEntry;
  727. firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
  728. firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
  729. this.activeClefsHaveBeenInitialized[key - 1] = true;
  730. } else {
  731. let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  732. this.currentMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
  733. newClefInstruction.Parent = lastStaffEntry;
  734. lastStaffEntry.Instructions.push(newClefInstruction);
  735. }
  736. } else if (!this.activeClefsHaveBeenInitialized[key - 1]) {
  737. let first: SourceMeasure = this.musicSheet.SourceMeasures[0];
  738. if (first.FirstInstructionsStaffEntries[sseIndex] === undefined) {
  739. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  740. } else {
  741. firstStaffEntry = first.FirstInstructionsStaffEntries[sseIndex];
  742. firstStaffEntry.removeFirstInstructionOfTypeClefInstruction();
  743. }
  744. newClefInstruction.Parent = firstStaffEntry;
  745. firstStaffEntry.Instructions.splice(0, 0, newClefInstruction);
  746. this.activeClefsHaveBeenInitialized[key - 1] = true;
  747. } else {
  748. let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  749. this.previousMeasure.LastInstructionsStaffEntries[sseIndex] = lastStaffEntry;
  750. newClefInstruction.Parent = lastStaffEntry;
  751. lastStaffEntry.Instructions.push(newClefInstruction);
  752. }
  753. this.activeClefs[key - 1] = clefInstruction;
  754. this.abstractInstructions.splice(i, 1);
  755. }
  756. }
  757. }
  758. else if (key <= this.activeClefs.length && clefInstruction === this.activeClefs[key - 1]) {
  759. this.abstractInstructions.splice(i, 1);
  760. }
  761. }
  762. if (value instanceof KeyInstruction) {
  763. let keyInstruction: KeyInstruction = <KeyInstruction>value;
  764. if (this.activeKey === undefined || this.activeKey.Key !== keyInstruction.Key) {
  765. this.activeKey = keyInstruction;
  766. this.abstractInstructions.splice(i, 1);
  767. let sourceMeasure: SourceMeasure;
  768. if (!this.activeKeyHasBeenInitialized) {
  769. this.activeKeyHasBeenInitialized = true;
  770. if (this.currentXmlMeasureIndex > 0) {
  771. sourceMeasure = this.musicSheet.SourceMeasures[0];
  772. } else {
  773. sourceMeasure = this.currentMeasure;
  774. }
  775. } else {
  776. sourceMeasure = this.currentMeasure;
  777. }
  778. if (sourceMeasure !== undefined) {
  779. for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
  780. let newKeyInstruction: KeyInstruction = keyInstruction;
  781. if (sourceMeasure.FirstInstructionsStaffEntries[j] === undefined) {
  782. let firstStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  783. sourceMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
  784. newKeyInstruction.Parent = firstStaffEntry;
  785. firstStaffEntry.Instructions.push(newKeyInstruction);
  786. } else {
  787. let firstStaffEntry: SourceStaffEntry = sourceMeasure.FirstInstructionsStaffEntries[j];
  788. newKeyInstruction.Parent = firstStaffEntry;
  789. firstStaffEntry.removeFirstInstructionOfTypeKeyInstruction();
  790. if (firstStaffEntry.Instructions.length === 0) {
  791. firstStaffEntry.Instructions.push(newKeyInstruction);
  792. } else {
  793. if (firstStaffEntry.Instructions[0] instanceof ClefInstruction) {
  794. firstStaffEntry.Instructions.splice(1, 0, newKeyInstruction);
  795. } else {
  796. firstStaffEntry.Instructions.splice(0, 0, newKeyInstruction);
  797. }
  798. }
  799. }
  800. }
  801. }
  802. }
  803. else {
  804. this.abstractInstructions.splice(i, 1);
  805. }
  806. }
  807. if (value instanceof RhythmInstruction) {
  808. let rhythmInstruction: RhythmInstruction = <RhythmInstruction>value;
  809. if (this.activeRhythm === undefined || this.activeRhythm !== rhythmInstruction) {
  810. this.activeRhythm = rhythmInstruction;
  811. this.abstractInstructions.splice(i, 1);
  812. if (this.currentMeasure !== undefined) {
  813. for (let j: number = this.inSourceMeasureInstrumentIndex; j < this.inSourceMeasureInstrumentIndex + numberOfStaves; j++) {
  814. let newRhythmInstruction: RhythmInstruction = rhythmInstruction;
  815. let firstStaffEntry: SourceStaffEntry;
  816. if (this.currentMeasure.FirstInstructionsStaffEntries[j] === undefined) {
  817. firstStaffEntry = new SourceStaffEntry(undefined, undefined);
  818. this.currentMeasure.FirstInstructionsStaffEntries[j] = firstStaffEntry;
  819. } else {
  820. firstStaffEntry = this.currentMeasure.FirstInstructionsStaffEntries[j];
  821. firstStaffEntry.removeFirstInstructionOfTypeRhythmInstruction();
  822. }
  823. newRhythmInstruction.Parent = firstStaffEntry;
  824. firstStaffEntry.Instructions.push(newRhythmInstruction);
  825. }
  826. }
  827. }
  828. else {
  829. this.abstractInstructions.splice(i, 1);
  830. }
  831. }
  832. }
  833. }
  834. private saveClefInstructionAtEndOfMeasure(): void {
  835. for (let i: number = this.abstractInstructions.length - 1; i >= 0; i--) {
  836. let key: number = this.abstractInstructions[i][0];
  837. let value: AbstractNotationInstruction = this.abstractInstructions[i][1];
  838. if (value instanceof ClefInstruction) {
  839. let clefInstruction: ClefInstruction = <ClefInstruction>value;
  840. if (
  841. (this.activeClefs[key - 1] === undefined) ||
  842. (clefInstruction.ClefType !== this.activeClefs[key - 1].ClefType || (
  843. clefInstruction.ClefType === this.activeClefs[key - 1].ClefType &&
  844. clefInstruction.Line !== this.activeClefs[key - 1].Line
  845. ))) {
  846. let lastStaffEntry: SourceStaffEntry = new SourceStaffEntry(undefined, undefined);
  847. this.currentMeasure.LastInstructionsStaffEntries[this.inSourceMeasureInstrumentIndex + key - 1] = lastStaffEntry;
  848. let newClefInstruction: ClefInstruction = clefInstruction;
  849. newClefInstruction.Parent = lastStaffEntry;
  850. lastStaffEntry.Instructions.push(newClefInstruction);
  851. this.activeClefs[key - 1] = clefInstruction;
  852. this.abstractInstructions.splice(i, 1);
  853. }
  854. }
  855. }
  856. }
  857. private getNoteDurationForTuplet(xmlNode: IXmlElement): Fraction {
  858. let duration: Fraction = new Fraction(0, 1);
  859. let typeDuration: Fraction = this.getNoteDurationFromTypeNode(xmlNode);
  860. if (xmlNode.element("time-modification") !== undefined) {
  861. let time: IXmlElement = xmlNode.element("time-modification");
  862. if (time !== undefined) {
  863. if (time.element("actual-notes") !== undefined && time.element("normal-notes") !== undefined) {
  864. let actualNotes: IXmlElement = time.element("actual-notes");
  865. let normalNotes: IXmlElement = time.element("normal-notes");
  866. if (actualNotes !== undefined && normalNotes !== undefined) {
  867. let actual: number = parseInt(actualNotes.value, 10);
  868. let normal: number = parseInt(normalNotes.value, 10);
  869. duration = new Fraction(normal * typeDuration.Numerator, actual * typeDuration.Denominator);
  870. }
  871. }
  872. }
  873. }
  874. return duration;
  875. }
  876. //private readExpressionStaffNumber(xmlNode: IXmlElement): number {
  877. // let directionStaffNumber: number = 1;
  878. // if (xmlNode.element("staff") !== undefined) {
  879. // let staffNode: IXmlElement = xmlNode.element("staff");
  880. // if (staffNode !== undefined) {
  881. // try {
  882. // directionStaffNumber = parseInt(staffNode.value, 10);
  883. // } catch (ex) {
  884. // let errorMsg: string = ITextTranslation.translateText(
  885. // "ReaderErrorMessages/ExpressionStaffError", "Invalid Expression staff number -> set to default."
  886. // );
  887. // this.musicSheet.SheetErrors.pushTemp(errorMsg);
  888. // directionStaffNumber = 1;
  889. // logging.debug("InstrumentReader.readExpressionStaffNumber", errorMsg, ex);
  890. // }
  891. //
  892. // }
  893. // }
  894. // return directionStaffNumber;
  895. //}
  896. private readDivisionsFromNotes(): number {
  897. let divisionsFromNote: number = 0;
  898. let xmlMeasureIndex: number = this.currentXmlMeasureIndex;
  899. let read: boolean = false;
  900. while (!read) {
  901. let xmlMeasureListArr: IXmlElement[] = this.xmlMeasureList[xmlMeasureIndex].elements();
  902. for (let idx: number = 0, len: number = xmlMeasureListArr.length; idx < len; ++idx) {
  903. let xmlNode: IXmlElement = xmlMeasureListArr[idx];
  904. if (xmlNode.name === "note" && xmlNode.element("time-modification") === undefined) {
  905. if (xmlNode.element("duration") !== undefined && xmlNode.element("type") !== undefined) {
  906. let durationNode: IXmlElement = xmlNode.element("duration");
  907. let typeNode: IXmlElement = xmlNode.element("type");
  908. if (durationNode !== undefined && typeNode !== undefined) {
  909. let type: string = typeNode.value;
  910. let noteDuration: number = 0;
  911. try {
  912. noteDuration = parseInt(durationNode.value, 10);
  913. } catch (ex) {
  914. Logging.debug("InstrumentReader.readDivisionsFromNotes", ex);
  915. continue;
  916. }
  917. switch (type) {
  918. case "1024th":
  919. divisionsFromNote = (noteDuration / 4) * 1024;
  920. break;
  921. case "512th":
  922. divisionsFromNote = (noteDuration / 4) * 512;
  923. break;
  924. case "256th":
  925. divisionsFromNote = (noteDuration / 4) * 256;
  926. break;
  927. case "128th":
  928. divisionsFromNote = (noteDuration / 4) * 128;
  929. break;
  930. case "64th":
  931. divisionsFromNote = (noteDuration / 4) * 64;
  932. break;
  933. case "32nd":
  934. divisionsFromNote = (noteDuration / 4) * 32;
  935. break;
  936. case "16th":
  937. divisionsFromNote = (noteDuration / 4) * 16;
  938. break;
  939. case "eighth":
  940. divisionsFromNote = (noteDuration / 4) * 8;
  941. break;
  942. case "quarter":
  943. divisionsFromNote = (noteDuration / 4) * 4;
  944. break;
  945. case "half":
  946. divisionsFromNote = (noteDuration / 4) * 2;
  947. break;
  948. case "whole":
  949. divisionsFromNote = (noteDuration / 4);
  950. break;
  951. case "breve":
  952. divisionsFromNote = (noteDuration / 4) / 2;
  953. break;
  954. case "long":
  955. divisionsFromNote = (noteDuration / 4) / 4;
  956. break;
  957. case "maxima":
  958. divisionsFromNote = (noteDuration / 4) / 8;
  959. break;
  960. default:
  961. break;
  962. }
  963. }
  964. }
  965. }
  966. if (divisionsFromNote > 0) {
  967. read = true;
  968. break;
  969. }
  970. }
  971. if (divisionsFromNote === 0) {
  972. xmlMeasureIndex++;
  973. if (xmlMeasureIndex === this.xmlMeasureList.length) {
  974. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMEssages/DivisionsError", "Invalid divisions value at Instrument: ");
  975. throw new MusicSheetReadingException(errorMsg + this.instrument.Name);
  976. }
  977. }
  978. }
  979. return divisionsFromNote;
  980. }
  981. }