Testing music without speakers
A song as data
notes(song, fromStep, toStep) lists every note that starts in a window of steps. It's pure JavaScript, so it runs in Node, in a test runner, or in an agent's sandbox, with no audio at all.
import { notes } from "plonkjs";
notes(theme, 0, 16);
// [
// { time: 0, instrument: "lead", freq: 523.25, duration: 0.134, velocity: 0.8 },
// { time: 0, instrument: "kick", freq: 0, duration: 0.134, velocity: 0.7 },
// { time: 0.268, instrument: "lead", freq: 659.26, duration: 0.134, velocity: 0.8 },
// ...
// ]Times are in seconds from the start. Windows past the end of the song keep counting, looping through order.
import { expect, test } from "vitest";
test("the chorus brings the drums in", () => {
const chorus = notes(song, 64, 128);
expect(chorus.some((n) => n.instrument === "kick")).toBe(true);
});Other helpers: parse(pattern) for a single pattern, frequency("C#4") for a note's pitch, songSteps(song) and sectionSteps(section) for lengths, stepSeconds(bpm) for timing.
What actually played
A player records the last 256 notes it scheduled in player.played, so a game test can check the right music is on:
expect(player.played.some((n) => n.instrument === "kick")).toBe(false); // the map has no drumsHow it sounds, in numbers
mix(song) renders a song offline in the browser and reports its loudness, balance and problems, so a test or an agent can catch an inaudible track or a clipping mix. See Sound design.
For coding agents
Songs are plain text in plain objects, so an agent can write one, change a pattern or an instrument, and check the result with notes() before a person listens. The plonk agent skill gives agents the notation and instrument recipes.