import { assertEquals } from "@std/assert"; import { chordsFromClipboard, chordsFromText, chordsToClipboard, notesFromClipboard, notesToClipboard, } from "./clipboard.ts"; import { keyOf, newChordTrack, newNoteTrack, pasteNotes, placeChord } from "./model.ts"; const C = { tonic: "C", mode: "ionian" } as const; const Am = { tonic: "A", mode: "aeolian" } as const; function track() { const t = newChordTrack(); for (const [start, symbol] of [ [0, "I"], [4, "bVI"], [8, "Dm7"], [12, "4"], ] as const) { placeChord(t, { id: symbol, start, dur: 4, symbol }); } t.chords.push({ id: "pinned", start: 16, dur: 2, notes: [43, 59, 62, 65] }); return t; } Deno.test("copied chords go out as letter names, whatever they were written as", () => { const copied = chordsToClipboard(track(), ["I", "bVI", "Dm7", "4", "pinned"], C)!; assertEquals(copied.text, "C Ab Dm7 F G7"); }); Deno.test("copied chords paste back exactly, renamed for the key they land in", () => { const copied = chordsToClipboard(track(), ["bVI", "Dm7", "pinned"], C)!; const clip = chordsFromClipboard(copied.data, keyOf(Am))!; assertEquals( clip.chords.map(c => [c.start, c.dur, c.symbol ?? c.notes]), [ [0, 4, "#VII"], [4, 4, "Dm7"], [12, 2, [43, 59, 62, 65]], ], ); assertEquals(clip.span, 14); assertEquals(chordsFromClipboard("not json", keyOf(C)), undefined); assertEquals(chordsFromClipboard('{"something": "else"}', keyOf(C)), undefined); }); Deno.test("chord symbols pasted as text, from anywhere", () => { const clip = chordsFromText("Dm7 G7 | Cmaj7, vi nonsense\nF/A", keyOf(C), 2)!; assertEquals( clip.chords.map(c => [c.start, c.symbol]), [ [0, "Dm7"], [2, "G7"], [4, "Cmaj7"], [6, "vi"], [8, "F/A"], ], ); assertEquals(clip.span, 10); assertEquals(chordsFromText("hello there", keyOf(C), 4), undefined); }); Deno.test( "notes copy with their timing, pitch and velocity, and paste alongside what's there", () => { const t = newNoteTrack(); t.notes.push( { id: "a", start: 2, dur: 1, pitch: 63, vel: 0.5 }, { id: "b", start: 2, dur: 2, pitch: 67, vel: 0.8 }, { id: "c", start: 3.5, dur: 0.5, pitch: 70, vel: 1 }, { id: "d", start: 8, dur: 1, pitch: 72, vel: 1 }, ); const copied = notesToClipboard( t, ["c", "a", "b"], keyOf({ tonic: "C", mode: "aeolian" }), )!; assertEquals(copied.text, "E♭4 G4 B♭4"); const clip = notesFromClipboard(copied.data)!; assertEquals(clip.span, 2); const ids = pasteNotes(t, clip, 7.5); const pasted = t.notes.filter(n => ids.includes(n.id)); assertEquals( pasted.map(n => [n.start, n.dur, n.pitch, n.vel]), [ [7.5, 1, 63, 0.5], [7.5, 2, 67, 0.8], [9, 0.5, 70, 1], ], ); // and the note already at 8 is still there assertEquals(t.notes.length, 7); assertEquals(notesFromClipboard("[1, 2]"), undefined); }, );