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); });