38 lines
1.6 KiB
TypeScript
38 lines
1.6 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { matchNotes, maxAssignment } from "../../src/eval/notes.ts";
|
|
import type { TimedNote } from "../../src/core/types.ts";
|
|
|
|
const n = (onset: number, pitch: number, string?: number): TimedNote => ({ onset, offset: onset + 0.2, pitch, string });
|
|
const ref = [n(1.0, 60), n(1.5, 62), n(2.0, 64)];
|
|
|
|
test("tp / octave errors", () => {
|
|
const est = [n(1.03, 60), n(1.5, 74), n(2.2, 64)];
|
|
expect(matchNotes(ref, est).tp).toBe(1);
|
|
expect(matchNotes(ref, est).octaveErrors).toBe(1);
|
|
});
|
|
test("perfect and empty cases", () => {
|
|
expect(matchNotes(ref, ref).f1).toBe(1);
|
|
expect(matchNotes([], []).f1).toBeNull();
|
|
expect(matchNotes(ref, []).recall).toBe(0);
|
|
expect(matchNotes(ref, []).precision).toBeNull();
|
|
expect(matchNotes([], ref).recall).toBeNull();
|
|
expect(matchNotes([], ref).f1).toBe(0);
|
|
});
|
|
test("matching is maximum, not greedy", () => {
|
|
// greedy nearest would pair r1-e1 (0.00) leaving r2 unmatched; optimum pairs r1-e2, r2-e1
|
|
const r = [n(1.0, 60), n(1.04, 60)];
|
|
const e = [n(1.0, 60), n(0.96, 60)];
|
|
expect(matchNotes(r, e, { onsetTol: 0.045 }).tp).toBe(2);
|
|
const r2 = [n(0.0, 60), n(0.08, 60)];
|
|
const e2 = [n(0.04, 60), n(-0.01, 60)];
|
|
expect(matchNotes(r2, e2, { onsetTol: 0.05 }).tp).toBe(2);
|
|
});
|
|
test("pitchString key", () => {
|
|
expect(matchNotes([n(1, 60, 1)], [n(1, 60, 2)], { key: "pitchString" }).tp).toBe(0);
|
|
expect(matchNotes([n(1, 60, 1)], [n(1, 60, 2)]).tp).toBe(1);
|
|
});
|
|
test("maxAssignment", () => {
|
|
expect(maxAssignment([[5, 4], [4, 0]])).toEqual([1, 0]);
|
|
expect(maxAssignment([[3], [5]])).toEqual([-1, 0]);
|
|
});
|