InstrumentReader.ts 48 KB

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