Home Manual Reference Source Test

tests/integration/midi.test.js

  1. import { describe, it, expect } from "vitest";
  2. import { generateMidi } from "../../src/controller/tracks.js";
  3. describe("integration: midi-writer-js", () => {
  4. /** @test {generateMidi} */
  5. it("emits a real MIDI binary with the expected header from a realistic solution", () => {
  6. const part = {
  7. solution: {
  8. note_0_0: 60, // C4
  9. note_0_1: -2, // tie -> extends C4
  10. note_0_2: 64, // E4
  11. note_0_3: -1, // rest
  12. },
  13. numSubBeats: 4,
  14. subdivision: 1,
  15. numerator: 4,
  16. denominator: 4,
  17. key: 0,
  18. mode: "major",
  19. };
  20. const step3Params = { voices: 1, voice: [{ instrument: 0 }] };
  21. const { combinedB64, voicesB64 } = generateMidi([part], step3Params, 120);
  22. expect(voicesB64).toHaveLength(1);
  23. // MIDI files start with "MThd" header chunk.
  24. const bytes = Uint8Array.from(atob(combinedB64), (c) => c.charCodeAt(0));
  25. const header = String.fromCharCode(...bytes.slice(0, 4));
  26. expect(header).toBe("MThd");
  27. // A "MTrk" chunk must be present somewhere after the header.
  28. const ascii = String.fromCharCode(...bytes);
  29. expect(ascii).toContain("MTrk");
  30. });
  31. /** @test {generateMidi} */
  32. it("produces one MTrk per voice in the combined file when multiple voices are present", () => {
  33. const part = {
  34. solution: { note_0_0: 60, note_1_0: 67 }, // C4 + G4 simultaneously
  35. numSubBeats: 1,
  36. subdivision: 1,
  37. numerator: 1,
  38. denominator: 4,
  39. key: 0,
  40. mode: "major",
  41. };
  42. const step3Params = {
  43. voices: 2,
  44. voice: [{ instrument: 0 }, { instrument: 42 }],
  45. };
  46. const { combinedB64, voicesB64 } = generateMidi([part], step3Params, 120);
  47. expect(voicesB64).toHaveLength(2);
  48. const bytes = Uint8Array.from(atob(combinedB64), (c) => c.charCodeAt(0));
  49. const ascii = String.fromCharCode(...bytes);
  50. // Combined file should contain two track chunks (one per voice).
  51. const trackCount = ascii.match(/MTrk/g)?.length ?? 0;
  52. expect(trackCount).toBe(2);
  53. });
  54. });