82 lines
3.5 KiB
TypeScript
82 lines
3.5 KiB
TypeScript
import { test, expect } from "bun:test";
|
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { buildSong, loadSongDir, RENDER_VERSION } from "../../src/bench/dataset.ts";
|
|
|
|
test("buildSong writes all artefacts; loadSongDir reads them; stems sum to mix; idempotent", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "stsheets-ds-"));
|
|
try {
|
|
const dir = await buildSong("t1a", 1, root);
|
|
const files = ["song.json", "truth.gp", "mix.wav", "mix.mp3"];
|
|
for (const f of files) expect(await Bun.file(join(dir, f)).exists()).toBe(true);
|
|
const { song, truth, mix, stems } = await loadSongDir(dir);
|
|
for (const t of song.tracks) expect(await Bun.file(join(dir, "stems", `${t.name}.wav`)).exists()).toBe(true);
|
|
expect(truth.tracks[0]!.notes.length).toBe(song.tracks[0]!.notes.length);
|
|
expect(mix.channels.length).toBe(2);
|
|
|
|
// Oracle stems are the exact mix contributions: they sum to the mix (PCM16 rounding only).
|
|
expect(stems.size).toBe(song.tracks.length);
|
|
let maxDiff = 0;
|
|
for (let c = 0; c < mix.channels.length; c++) {
|
|
const m = mix.channels[c]!;
|
|
for (let i = 0; i < m.length; i++) {
|
|
let s = 0;
|
|
for (const a of stems.values()) s += a.channels[c]![i] ?? 0;
|
|
maxDiff = Math.max(maxDiff, Math.abs(s - m[i]!));
|
|
}
|
|
}
|
|
expect(maxDiff).toBeLessThan(2e-3);
|
|
|
|
const before = (await Bun.file(join(dir, "mix.mp3")).stat()).mtimeMs;
|
|
expect(await buildSong("t1a", 1, root)).toBe(dir);
|
|
expect((await Bun.file(join(dir, "mix.mp3")).stat()).mtimeMs).toBe(before);
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
}, 120_000);
|
|
|
|
test("multi-track t1b: stems on disk sum to mix.wav", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "stsheets-ds-"));
|
|
try {
|
|
const dir = await buildSong("t1b", 1, root);
|
|
expect(dir).toBe(join(root, "t1b", "1"));
|
|
const { song, mix, stems } = await loadSongDir(dir);
|
|
expect(song.tracks.length).toBeGreaterThan(1);
|
|
expect(stems.size).toBe(song.tracks.length);
|
|
let maxDiff = 0;
|
|
for (let c = 0; c < mix.channels.length; c++) for (let i = 0; i < mix.channels[c]!.length; i++) {
|
|
let s = 0;
|
|
for (const a of stems.values()) s += a.channels[c]![i] ?? 0;
|
|
maxDiff = Math.max(maxDiff, Math.abs(s - mix.channels[c]![i]!));
|
|
}
|
|
expect(maxDiff).toBeLessThan(2e-3);
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
}, 120_000);
|
|
|
|
test("a dir built under an older/missing RENDER_VERSION is rebuilt", async () => {
|
|
const root = await mkdtemp(join(tmpdir(), "stsheets-ds-"));
|
|
try {
|
|
const dir = await buildSong("t1a", 2, root);
|
|
const mp3 = join(dir, "mix.mp3");
|
|
const v = Bun.file(join(dir, "render-version"));
|
|
expect((await v.text()).trim()).toBe(String(RENDER_VERSION));
|
|
const m0 = (await Bun.file(mp3).stat()).mtimeMs;
|
|
await Bun.write(join(dir, "render-version"), String(RENDER_VERSION - 1)); // simulate an old build
|
|
await Bun.sleep(20);
|
|
await buildSong("t1a", 2, root);
|
|
const m1 = (await Bun.file(mp3).stat()).mtimeMs;
|
|
expect(m1).toBeGreaterThan(m0);
|
|
expect((await Bun.file(join(dir, "render-version")).text()).trim()).toBe(String(RENDER_VERSION));
|
|
// missing marker file also rebuilds
|
|
await rm(join(dir, "render-version"));
|
|
await Bun.sleep(20);
|
|
await buildSong("t1a", 2, root);
|
|
expect((await Bun.file(mp3).stat()).mtimeMs).toBeGreaterThan(m1);
|
|
} finally {
|
|
await rm(root, { recursive: true, force: true });
|
|
}
|
|
}, 180_000);
|