import { expect, test } from "bun:test"; import { alignGrid, rhythmScore } from "../../src/eval/rhythm.ts"; import type { ScoreNote } from "../../src/core/types.ts"; const sn = (a: number[][]): ScoreNote[] => a.map(([tick, dur, pitch]) => ({ tick: tick!, dur: dur!, pitch: pitch! })); test("grid alignment: double tempo and one beat shift", () => { const r = sn([[0, 240, 60], [960, 960, 62]]); const e = sn([[960, 480, 60], [2880, 1920, 62]]); expect(alignGrid(r, e)).toEqual({ factor: 2, beatOffset: 1 }); expect(rhythmScore(r, e, { factor: 2, beatOffset: 1 })).toEqual({ onBeat: 1, durationOk: 1 }); }); test("identity preferred and partial scores", () => { const r = sn([[0, 480, 60], [960, 480, 62]]); expect(alignGrid(r, r)).toEqual({ factor: 1, beatOffset: 0 }); const e = sn([[0, 480, 60], [1000, 240, 62]]); expect(rhythmScore(r, e, { factor: 1, beatOffset: 0 })).toEqual({ onBeat: 0.5, durationOk: 0.5 }); }); test("no pitch matches -> null", () => { expect(rhythmScore(sn([[0, 1, 60]]), sn([[0, 1, 61]]), { factor: 1, beatOffset: 0 })).toEqual({ onBeat: null, durationOk: null }); });