fix: drum single hit, dedupe notes, validate role

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-30 02:42:35 +01:00
co-authored by Claude Sonnet 5.5
parent ec7cb0e568
commit 470e089f92
3 changed files with 40 additions and 2 deletions
+31
View File
@@ -80,3 +80,34 @@ test("GP round trip preserves notes, ties, strings, roles", () => {
test("songToMidi generates events", () => {
expect(songToMidi(song).tracks.length).toBeGreaterThan(0);
});
function drumSong(notes: { tick: number; dur: number; pitch: number }[]): Song {
return {
title: "d", tier: "t1", seed: 1, bpm: BPM, timeSig: [4, 4], bars: 2, key: "C",
tracks: [{ name: "Kit", role: "drums", program: 0, pan: 0, fx: "none", gainDb: 0, notes }],
};
}
test("drum note with multi-piece duration yields exactly one hit", () => {
const truth = truthFromGp(songToGp(drumSong([{ tick: 0, dur: 5 * S, pitch: 38 }])));
expect(truth.tracks[0]!.notes.map((n) => [n.pitch, n.onset])).toEqual([[38, 0]]);
});
test("drum note crossing a barline yields exactly one hit", () => {
const truth = truthFromGp(songToGp(drumSong([{ tick: 3 * Q, dur: 2 * Q, pitch: 36 }])));
expect(truth.tracks[0]!.notes.map((n) => [n.pitch, round3(n.onset)])).toEqual([[36, round3(t(3 * Q))]]);
});
test("exact duplicate notes are de-duplicated", () => {
const dup = { tick: Q, dur: Q, pitch: 60 };
const s = drumSong([]);
s.tracks = [{ name: "V", role: "vocals", program: 53, pan: 0, fx: "none", gainDb: 0, notes: [dup, { ...dup }] }];
const truth = truthFromGp(songToGp(s));
expect(truth.tracks[0]!.notes.length).toBe(1);
});
test("truthFromGp rejects an invalid role short name", () => {
const s = drumSong([{ tick: 0, dur: Q, pitch: 36 }]);
(s.tracks[0] as any).role = "banjo";
expect(() => truthFromGp(songToGp(s))).toThrow(/not a valid Role/);
});