Key_Test.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /* eslint-disable @typescript-eslint/no-unused-expressions */
  2. import { MusicSheetReader } from "../../../src/MusicalScore/ScoreIO/MusicSheetReader";
  3. import { MusicSheet } from "../../../src/MusicalScore/MusicSheet";
  4. import { IXmlElement } from "../../../src/Common/FileIO/Xml";
  5. import { KeyInstruction } from "../../../src/MusicalScore/VoiceData/Instructions/KeyInstruction";
  6. import { KeyEnum as KeyModeEnum } from "../../../src/MusicalScore/VoiceData/Instructions/KeyInstruction";
  7. import { VexFlowConverter } from "../../../src/MusicalScore/Graphical/VexFlow/VexFlowConverter";
  8. import chai from "chai";
  9. import { AbstractNotationInstruction } from "../../../src/MusicalScore/VoiceData/Instructions/AbstractNotationInstruction";
  10. import { RhythmInstruction, RhythmSymbolEnum } from "../../../src/MusicalScore/VoiceData/Instructions/RhythmInstruction";
  11. let reader: MusicSheetReader;
  12. let parser: DOMParser;
  13. describe("MusicXML parser for element 'key'", () => {
  14. before((): void => {
  15. reader = new MusicSheetReader();
  16. parser = new DOMParser();
  17. });
  18. describe("for group traditional keys", () => {
  19. it("enforces single occurrence of element 'fifths'", (done: Mocha.Done) => {
  20. const keyInstruction: KeyInstruction = getIllegalMusicXmlWithTwoFifthsElements().getFirstSourceMeasure().getKeyInstruction(0);
  21. // TODO Make sure we detect the multiple fifths and react properly // [it seems like we do this, test passes. ssch]
  22. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.none);
  23. done();
  24. });
  25. it("reads key signature with no optional 'mode' element present", (done: Mocha.Done) => {
  26. const keyInstruction: KeyInstruction = getMusicSheetWithKey(0, undefined).getFirstSourceMeasure().getKeyInstruction(0);
  27. chai.expect(keyInstruction.Key).to.equal(0);
  28. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.none);
  29. done();
  30. });
  31. describe("major keys", () => {
  32. it("reads key signature C-major", (done: Mocha.Done) => {
  33. const keyInstruction: KeyInstruction = getMusicSheetWithKey(0, "major").getFirstSourceMeasure().getKeyInstruction(0);
  34. chai.expect(keyInstruction.Key).to.equal(0);
  35. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  36. done();
  37. });
  38. it("reads key signature G-major", (done: Mocha.Done) => {
  39. const keyInstruction: KeyInstruction = getMusicSheetWithKey(1, "major").getFirstSourceMeasure().getKeyInstruction(0);
  40. chai.expect(keyInstruction.Key).to.equal(1);
  41. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  42. done();
  43. });
  44. it("reads key signature D-major", (done: Mocha.Done) => {
  45. const keyInstruction: KeyInstruction = getMusicSheetWithKey(2, "major").getFirstSourceMeasure().getKeyInstruction(0);
  46. chai.expect(keyInstruction.Key).to.equal(2);
  47. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  48. done();
  49. });
  50. it("reads key signature A-major", (done: Mocha.Done) => {
  51. const keyInstruction: KeyInstruction = getMusicSheetWithKey(3, "major").getFirstSourceMeasure().getKeyInstruction(0);
  52. chai.expect(keyInstruction.Key).to.equal(3);
  53. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  54. done();
  55. });
  56. it("reads key signature E-major", (done: Mocha.Done) => {
  57. const keyInstruction: KeyInstruction = getMusicSheetWithKey(4, "major").getFirstSourceMeasure().getKeyInstruction(0);
  58. chai.expect(keyInstruction.Key).to.equal(4);
  59. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  60. done();
  61. });
  62. it("reads key signature B-major", (done: Mocha.Done) => {
  63. const keyInstruction: KeyInstruction = getMusicSheetWithKey(5, "major").getFirstSourceMeasure().getKeyInstruction(0);
  64. chai.expect(keyInstruction.Key).to.equal(5);
  65. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  66. done();
  67. });
  68. it("reads key signature F#-major", (done: Mocha.Done) => {
  69. const keyInstruction: KeyInstruction = getMusicSheetWithKey(6, "major").getFirstSourceMeasure().getKeyInstruction(0);
  70. chai.expect(keyInstruction.Key).to.equal(6);
  71. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  72. done();
  73. });
  74. it("reads key signature C#-major", (done: Mocha.Done) => {
  75. const keyInstruction: KeyInstruction = getMusicSheetWithKey(7, "major").getFirstSourceMeasure().getKeyInstruction(0);
  76. chai.expect(keyInstruction.Key).to.equal(7);
  77. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  78. done();
  79. });
  80. it("reads key signature G#-major", (done: Mocha.Done) => {
  81. const keyInstruction: KeyInstruction = getMusicSheetWithKey(8, "major").getFirstSourceMeasure().getKeyInstruction(0);
  82. chai.expect(keyInstruction.Key).to.equal(8);
  83. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  84. done();
  85. });
  86. it("reads key signature F-major", (done: Mocha.Done) => {
  87. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-1, "major").getFirstSourceMeasure().getKeyInstruction(0);
  88. chai.expect(keyInstruction.Key).to.equal(-1);
  89. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  90. done();
  91. });
  92. it("reads key signature Bb-major", (done: Mocha.Done) => {
  93. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-2, "major").getFirstSourceMeasure().getKeyInstruction(0);
  94. chai.expect(keyInstruction.Key).to.equal(-2);
  95. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  96. done();
  97. });
  98. it("reads key signature Eb-major", (done: Mocha.Done) => {
  99. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-3, "major").getFirstSourceMeasure().getKeyInstruction(0);
  100. chai.expect(keyInstruction.Key).to.equal(-3);
  101. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  102. done();
  103. });
  104. it("reads key signature Ab-major", (done: Mocha.Done) => {
  105. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-4, "major").getFirstSourceMeasure().getKeyInstruction(0);
  106. chai.expect(keyInstruction.Key).to.equal(-4);
  107. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  108. done();
  109. });
  110. it("reads key signature Db-major", (done: Mocha.Done) => {
  111. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-5, "major").getFirstSourceMeasure().getKeyInstruction(0);
  112. chai.expect(keyInstruction.Key).to.equal(-5);
  113. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  114. done();
  115. });
  116. it("reads key signature Gb-major", (done: Mocha.Done) => {
  117. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-6, "major").getFirstSourceMeasure().getKeyInstruction(0);
  118. chai.expect(keyInstruction.Key).to.equal(-6);
  119. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  120. done();
  121. });
  122. it("reads key signature Fb-major", (done: Mocha.Done) => {
  123. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-8, "major").getFirstSourceMeasure().getKeyInstruction(0);
  124. chai.expect(keyInstruction.Key).to.equal(-8);
  125. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.major);
  126. done();
  127. });
  128. });
  129. describe("minor keys", () => {
  130. it("reads key signature a-minor", (done: Mocha.Done) => {
  131. const keyInstruction: KeyInstruction = getMusicSheetWithKey(0, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  132. chai.expect(keyInstruction.Key).to.equal(0);
  133. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  134. done();
  135. });
  136. it("reads key signature e-minor", (done: Mocha.Done) => {
  137. const keyInstruction: KeyInstruction = getMusicSheetWithKey(1, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  138. chai.expect(keyInstruction.Key).to.equal(1);
  139. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  140. done();
  141. });
  142. it("reads key signature b-minor", (done: Mocha.Done) => {
  143. const keyInstruction: KeyInstruction = getMusicSheetWithKey(2, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  144. chai.expect(keyInstruction.Key).to.equal(2);
  145. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  146. done();
  147. });
  148. it("reads key signature f#-minor", (done: Mocha.Done) => {
  149. const keyInstruction: KeyInstruction = getMusicSheetWithKey(3, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  150. chai.expect(keyInstruction.Key).to.equal(3);
  151. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  152. done();
  153. });
  154. it("reads key signature c#-minor", (done: Mocha.Done) => {
  155. const keyInstruction: KeyInstruction = getMusicSheetWithKey(4, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  156. chai.expect(keyInstruction.Key).to.equal(4);
  157. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  158. done();
  159. });
  160. it("reads key signature g#-minor", (done: Mocha.Done) => {
  161. const keyInstruction: KeyInstruction = getMusicSheetWithKey(5, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  162. chai.expect(keyInstruction.Key).to.equal(5);
  163. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  164. done();
  165. });
  166. it("reads key signature d#-minor", (done: Mocha.Done) => {
  167. const keyInstruction: KeyInstruction = getMusicSheetWithKey(6, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  168. chai.expect(keyInstruction.Key).to.equal(6);
  169. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  170. done();
  171. });
  172. it("reads key signature a#-minor", (done: Mocha.Done) => {
  173. const keyInstruction: KeyInstruction = getMusicSheetWithKey(7, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  174. chai.expect(keyInstruction.Key).to.equal(7);
  175. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  176. done();
  177. });
  178. it("reads key signature d-minor", (done: Mocha.Done) => {
  179. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-1, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  180. chai.expect(keyInstruction.Key).to.equal(-1);
  181. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  182. done();
  183. });
  184. it("reads key signature g-minor", (done: Mocha.Done) => {
  185. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-2, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  186. chai.expect(keyInstruction.Key).to.equal(-2);
  187. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  188. done();
  189. });
  190. it("reads key signature c-minor", (done: Mocha.Done) => {
  191. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-3, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  192. chai.expect(keyInstruction.Key).to.equal(-3);
  193. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  194. done();
  195. });
  196. it("reads key signature f-minor", (done: Mocha.Done) => {
  197. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-4, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  198. chai.expect(keyInstruction.Key).to.equal(-4);
  199. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  200. done();
  201. });
  202. it("reads key signature bb-minor", (done: Mocha.Done) => {
  203. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-5, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  204. chai.expect(keyInstruction.Key).to.equal(-5);
  205. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  206. done();
  207. });
  208. it("reads key signature eb-minor", (done: Mocha.Done) => {
  209. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-6, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  210. chai.expect(keyInstruction.Key).to.equal(-6);
  211. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  212. done();
  213. });
  214. it("reads key signature ab-minor", (done: Mocha.Done) => {
  215. const keyInstruction: KeyInstruction = getMusicSheetWithKey(-7, "minor").getFirstSourceMeasure().getKeyInstruction(0);
  216. chai.expect(keyInstruction.Key).to.equal(-7);
  217. chai.expect(keyInstruction.Mode).to.equal(KeyModeEnum.minor);
  218. done();
  219. });
  220. });
  221. });
  222. });
  223. describe("VexFlowConverter for element 'key'", () => {
  224. before((): void => {
  225. reader = new MusicSheetReader();
  226. parser = new DOMParser();
  227. });
  228. it("gives key signature G-major with no optional 'mode' element present", (done: Mocha.Done) => {
  229. const keyInstruction: KeyInstruction = getMusicSheetWithKey(1, "").getFirstSourceMeasure().getKeyInstruction(0);
  230. const vexflowKeySignature: string = VexFlowConverter.keySignature(keyInstruction);
  231. const isGMajorOrEminor: boolean = ["G", "E"].indexOf(vexflowKeySignature.charAt(0)) !== -1;
  232. chai.expect(isGMajorOrEminor).to.equal(true);
  233. done();
  234. });
  235. });
  236. // not key tests, but if we outsource this, we need to make getMusicSheetWithKey() accessible from other test files.
  237. describe("InstrumentReader for element 'time'", () => {
  238. before((): void => {
  239. reader = new MusicSheetReader();
  240. parser = new DOMParser();
  241. });
  242. it("gives common time RythmSymbolEnum from xml", (done: Mocha.Done) => {
  243. const instructions: AbstractNotationInstruction[] =
  244. getMusicSheetWithKey(1, "major", "common").getFirstSourceMeasure().FirstInstructionsStaffEntries[0].Instructions;
  245. for (const instruction of instructions) {
  246. if (instruction instanceof RhythmInstruction) {
  247. chai.expect(instruction.SymbolEnum).to.equal(RhythmSymbolEnum.COMMON);
  248. }
  249. }
  250. done();
  251. });
  252. it("gives alla breve/cut time RythmSymbolEnum from xml", (done: Mocha.Done) => {
  253. const instructions: AbstractNotationInstruction[] =
  254. getMusicSheetWithKey(1, "major", "cut").getFirstSourceMeasure().FirstInstructionsStaffEntries[0].Instructions;
  255. for (const instruction of instructions) {
  256. if (instruction instanceof RhythmInstruction) {
  257. chai.expect(instruction.SymbolEnum).to.equal(RhythmSymbolEnum.CUT);
  258. }
  259. }
  260. done();
  261. });
  262. });
  263. function getMusicSheetWithKey(fifths: number = undefined, mode: string = undefined, timeSymbol: string = ""): MusicSheet {
  264. const doc: Document = parser.parseFromString(getMusicXmlWithKey(fifths, mode, timeSymbol), "text/xml");
  265. chai.expect(doc).to.not.be.undefined;
  266. const score: IXmlElement = new IXmlElement(doc.getElementsByTagName("score-partwise")[0]);
  267. chai.expect(score).to.not.be.undefined;
  268. return reader.createMusicSheet(score, "template.xml");
  269. }
  270. function getMusicXmlWithKey(fifths: number = undefined, mode: string = undefined, timeSymbol: string = ""): string {
  271. const modeElement: string = mode ? `<mode>${mode}</mode>` : "";
  272. const fifthsElement: string = fifths ? `<fifths>${fifths}</fifths>` : "";
  273. const timeSymbolAttribute: string = timeSymbol ? `symbol="${timeSymbol}"` : "";
  274. return `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  275. <!DOCTYPE score-partwise PUBLIC
  276. "-//Recordare//DTD MusicXML 3.0 Partwise//EN"
  277. "http://www.musicxml.org/dtds/partwise.dtd">
  278. <score-partwise version="3.0">
  279. <part-list>
  280. <score-part id="P1">
  281. <part-name>Music</part-name>
  282. </score-part>
  283. </part-list>
  284. <part id="P1">
  285. <measure number="1">
  286. <attributes>
  287. <divisions>1</divisions>
  288. <key>
  289. ${fifthsElement}
  290. ${modeElement}
  291. </key>
  292. <time ${timeSymbolAttribute}>
  293. <beats>4</beats>
  294. <beat-type>4</beat-type>
  295. </time>
  296. <clef>
  297. <sign>G</sign>
  298. <line>2</line>
  299. </clef>
  300. </attributes>
  301. <note>
  302. <pitch>
  303. <step>C</step>
  304. <octave>4</octave>
  305. </pitch>
  306. <duration>4</duration>
  307. <type>whole</type>
  308. </note>
  309. </measure>
  310. </part>
  311. </score-partwise>`;
  312. }
  313. function getIllegalMusicXmlWithTwoFifthsElements(): MusicSheet {
  314. const doc: Document = parser.parseFromString(
  315. `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  316. <!DOCTYPE score-partwise PUBLIC
  317. "-//Recordare//DTD MusicXML 3.0 Partwise//EN"
  318. "http://www.musicxml.org/dtds/partwise.dtd">
  319. <score-partwise version="3.0">
  320. <part-list>
  321. <score-part id="P1">
  322. <part-name>Music</part-name>
  323. </score-part>
  324. </part-list>
  325. <part id="P1">
  326. <measure number="1">
  327. <attributes>
  328. <divisions>1</divisions>
  329. <key>
  330. <fifths>1</fifths>
  331. <fifths>2</fifths>
  332. <fifths>3</fifths>
  333. </key>
  334. <time>
  335. <beats>4</beats>
  336. <beat-type>4</beat-type>
  337. </time>
  338. <clef>
  339. <sign>G</sign>
  340. <line>2</line>
  341. </clef>
  342. </attributes>
  343. <note>
  344. <pitch>
  345. <step>C</step>
  346. <octave>4</octave>
  347. </pitch>
  348. <duration>4</duration>
  349. <type>whole</type>
  350. </note>
  351. </measure>
  352. </part>
  353. </score-partwise>`,
  354. "text/xml"
  355. );
  356. chai.expect(doc).to.not.be.undefined;
  357. const score: IXmlElement = new IXmlElement(doc.getElementsByTagName("score-partwise")[0]);
  358. chai.expect(score).to.not.be.undefined;
  359. return reader.createMusicSheet(score, "template.xml");
  360. }