Files
STSheets/tests/pipeline/tab.test.ts
2026-10-30 05:00:20 +01:00

51 lines
2.2 KiB
TypeScript

import { test, expect } from "bun:test";
import { assignTab } from "../../src/pipeline/tab.ts";
import { GUITAR_STANDARD, BASS_STANDARD } from "../../src/core/types.ts";
import type { ScoreNote } from "../../src/core/types.ts";
const sn = (tick: number, dur: number, pitch: number): ScoreNote => ({ tick, dur, pitch });
test("chord gets playable, injective tab", () => {
const chordC = [48, 52, 55, 60, 64].map((p) => sn(0, 960, p));
const a = assignTab(chordC, GUITAR_STANDARD);
expect(a.dropped).toBe(0);
for (const n of a.notes) expect(GUITAR_STANDARD[n.string! - 1]! + n.fret!).toBe(n.pitch);
expect(new Set(a.notes.map((n) => n.string)).size).toBe(5);
expect(Math.max(...a.notes.map((n) => n.fret!))).toBeLessThanOrEqual(3);
});
test("drops unplayable notes", () => {
expect(assignTab([sn(0, 960, 30)], GUITAR_STANDARD)).toEqual({ notes: [], dropped: 1 });
expect(assignTab([sn(0, 960, 90)], GUITAR_STANDARD)).toEqual({ notes: [], dropped: 1 });
});
test("keeps highest notes when chord exceeds string count", () => {
const a = assignTab([40, 45, 50, 55, 59, 64, 67].map((p) => sn(0, 960, p)), GUITAR_STANDARD);
expect(a.dropped).toBe(1);
expect(a.notes.map((n) => n.pitch).sort()).toEqual([45, 50, 55, 59, 64, 67]);
});
test("a scale run stays in a low, smoothly moving position", () => {
const run = [60, 62, 64, 65, 67, 69, 71, 72].map((p, i) => sn(i * 240, 240, p));
const a = assignTab(run, GUITAR_STANDARD);
expect(a.dropped).toBe(0);
const frets = a.notes.map((n) => n.fret!);
expect(Math.max(...frets)).toBeLessThanOrEqual(9);
for (let i = 1; i < frets.length; i++) expect(Math.abs(frets[i]! - frets[i - 1]!)).toBeLessThanOrEqual(4);
});
test("bass notes are valid and respect maxFret", () => {
const a = assignTab([28, 33, 38, 43, 80].map((p, i) => sn(i * 240, 240, p)), BASS_STANDARD, 20);
for (const n of a.notes) {
expect(BASS_STANDARD[n.string! - 1]! + n.fret!).toBe(n.pitch);
expect(n.fret!).toBeLessThanOrEqual(20);
}
expect(a.dropped).toBe(1);
});
test("two notes that only fit the low E string: one dropped", () => {
const a = assignTab([sn(0, 240, 40), sn(0, 240, 41)], GUITAR_STANDARD, 20);
expect(a.notes.length).toBe(1);
expect(a.dropped).toBe(1);
});