InstrumentReader.ts 48 KB

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