char-slop/chordpad.vibed.software
git clone https://git.t4t.associates/char-slop/chordpad.vibed.software
2b249d4
main
1import { assertEquals } from "@std/assert" ; 2import { 3chordsFromClipboard , 4chordsFromText , 5chordsToClipboard , 6notesFromClipboard , 7notesToClipboard , 8} from "./clipboard.ts" ; 9import { keyOf , newChordTrack , newNoteTrack , pasteNotes , placeChord } from "./model.ts" ; 10 11const C = { tonic :"C" , mode :"ionian" } as const ; 12const Am = { tonic :"A" , mode :"aeolian" } as const ; 13 14function track () { 15const t = newChordTrack (); 16for ( const [ start , symbol ] of [ 17[ 0 , "I" ], 18[ 4 , "bVI" ], 19[ 8 , "Dm7" ], 20[ 12 , "4" ], 21] as const ) { 22placeChord ( t , { id :symbol , start, dur :4 , symbol}); 23} 24t . chords . push ({ id :"pinned" , start :16 , dur :2 , notes :[ 43 , 59 , 62 , 65 ] }); 25return t ; 26} 27 28Deno . test ( "copied chords go out as letter names, whatever they were written as" , () => { 29const copied = chordsToClipboard ( track (), [ "I" , "bVI" , "Dm7" , "4" , "pinned" ], C ) ! ; 30assertEquals ( copied . text , "C Ab Dm7 F G7" ); 31}); 32 33Deno . test ( "copied chords paste back exactly, renamed for the key they land in" , () => { 34const copied = chordsToClipboard ( track (), [ "bVI" , "Dm7" , "pinned" ], C ) ! ; 35const clip = chordsFromClipboard ( copied . data , keyOf ( Am )) ! ; 36assertEquals ( 37clip . chords . map ( c => [ c . start , c . dur , c . symbol ?? c . notes ]), 38[ 39[ 0 , 4 , "#VII" ], 40[ 4 , 4 , "Dm7" ], 41[ 12 , 2 , [ 43 , 59 , 62 , 65 ]], 42], 43); 44assertEquals ( clip . span , 14 ); 45assertEquals ( chordsFromClipboard ( "not json" , keyOf ( C )), undefined ); 46assertEquals ( chordsFromClipboard ( '{"something": "else"}' , keyOf ( C )), undefined ); 47}); 48 49Deno . test ( "chord symbols pasted as text, from anywhere" , () => { 50const clip = chordsFromText ( "Dm7 G7 | Cmaj7, vi nonsense\nF/A" , keyOf ( C ), 2 ) ! ; 51assertEquals ( 52clip . chords . map ( c => [ c . start , c . symbol ]), 53[ 54[ 0 , "Dm7" ], 55[ 2 , "G7" ], 56[ 4 , "Cmaj7" ], 57[ 6 , "vi" ], 58[ 8 , "F/A" ], 59], 60); 61assertEquals ( clip . span , 10 ); 62assertEquals ( chordsFromText ( "hello there" , keyOf ( C ), 4 ), undefined ); 63}); 64 65Deno . test ( 66"notes copy with their timing, pitch and velocity, and paste alongside what's there" , 67() => { 68const t = newNoteTrack (); 69t . notes . push ( 70{ id :"a" , start :2 , dur :1 , pitch :63 , vel :0.5 }, 71{ id :"b" , start :2 , dur :2 , pitch :67 , vel :0.8 }, 72{ id :"c" , start :3.5 , dur :0.5 , pitch :70 , vel :1 }, 73{ id :"d" , start :8 , dur :1 , pitch :72 , vel :1 }, 74); 75const copied = notesToClipboard ( 76t , 77[ "c" , "a" , "b" ], 78keyOf ({ tonic :"C" , mode :"aeolian" }), 79) ! ; 80assertEquals ( copied . text , "E♭4 G4 B♭4" ); 81const clip = notesFromClipboard ( copied . data ) ! ; 82assertEquals ( clip . span , 2 ); 83const ids = pasteNotes ( t , clip , 7.5 ); 84const pasted = t . notes . filter ( n => ids . includes ( n . id )); 85assertEquals ( 86pasted . map ( n => [ n . start , n . dur , n . pitch , n . vel ]), 87[ 88[ 7.5 , 1 , 63 , 0.5 ], 89[ 7.5 , 2 , 67 , 0.8 ], 90[ 9 , 0.5 , 70 , 1 ], 91], 92); 93// and the note already at 8 is still there 94assertEquals ( t . notes . length , 7 ); 95assertEquals ( notesFromClipboard ( "[1, 2]" ), undefined ); 96}, 97);