Key_Test.ts 18 KB

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