MusicSheetReader.ts 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. import {MusicSheet} from "../MusicSheet";
  2. import {SourceMeasure} from "../VoiceData/SourceMeasure";
  3. import {Fraction} from "../../Common/DataObjects/fraction";
  4. import {InstrumentReader} from "./InstrumentReader";
  5. import {IXmlElement} from "../../Common/FileIO/Xml";
  6. import {Instrument} from "../Instrument";
  7. import {ITextTranslation} from "../Interfaces/ITextTranslation";
  8. import {MusicSheetReadingException} from "../Exceptions";
  9. import {logging} from "../../Common/logging";
  10. import {IXmlAttribute} from "../../Common/FileIO/Xml";
  11. import {RhythmInstruction} from "../VoiceData/Instructions/RhythmInstruction";
  12. import {RhythmSymbolEnum} from "../VoiceData/Instructions/RhythmInstruction";
  13. import {SourceStaffEntry} from "../VoiceData/SourceStaffEntry";
  14. import {VoiceEntry} from "../VoiceData/VoiceEntry";
  15. import {Label} from "../Label";
  16. import {InstrumentalGroup} from "../InstrumentalGroup";
  17. import {SubInstrument} from "../SubInstrument";
  18. import {MidiInstrument} from "../VoiceData/Instructions/ClefInstruction";
  19. import {AbstractNotationInstruction} from "../VoiceData/Instructions/AbstractNotationInstruction";
  20. type IPhonicScoreInterface = any;
  21. type RepetitionInstructionReader = any;
  22. export class MusicSheetReader /*implements IMusicSheetReader*/ {
  23. //constructor(afterSheetReadingModules: IAfterSheetReadingModule[]) {
  24. // if (afterSheetReadingModules === undefined) {
  25. // this.afterSheetReadingModules = [];
  26. // } else {
  27. // this.afterSheetReadingModules = afterSheetReadingModules;
  28. // }
  29. // this.repetitionInstructionReader = MusicSymbolModuleFactory.createRepetitionInstructionReader();
  30. // this.repetitionCalculator = MusicSymbolModuleFactory.createRepetitionCalculator();
  31. //}
  32. private phonicScoreInterface: IPhonicScoreInterface;
  33. private repetitionInstructionReader: RepetitionInstructionReader;
  34. // private repetitionCalculator: RepetitionCalculator;
  35. // private afterSheetReadingModules: IAfterSheetReadingModule[];
  36. private musicSheet: MusicSheet;
  37. private completeNumberOfStaves: number = 0;
  38. private currentMeasure: SourceMeasure;
  39. private previousMeasure: SourceMeasure;
  40. private currentFraction: Fraction;
  41. public get CompleteNumberOfStaves(): number {
  42. return this.completeNumberOfStaves;
  43. }
  44. private static doCalculationsAfterDurationHasBeenSet(instrumentReaders: InstrumentReader[]): void {
  45. for (let instrumentReader of instrumentReaders) {
  46. instrumentReader.doCalculationsAfterDurationHasBeenSet();
  47. }
  48. }
  49. //public SetPhonicScoreInterface(phonicScoreInterface: IPhonicScoreInterface): void {
  50. // this.phonicScoreInterface = phonicScoreInterface;
  51. //}
  52. //public ReadMusicSheetParameters(sheetObject: MusicSheetParameterObject, root: IXmlElement, path: string): MusicSheetParameterObject {
  53. // this.musicSheet = new MusicSheet();
  54. // if (root !== undefined) {
  55. // this.pushSheetLabels(root, path);
  56. // if (this.musicSheet.Title !== undefined) {
  57. // sheetObject.Title = this.musicSheet.Title.Text;
  58. // }
  59. // if (this.musicSheet.Composer !== undefined) {
  60. // sheetObject.Composer = this.musicSheet.Composer.Text;
  61. // }
  62. // if (this.musicSheet.Lyricist !== undefined) {
  63. // sheetObject.Lyricist = this.musicSheet.Lyricist.Text;
  64. // }
  65. // let partlistNode: IXmlElement = root.Element("part-list");
  66. // let partList: IXmlElement[] = partlistNode.Elements();
  67. // this.createInstrumentGroups(partList);
  68. // for (let idx: number = 0, len: number = this.musicSheet.Instruments.length; idx < len; ++idx) {
  69. // let instr: Instrument = this.musicSheet.Instruments[idx];
  70. // sheetObject.InstrumentList.push(__init(new MusicSheetParameterObject.LibrarySheetInstrument(), { Name: instr.Name }));
  71. // }
  72. // }
  73. // return sheetObject;
  74. //}
  75. public createMusicSheet(root: IXmlElement, path: string): MusicSheet {
  76. try {
  77. return this._createMusicSheet(root, path);
  78. } catch (e) {
  79. logging.log("MusicSheetReader.CreateMusicSheet", e);
  80. }
  81. }
  82. //public CreateIMusicSheet(root: IXmlElement, path: string): IMusicSheet {
  83. // return this.createMusicSheet(root, path);
  84. //}
  85. private _removeFromArray(list: any[], elem: any) {
  86. let i: number = list.indexOf(elem);
  87. if (i !== -1) {
  88. list.splice(i, 1);
  89. }
  90. }
  91. private _createMusicSheet(root: IXmlElement, path: string): MusicSheet {
  92. let instrumentReaders: InstrumentReader[] = [];
  93. let sourceMeasureCounter: number = 0;
  94. this.musicSheet = new MusicSheet();
  95. this.musicSheet.Path = path;
  96. try {
  97. if (root !== undefined) {
  98. // this.pushSheetLabels(root, path); // FIXME Andrea
  99. let partlistNode: IXmlElement = root.Element("part-list");
  100. if (partlistNode !== undefined) {
  101. let partInst: IXmlElement[] = root.Elements("part");
  102. let partList: IXmlElement[] = partlistNode.Elements();
  103. this.initializeReading(partList, partInst, instrumentReaders);
  104. let couldReadMeasure: boolean = true;
  105. this.currentFraction = new Fraction(0, 1);
  106. let guitarPro: boolean = false;
  107. let encoding: IXmlElement = root.Element("identification");
  108. if (encoding !== undefined) {
  109. encoding = encoding.Element("encoding");
  110. }
  111. if (encoding !== undefined) {
  112. encoding = encoding.Element("software");
  113. }
  114. if (encoding !== undefined && encoding.Value === "Guitar Pro 5") {
  115. guitarPro = true;
  116. }
  117. while (couldReadMeasure) {
  118. if (this.currentMeasure !== undefined && this.currentMeasure.EndsPiece) {
  119. sourceMeasureCounter = 0;
  120. }
  121. this.currentMeasure = new SourceMeasure(this.completeNumberOfStaves);
  122. for (let instrumentReader of instrumentReaders) {
  123. try {
  124. couldReadMeasure = instrumentReader.readNextXmlMeasure(this.currentMeasure, this.currentFraction, guitarPro);
  125. } catch (e) {
  126. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/InstrumentError", "Error while reading instruments.");
  127. throw new MusicSheetReadingException(errorMsg, e);
  128. }
  129. }
  130. if (couldReadMeasure) {
  131. this.musicSheet.addMeasure(this.currentMeasure);
  132. this.checkIfRhythmInstructionsAreSetAndEqual(instrumentReaders);
  133. this.checkSourceMeasureForundefinedEntries();
  134. this.setSourceMeasureDuration(instrumentReaders, sourceMeasureCounter);
  135. MusicSheetReader.doCalculationsAfterDurationHasBeenSet(instrumentReaders);
  136. this.currentMeasure.AbsoluteTimestamp = this.currentFraction.clone();
  137. this.musicSheet.SheetErrors.TransferTempErrorsToDict(this.currentMeasure.MeasureNumber);
  138. this.currentFraction.Add(this.currentMeasure.Duration);
  139. this.previousMeasure = this.currentMeasure;
  140. }
  141. }
  142. }
  143. }
  144. //if (this.repetitionInstructionReader !== undefined) {
  145. // this.repetitionInstructionReader.removeRedundantInstructions();
  146. // if (this.repetitionCalculator !== undefined) {
  147. // this.repetitionCalculator.calculateRepetitions(this.musicSheet, this.repetitionInstructionReader.RepetitionInstructions);
  148. // }
  149. //}
  150. this.musicSheet.checkForInstrumentWithNoVoice();
  151. this.musicSheet.fillStaffList();
  152. //this.musicSheet.DefaultStartTempoInBpm = this.musicSheet.SheetPlaybackSetting.BeatsPerMinute;
  153. //for (let idx: number = 0, len: number = this.afterSheetReadingModules.length; idx < len; ++idx) {
  154. // let afterSheetReadingModule: IAfterSheetReadingModule = this.afterSheetReadingModules[idx];
  155. // afterSheetReadingModule.calculate(this.musicSheet);
  156. //}
  157. } catch (e) {
  158. logging.log("MusicSheetReader._createMusicSheet", e);
  159. }
  160. return this.musicSheet;
  161. }
  162. // Trim from a string also newlines
  163. private trimString(str: string): string {
  164. return str.replace(/^\s+|\s+$/g, "");
  165. }
  166. private _lastElement<T>(list: T[]): T {
  167. return list[list.length -1];
  168. }
  169. private initializeReading(
  170. partList: IXmlElement[], partInst: IXmlElement[], instrumentReaders: InstrumentReader[]
  171. ): void {
  172. let instrumentDict: { [_:string]: Instrument; } = this.createInstrumentGroups(partList);
  173. this.completeNumberOfStaves = this.getCompleteNumberOfStavesFromXml(partInst);
  174. if (partInst.length !== 0) {
  175. // (*) this.repetitionInstructionReader.MusicSheet = this.musicSheet;
  176. this.currentFraction = new Fraction(0, 1);
  177. this.currentMeasure = undefined;
  178. this.previousMeasure = undefined;
  179. }
  180. let counter: number = 0;
  181. let partInstArr: IXmlElement[] = partInst.slice();
  182. for (let idx: number = 0, len: number = partInstArr.length; idx < len; ++idx) {
  183. let node: IXmlElement = partInstArr[idx];
  184. if (node.Attribute("id") !== undefined) {
  185. let idNode: IXmlAttribute = node.Attribute("id");
  186. if (idNode !== undefined) {
  187. let partInstId: string = idNode.Value;
  188. let currentInstrument: Instrument = instrumentDict[partInstId];
  189. let xmlMeasureList: IXmlElement[] = node.Elements("measure");
  190. let instrumentNumberOfStaves: number = 1;
  191. try {
  192. instrumentNumberOfStaves = this.getInstrumentNumberOfStavesFromXml(node);
  193. } catch (err) {
  194. let errorMsg: string = ITextTranslation.translateText(
  195. "ReaderErrorMessages/InstrumentStavesNumberError",
  196. "Invalid number of staves at instrument: "
  197. );
  198. this.musicSheet.SheetErrors.push(errorMsg + currentInstrument.Name);
  199. continue;
  200. }
  201. currentInstrument.createStaves(instrumentNumberOfStaves);
  202. let instrumentReader: InstrumentReader = new InstrumentReader(this.repetitionInstructionReader, xmlMeasureList, currentInstrument);
  203. instrumentReaders.push(instrumentReader);
  204. //if (this.repetitionInstructionReader !== undefined) {
  205. // this.repetitionInstructionReader.XmlMeasureList[counter] = xmlMeasureList;
  206. //}
  207. counter++;
  208. }
  209. }
  210. }
  211. }
  212. private checkIfRhythmInstructionsAreSetAndEqual(instrumentReaders: InstrumentReader[]): void {
  213. let rhythmInstructions: RhythmInstruction[] = [];
  214. for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
  215. if (this.currentMeasure.FirstInstructionsStaffEntries[i] !== undefined) {
  216. let last = this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions[this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.length - 1];
  217. if (last instanceof RhythmInstruction) {
  218. rhythmInstructions.push(<RhythmInstruction>last);
  219. }
  220. }
  221. }
  222. let maxRhythmValue: number = 0.0;
  223. let index: number = -1;
  224. for (let idx: number = 0, len: number = rhythmInstructions.length; idx < len; ++idx) {
  225. let rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
  226. if (rhythmInstruction.Rhythm.RealValue > maxRhythmValue) {
  227. if (this.areRhythmInstructionsMixed(rhythmInstructions) && rhythmInstruction.SymbolEnum !== RhythmSymbolEnum.NONE) { continue; }
  228. maxRhythmValue = rhythmInstruction.Rhythm.RealValue;
  229. index = rhythmInstructions.indexOf(rhythmInstruction);
  230. }
  231. }
  232. if (rhythmInstructions.length > 0 && rhythmInstructions.length < this.completeNumberOfStaves) {
  233. let rhythmInstruction: RhythmInstruction = new RhythmInstruction(rhythmInstructions[index]);
  234. for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
  235. if (
  236. this.currentMeasure.FirstInstructionsStaffEntries[i] !== undefined &&
  237. !(this._lastElement(this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions) instanceof RhythmInstruction)
  238. ) {
  239. this.currentMeasure.FirstInstructionsStaffEntries[i].removeAllInstructionsOfType<RhythmInstruction>();
  240. this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.push(new RhythmInstruction(rhythmInstruction));
  241. }
  242. if (this.currentMeasure.FirstInstructionsStaffEntries[i] === undefined) {
  243. this.currentMeasure.FirstInstructionsStaffEntries[i] = new SourceStaffEntry(undefined, undefined);
  244. this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.push(new RhythmInstruction(rhythmInstruction));
  245. }
  246. }
  247. for (let idx: number = 0, len: number = instrumentReaders.length; idx < len; ++idx) {
  248. let instrumentReader: InstrumentReader = instrumentReaders[idx];
  249. instrumentReader.ActiveRhythm = rhythmInstruction;
  250. }
  251. }
  252. if (rhythmInstructions.length === 0 && this.currentMeasure === this.musicSheet.SourceMeasures[0]) {
  253. let rhythmInstruction: RhythmInstruction = new RhythmInstruction(new Fraction(4, 4, false), 4, 4, RhythmSymbolEnum.NONE);
  254. for (let i: number = 0; i < this.completeNumberOfStaves; i++) {
  255. if (this.currentMeasure.FirstInstructionsStaffEntries[i] === undefined) {
  256. this.currentMeasure.FirstInstructionsStaffEntries[i] = new SourceStaffEntry(undefined, undefined);
  257. } else {
  258. this.currentMeasure.FirstInstructionsStaffEntries[i].removeAllInstructionsOfType<RhythmInstruction>();
  259. }
  260. this.currentMeasure.FirstInstructionsStaffEntries[i].Instructions.push(rhythmInstruction);
  261. }
  262. for (let idx: number = 0, len: number = instrumentReaders.length; idx < len; ++idx) {
  263. let instrumentReader: InstrumentReader = instrumentReaders[idx];
  264. instrumentReader.ActiveRhythm = rhythmInstruction;
  265. }
  266. }
  267. for (let idx: number = 0, len: number = rhythmInstructions.length; idx < len; ++idx) {
  268. let rhythmInstruction: RhythmInstruction = rhythmInstructions[idx];
  269. if (rhythmInstruction.Rhythm.RealValue < maxRhythmValue) {
  270. if (this._lastElement(this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.indexOf(rhythmInstruction)].Instructions) instanceof RhythmInstruction) {
  271. // TODO Test correctness
  272. let instrs: AbstractNotationInstruction[] = this.currentMeasure.FirstInstructionsStaffEntries[rhythmInstructions.indexOf(rhythmInstruction)].Instructions;
  273. instrs[instrs.length - 1] = new RhythmInstruction(rhythmInstructions[index]);
  274. }
  275. }
  276. if (
  277. Math.abs(rhythmInstruction.Rhythm.RealValue - maxRhythmValue) < 0.000001 &&
  278. rhythmInstruction.SymbolEnum !== RhythmSymbolEnum.NONE &&
  279. this.areRhythmInstructionsMixed(rhythmInstructions)
  280. ) {
  281. rhythmInstruction.SymbolEnum = RhythmSymbolEnum.NONE;
  282. }
  283. }
  284. }
  285. private areRhythmInstructionsMixed(rhythmInstructions: RhythmInstruction[]): boolean {
  286. for (let i: number = 1; i < rhythmInstructions.length; i++) {
  287. if (
  288. Math.abs(rhythmInstructions[i].Rhythm.RealValue - rhythmInstructions[0].Rhythm.RealValue) < 0.000001 &&
  289. rhythmInstructions[i].SymbolEnum !== rhythmInstructions[0].SymbolEnum
  290. ) { return true; }
  291. }
  292. return false;
  293. }
  294. private setSourceMeasureDuration(
  295. instrumentReaders: InstrumentReader[], sourceMeasureCounter: number
  296. ): void {
  297. let activeRhythm: Fraction = new Fraction(0, 1);
  298. let instrumentsMaxTieNoteFractions: Fraction[] = [];
  299. for (let idx: number = 0, len: number = instrumentReaders.length; idx < len; ++idx) {
  300. let instrumentReader: InstrumentReader = instrumentReaders[idx];
  301. instrumentsMaxTieNoteFractions.push(instrumentReader.MaxTieNoteFraction);
  302. let activeRythmMeasure: Fraction = instrumentReader.ActiveRhythm.Rhythm;
  303. if (activeRhythm < activeRythmMeasure) {
  304. activeRhythm = new Fraction(activeRythmMeasure.Numerator, activeRythmMeasure.Denominator, false);
  305. }
  306. }
  307. let instrumentsDurations: Fraction[] = this.currentMeasure.calculateInstrumentsDuration(this.musicSheet, instrumentsMaxTieNoteFractions);
  308. let maxInstrumentDuration: Fraction = new Fraction(0, 1);
  309. for (let idx: number = 0, len: number = instrumentsDurations.length; idx < len; ++idx) {
  310. let instrumentsDuration: Fraction = instrumentsDurations[idx];
  311. if (maxInstrumentDuration < instrumentsDuration) {
  312. maxInstrumentDuration = instrumentsDuration;
  313. }
  314. }
  315. if (Fraction.Equal(maxInstrumentDuration, activeRhythm)) {
  316. this.checkFractionsForEquivalence(maxInstrumentDuration, activeRhythm);
  317. } else {
  318. if (maxInstrumentDuration < activeRhythm) {
  319. maxInstrumentDuration = this.currentMeasure.reverseCheck(this.musicSheet, maxInstrumentDuration);
  320. this.checkFractionsForEquivalence(maxInstrumentDuration, activeRhythm);
  321. }
  322. }
  323. this.currentMeasure.ImplicitMeasure = this.checkIfMeasureIsImplicit(maxInstrumentDuration, activeRhythm);
  324. if (!this.currentMeasure.ImplicitMeasure) {
  325. sourceMeasureCounter++;
  326. }
  327. this.currentMeasure.Duration = maxInstrumentDuration;
  328. this.currentMeasure.MeasureNumber = sourceMeasureCounter;
  329. for (let i: number = 0; i < instrumentsDurations.length; i++) {
  330. let instrumentsDuration: Fraction = instrumentsDurations[i];
  331. if (
  332. (this.currentMeasure.ImplicitMeasure && instrumentsDuration !== maxInstrumentDuration) ||
  333. instrumentsDuration !== activeRhythm && // FIXME
  334. !this.allInstrumentsHaveSameDuration(instrumentsDurations, maxInstrumentDuration)
  335. ) {
  336. let firstStaffIndexOfInstrument: number = this.musicSheet.getGlobalStaffIndexOfFirstStaff(this.musicSheet.Instruments[i]);
  337. for (let staffIndex: number = 0; staffIndex < this.musicSheet.Instruments[i].Staves.length; staffIndex++) {
  338. if (!this.staffMeasureIsEmpty(firstStaffIndexOfInstrument + staffIndex)) {
  339. this.currentMeasure.setErrorInStaffMeasure(firstStaffIndexOfInstrument + staffIndex, true);
  340. let errorMsg: string = ITextTranslation.translateText("ReaderErrorMessages/MissingNotesError", "Given Notes don't correspond to measure duration.");
  341. this.musicSheet.SheetErrors.pushTemp(errorMsg);
  342. }
  343. }
  344. }
  345. }
  346. }
  347. private checkFractionsForEquivalence(maxInstrumentDuration: Fraction, activeRhythm: Fraction): void {
  348. if (activeRhythm.Denominator > maxInstrumentDuration.Denominator) {
  349. let factor: number = activeRhythm.Denominator / maxInstrumentDuration.Denominator;
  350. maxInstrumentDuration.multiplyWithFactor(factor);
  351. }
  352. }
  353. private checkIfMeasureIsImplicit(maxInstrumentDuration: Fraction, activeRhythm: Fraction): boolean {
  354. if (this.previousMeasure === undefined && maxInstrumentDuration < activeRhythm) { return true; }
  355. if (this.previousMeasure !== undefined) {
  356. return (this.previousMeasure.Duration + maxInstrumentDuration === activeRhythm);
  357. }
  358. return false;
  359. }
  360. private allInstrumentsHaveSameDuration(
  361. instrumentsDurations: Fraction[], maxInstrumentDuration: Fraction
  362. ): boolean {
  363. let counter: number = 0;
  364. for (let idx: number = 0, len: number = instrumentsDurations.length; idx < len; ++idx) {
  365. let instrumentsDuration: Fraction = instrumentsDurations[idx];
  366. if (instrumentsDuration === maxInstrumentDuration) { counter++; }
  367. }
  368. return (counter === instrumentsDurations.length && maxInstrumentDuration !== new Fraction(0, 1));
  369. }
  370. private staffMeasureIsEmpty(index: number): boolean {
  371. let counter: number = 0;
  372. for (let i: number = 0; i < this.currentMeasure.VerticalSourceStaffEntryContainers.length; i++) {
  373. if (this.currentMeasure.VerticalSourceStaffEntryContainers[i][index] === undefined) { counter++; }
  374. }
  375. return (counter === this.currentMeasure.VerticalSourceStaffEntryContainers.length);
  376. }
  377. private checkSourceMeasureForundefinedEntries(): void {
  378. for (let i: number = this.currentMeasure.VerticalSourceStaffEntryContainers.length - 1; i >= 0; i--) {
  379. for (let j: number = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.length - 1; j >= 0; j--) {
  380. let sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[j];
  381. if (sourceStaffEntry !== undefined) {
  382. for (let k: number = sourceStaffEntry.VoiceEntries.length - 1; k >= 0; k--) {
  383. let voiceEntry: VoiceEntry = sourceStaffEntry.VoiceEntries[k];
  384. if (voiceEntry.Notes.length === 0) {
  385. this._removeFromArray(voiceEntry.ParentVoice.VoiceEntries, voiceEntry);
  386. this._removeFromArray(sourceStaffEntry.VoiceEntries, voiceEntry);
  387. }
  388. }
  389. }
  390. if (sourceStaffEntry !== undefined && sourceStaffEntry.VoiceEntries.length === 0) {
  391. this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[j] = undefined;
  392. }
  393. }
  394. }
  395. for (let i: number = this.currentMeasure.VerticalSourceStaffEntryContainers.length - 1; i >= 0; i--) {
  396. let counter: number = 0;
  397. for (let idx: number = 0, len: number = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.length; idx < len; ++idx) {
  398. let sourceStaffEntry: SourceStaffEntry = this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries[idx];
  399. if (sourceStaffEntry === undefined) { counter++; }
  400. }
  401. if (counter === this.currentMeasure.VerticalSourceStaffEntryContainers[i].StaffEntries.length) {
  402. this._removeFromArray(this.currentMeasure.VerticalSourceStaffEntryContainers, this.currentMeasure.VerticalSourceStaffEntryContainers[i]);
  403. }
  404. }
  405. }
  406. private addSheetLabels(root: IXmlElement, filePath: string): void {
  407. this.readComposer(root);
  408. this.readTitle(root);
  409. if (this.musicSheet.Title === undefined || this.musicSheet.Composer === undefined) {
  410. this.readTitleAndComposerFromCredits(root);
  411. }
  412. if (this.musicSheet.Title === undefined) {
  413. try {
  414. let bar_i: number = Math.max(
  415. 0, filePath.lastIndexOf("/"), filePath.lastIndexOf("\\")
  416. );
  417. let filename: string = filePath.substr(bar_i);
  418. let filenameSplits: string[] = filename.split(".", 1);
  419. this.musicSheet.Title = new Label(filenameSplits[0]);
  420. } catch (ex) {
  421. logging.log("MusicSheetReader.pushSheetLabels: ", ex);
  422. }
  423. }
  424. }
  425. // Checks whether _elem_ has an attribute with value _val_.
  426. private presentAttrsWithValue(elem: IXmlElement, val: string): boolean {
  427. for (let attr of elem.Attributes()) {
  428. if (attr.Value === val) { return true; }
  429. }
  430. return false;
  431. }
  432. private readComposer(root: IXmlElement): void {
  433. let identificationNode: IXmlElement = root.Element("identification");
  434. if (identificationNode !== undefined) {
  435. let creators: IXmlElement[] = identificationNode.Elements("creator");
  436. for (let idx: number = 0, len: number = creators.length; idx < len; ++idx) {
  437. let creator: IXmlElement = creators[idx];
  438. if (creator.HasAttributes) {
  439. if (this.presentAttrsWithValue(creator, "composer")) {
  440. this.musicSheet.Composer = new Label(this.trimString(creator.Value));
  441. continue;
  442. }
  443. if (this.presentAttrsWithValue(creator, "lyricist") || this.presentAttrsWithValue(creator, "poet")) {
  444. this.musicSheet.Lyricist = new Label(this.trimString(creator.Value));
  445. }
  446. }
  447. }
  448. }
  449. }
  450. private readTitleAndComposerFromCredits(root: IXmlElement): void {
  451. let systemYCoordinates: number = this.computeSystemYCoordinates(root);
  452. if (systemYCoordinates === 0) { return; }
  453. let largestTitleCreditSize: number = 1;
  454. let finalTitle: string = undefined;
  455. let largestCreditYInfo: number = 0;
  456. let finalSubtitle: string = undefined;
  457. let possibleTitle: string = undefined;
  458. let creditElements: IXmlElement[] = root.Elements("credit");
  459. for (let idx: number = 0, len: number = creditElements.length; idx < len; ++idx) {
  460. let credit: IXmlElement = creditElements[idx];
  461. if (credit.Attribute("page") === undefined) { return; }
  462. if (credit.Attribute("page").Value === "1") {
  463. let creditChild: IXmlElement = undefined;
  464. if (credit !== undefined) {
  465. creditChild = credit.Element("credit-words");
  466. if (creditChild.Attribute("justify") === undefined) {
  467. break;
  468. }
  469. let creditJustify: string = creditChild.Attribute("justify").Value;
  470. let creditY: string = creditChild.Attribute("default-y").Value;
  471. let creditYInfo: number = parseFloat(creditY);
  472. if (creditYInfo > systemYCoordinates) {
  473. if (this.musicSheet.Title === undefined) {
  474. let creditSize: string = creditChild.Attribute("font-size").Value;
  475. let titleCreditSizeInt: number = parseFloat(creditSize);
  476. if (largestTitleCreditSize < titleCreditSizeInt) {
  477. largestTitleCreditSize = titleCreditSizeInt;
  478. finalTitle = creditChild.Value;
  479. }
  480. }
  481. if (this.musicSheet.Subtitle === undefined) {
  482. if (creditJustify !== "right" && creditJustify !== "left") {
  483. if (largestCreditYInfo < creditYInfo) {
  484. largestCreditYInfo = creditYInfo;
  485. if (possibleTitle) {
  486. finalSubtitle = possibleTitle;
  487. possibleTitle = creditChild.Value;
  488. } else {
  489. possibleTitle = creditChild.Value;
  490. }
  491. }
  492. }
  493. }
  494. if (!(this.musicSheet.Composer !== undefined && this.musicSheet.Lyricist !== undefined)) {
  495. switch (creditJustify) {
  496. case "right":
  497. this.musicSheet.Composer = new Label(this.trimString(creditChild.Value));
  498. break;
  499. case "left":
  500. this.musicSheet.Lyricist = new Label(this.trimString(creditChild.Value));
  501. break;
  502. default: break;
  503. }
  504. }
  505. }
  506. }
  507. }
  508. }
  509. if (this.musicSheet.Title === undefined && finalTitle) {
  510. this.musicSheet.Title = new Label(this.trimString(finalTitle));
  511. }
  512. if (this.musicSheet.Subtitle === undefined && finalSubtitle) {
  513. this.musicSheet.Subtitle = new Label(this.trimString(finalSubtitle));
  514. }
  515. }
  516. private computeSystemYCoordinates(root: IXmlElement): number {
  517. if (root.Element("defaults") === undefined) {
  518. return 0;
  519. }
  520. let paperHeight: number = 0;
  521. let topSystemDistance: number = 0;
  522. let defi: string = root.Element("defaults").Element("page-layout").Element("page-height").Value;
  523. paperHeight = parseFloat(defi);
  524. let found: boolean = false;
  525. let parts: IXmlElement[] = root.Elements("part");
  526. for (let idx: number = 0, len: number = parts.length; idx < len; ++idx) {
  527. let measures: IXmlElement[] = parts[idx].Elements("measure");
  528. for (let idx2: number = 0, len2: number = measures.length; idx2 < len2; ++idx2) {
  529. let measure: IXmlElement = measures[idx2];
  530. if (measure.Element("print") !== undefined) {
  531. let systemLayouts: IXmlElement[] = measure.Element("print").Elements("system-layout");
  532. for (let idx3: number = 0, len3: number = systemLayouts.length; idx3 < len3; ++idx3) {
  533. let syslab: IXmlElement = systemLayouts[idx3];
  534. if (syslab.Element("top-system-distance") !== undefined) {
  535. let topSystemDistanceString: string = syslab.Element("top-system-distance").Value;
  536. topSystemDistance = parseFloat(topSystemDistanceString);
  537. found = true;
  538. break;
  539. }
  540. }
  541. break;
  542. }
  543. }
  544. if (found) { break; }
  545. }
  546. if (root.Element("defaults").Element("system-layout") !== undefined) {
  547. let syslay: IXmlElement = root.Element("defaults").Element("system-layout");
  548. if (syslay.Element("top-system-distance") !== undefined) {
  549. let topSystemDistanceString: string = root.Element("defaults").Element("system-layout").Element("top-system-distance").Value;
  550. topSystemDistance = parseFloat(topSystemDistanceString);
  551. }
  552. }
  553. if (topSystemDistance === 0) { return 0; }
  554. return paperHeight - topSystemDistance;
  555. }
  556. private readTitle(root: IXmlElement): void {
  557. let titleNode: IXmlElement = root.Element("work");
  558. let titleNodeChild: IXmlElement = undefined;
  559. if (titleNode !== undefined) {
  560. titleNodeChild = titleNode.Element("work-title");
  561. if (titleNodeChild !== undefined && titleNodeChild.Value) {
  562. this.musicSheet.Title = new Label(this.trimString(titleNodeChild.Value));
  563. }
  564. }
  565. let movementNode: IXmlElement = root.Element("movement-title");
  566. let finalSubTitle: string = "";
  567. if (movementNode !== undefined) {
  568. if (this.musicSheet.Title === undefined) {
  569. this.musicSheet.Title = new Label(this.trimString(movementNode.Value));
  570. } else {
  571. finalSubTitle = this.trimString(movementNode.Value);
  572. }
  573. }
  574. if (titleNode !== undefined) {
  575. let subtitleNodeChild: IXmlElement = titleNode.Element("work-number");
  576. if (subtitleNodeChild !== undefined) {
  577. let workNumber: string = subtitleNodeChild.Value;
  578. if (workNumber) {
  579. if (finalSubTitle) {
  580. finalSubTitle = workNumber;
  581. } else {
  582. finalSubTitle = finalSubTitle + ", " + workNumber;
  583. }
  584. }
  585. }
  586. }
  587. if (finalSubTitle
  588. ) {
  589. this.musicSheet.Subtitle = new Label(finalSubTitle);
  590. }
  591. }
  592. private createInstrumentGroups(entryList: IXmlElement[]): { [_: string]: Instrument; } {
  593. let instrumentId: number = 0;
  594. let instrumentDict: { [_: string]: Instrument; } = {};
  595. let currentGroup: InstrumentalGroup = undefined;
  596. try {
  597. let entryArray: IXmlElement[] = entryList;
  598. for (let idx: number = 0, len: number = entryArray.length; idx < len; ++idx) {
  599. let node: IXmlElement = entryArray[idx];
  600. if (node.Name === "score-part") {
  601. let instrIdString: string = node.Attribute("id").Value;
  602. let instrument: Instrument = new Instrument(instrumentId, instrIdString, this.phonicScoreInterface, this.musicSheet, currentGroup);
  603. instrumentId++;
  604. let partElements: IXmlElement[] = node.Elements();
  605. for (let idx2: number = 0, len2: number = partElements.length; idx2 < len2; ++idx2) {
  606. let partElement: IXmlElement = partElements[idx2];
  607. try {
  608. if (partElement.Name === "part-name") {
  609. instrument.Name = partElement.Value;
  610. } else if (partElement.Name === "score-instrument") {
  611. let subInstrument: SubInstrument = new SubInstrument(instrument);
  612. subInstrument.IdString = partElement.FirstAttribute.Value;
  613. instrument.SubInstruments.push(subInstrument);
  614. let subElement: IXmlElement = partElement.Element("instrument-name");
  615. if (subElement !== undefined) {
  616. subInstrument.Name = subElement.Value;
  617. subInstrument.setMidiInstrument(subElement.Value);
  618. }
  619. } else if (partElement.Name === "midi-instrument") {
  620. let subInstrument: SubInstrument = instrument.getSubInstrument(partElement.FirstAttribute.Value);
  621. for (let idx3: number = 0, len3: number = instrument.SubInstruments.length; idx3 < len3; ++idx3) {
  622. let subInstr: SubInstrument = instrument.SubInstruments[idx3];
  623. if (subInstr.IdString === partElement.Value) {
  624. subInstrument = subInstr;
  625. break;
  626. }
  627. }
  628. let instrumentElements: IXmlElement[] = partElement.Elements();
  629. for (let idx3: number = 0, len3: number = instrumentElements.length; idx3 < len3; ++idx3) {
  630. let instrumentElement: IXmlElement = instrumentElements[idx3];
  631. try {
  632. if (instrumentElement.Name === "midi-channel") {
  633. if (parseInt(instrumentElement.Value) === 10) {
  634. instrument.MidiInstrumentId = MidiInstrument.Percussion;
  635. }
  636. } else if (instrumentElement.Name === "midi-program") {
  637. if (instrument.SubInstruments.length > 0 && instrument.MidiInstrumentId !== MidiInstrument.Percussion) {
  638. subInstrument.MidiInstrumentId = <MidiInstrument>Math.max(0, parseInt(instrumentElement.Value) - 1);
  639. }
  640. } else if (instrumentElement.Name === "midi-unpitched") {
  641. subInstrument.FixedKey = Math.max(0, parseInt(instrumentElement.Value));
  642. } else if (instrumentElement.Name === "volume") {
  643. try {
  644. let result: number = <number>parseFloat(instrumentElement.Value);
  645. subInstrument.Volume = result / 127.0;
  646. } catch (ex) {
  647. logging.debug("ExpressionReader.readExpressionParameters", "read volume", ex);
  648. }
  649. } else if (instrumentElement.Name === "pan") {
  650. try {
  651. let result: number = <number>parseFloat(instrumentElement.Value);
  652. subInstrument.Pan = result / 64.0;
  653. } catch (ex) {
  654. logging.debug("ExpressionReader.readExpressionParameters", "read pan", ex);
  655. }
  656. }
  657. } catch (ex) {
  658. logging.log("MusicSheetReader.createInstrumentGroups midi settings: ", ex);
  659. }
  660. }
  661. }
  662. } catch (ex) {
  663. logging.log("MusicSheetReader.createInstrumentGroups: ", ex);
  664. }
  665. }
  666. if (instrument.SubInstruments.length === 0) {
  667. let subInstrument: SubInstrument = new SubInstrument(instrument);
  668. instrument.SubInstruments.push(subInstrument);
  669. }
  670. instrumentDict[instrIdString] = instrument;
  671. if (currentGroup !== undefined) {
  672. currentGroup.InstrumentalGroups.push(instrument);
  673. this.musicSheet.Instruments.push(instrument);
  674. } else {
  675. this.musicSheet.InstrumentalGroups.push(instrument);
  676. this.musicSheet.Instruments.push(instrument);
  677. }
  678. } else {
  679. if ((node.Name === "part-group") && (node.Attribute("type").Value === "start")) {
  680. let iG: InstrumentalGroup = new InstrumentalGroup("group", this.musicSheet, currentGroup);
  681. if (currentGroup !== undefined) {
  682. currentGroup.InstrumentalGroups.push(iG);
  683. } else {
  684. this.musicSheet.InstrumentalGroups.push(iG);
  685. }
  686. currentGroup = iG;
  687. } else {
  688. if ((node.Name === "part-group") && (node.Attribute("type").Value === "stop")) {
  689. if (currentGroup !== undefined) {
  690. if (currentGroup.InstrumentalGroups.length === 1) {
  691. let instr: InstrumentalGroup = currentGroup.InstrumentalGroups[0];
  692. if (currentGroup.Parent !== undefined) {
  693. currentGroup.Parent.InstrumentalGroups.push(instr);
  694. this._removeFromArray(currentGroup.Parent.InstrumentalGroups, currentGroup);
  695. } else {
  696. this.musicSheet.InstrumentalGroups.push(instr);
  697. this._removeFromArray(this.musicSheet.InstrumentalGroups, currentGroup);
  698. }
  699. }
  700. currentGroup = currentGroup.Parent;
  701. }
  702. }
  703. }
  704. }
  705. }
  706. } catch (e) {
  707. let errorMsg: string = ITextTranslation.translateText(
  708. "ReaderErrorMessages/InstrumentError", "Error while reading Instruments"
  709. );
  710. throw new MusicSheetReadingException(errorMsg, e);
  711. }
  712. for (let idx: number = 0, len: number = this.musicSheet.Instruments.length; idx < len; ++idx) {
  713. let instrument: Instrument = this.musicSheet.Instruments[idx];
  714. if (!instrument.Name) {
  715. instrument.Name = "Instr. " + instrument.IdString;
  716. }
  717. }
  718. return instrumentDict;
  719. }
  720. private getCompleteNumberOfStavesFromXml(partInst: IXmlElement[]): number {
  721. let number: number = 0;
  722. let partInstArr: IXmlElement[] = partInst;
  723. for (let idx: number = 0, len: number = partInstArr.length; idx < len; ++idx) {
  724. let partNode: IXmlElement = partInstArr[idx];
  725. let xmlMeasureList: IXmlElement[] = partNode.Elements("measure");
  726. if (xmlMeasureList !== undefined) {
  727. let xmlMeasure: IXmlElement = xmlMeasureList[0];
  728. if (xmlMeasure !== undefined) {
  729. let stavesNode: IXmlElement = xmlMeasure.Element("attributes");
  730. if (stavesNode !== undefined) {
  731. stavesNode = stavesNode.Element("staves");
  732. }
  733. if (stavesNode === undefined) {
  734. number++;
  735. } else {
  736. number += parseInt(stavesNode.Value);
  737. }
  738. }
  739. }
  740. }
  741. if (number <= 0) {
  742. let errorMsg: string = ITextTranslation.translateText(
  743. "ReaderErrorMessages/StaffError", "Invalid number of staves."
  744. );
  745. throw new MusicSheetReadingException(errorMsg);
  746. }
  747. return number;
  748. }
  749. private getInstrumentNumberOfStavesFromXml(partNode: IXmlElement): number {
  750. let number: number = 0;
  751. let xmlMeasure: IXmlElement = partNode.Element("measure");
  752. if (xmlMeasure !== undefined) {
  753. let attributes: IXmlElement = xmlMeasure.Element("attributes");
  754. let staves: IXmlElement = undefined;
  755. if (attributes !== undefined) {
  756. staves = attributes.Element("staves");
  757. }
  758. if (attributes === undefined || staves === undefined) {
  759. number = 1;
  760. } else {
  761. number = parseInt(staves.Value);
  762. }
  763. }
  764. if (number <= 0) {
  765. let errorMsg: string = ITextTranslation.translateText(
  766. "ReaderErrorMessages/StaffError", "Invalid number of Staves."
  767. );
  768. throw new MusicSheetReadingException(errorMsg);
  769. }
  770. return number;
  771. }
  772. }