char-slop/chordpad.vibed.software

git clone https://git.t4t.associates/char-slop/chordpad.vibed.software

Charlotte Somchord panel style tweakad1ae60

main
2.6 KiB54 linesraw
1import { assert, assertEquals } from "@std/assert";
2import { chordName, parseChord } from "./chord.ts";
3import { connections } from "./connect.ts";
4import { parseNote } from "./pitch.ts";
5
6const C = { tonic: parseNote("C")!.note, mode: "ionian" as const };
7const chord = (s: string) => parseChord(s, C)!;
8const routes = (prev: string | undefined, target: string) =>
9  connections(prev ? chord(prev) : undefined, chord(target)).map(
10    r => `${r.name}: ${r.chords.map(chordName).join(" ")}`,
11  );
12
13Deno.test("the way in is coloured like where it's going", () => {
14  const into = (target: string) => routes(undefined, target).slice(0, 2);
15  assertEquals(into("Cmaj9"), ["V: G9", "ii–V: Dm9 G9"]);
16  assertEquals(into("Cmaj7"), ["V: G7", "ii–V: Dm7 G7"]);
17  assertEquals(into("C"), ["V: G7", "ii–V: Dm7 G7"]);
18  // into a minor chord: the minor key's ii and V
19  assertEquals(into("Am"), ["V: E7♭9", "ii–V: Bm7♭5 E7♭9"]);
20});
21
22Deno.test("the ways in that follow on best from the chord before come first", () => {
23  // from Am7, down a fifth to the ii
24  assertEquals(routes("Am7", "Cmaj7")[0], "ii–V: Dm7 G7");
25  // from E♭maj7, down a fifth to ♭VI, then a semitone down to ii; and C's own shape planed down
26  // the scale, ♭III–♭II–I, as the autocomposer does
27  const fromThree = routes("Ebmaj7", "Cmaj7");
28  assertEquals(fromThree.slice(0, 2), ["♭VI–V: A♭maj7 G7", "ii–V: Dm7 G7"]);
29  assert(fromThree.includes("planed ♭II: D♭maj7"));
30  // from Dm7, the ii is already there: no playing it again
31  const fromTwo = routes("Dm7", "Cmaj7");
32  assertEquals(fromTwo[0], "V: G7");
33  assert(!fromTwo.some(r => r.startsWith("ii–V")));
34});
35
36Deno.test("colourful ways in, where they fit", () => {
37  const all = routes(undefined, "Cmaj7");
38  assert(all.includes("♭VI–V: A♭maj7 G7"));
39  assert(all.includes("iv–♭VII: Fm7 B♭7"));
40  assert(all.includes("iii–VI–ii–V: Em7 A7 Dm7 G7"));
41  assert(all.includes("planed ♭II: D♭maj7"));
42  // coltrane's major thirds, only from a major third away
43  assert(!all.some(r => r.startsWith("coltrane")));
44  assert(routes("Abmaj7", "Cmaj7").includes("coltrane: B7 Emaj7 G7"));
45  // no backdoor or iii–VI into a minor chord
46  assert(!routes(undefined, "Am").some(r => r.startsWith("iv–") || r.startsWith("iii–")));
47});
48
49Deno.test("ways in are spelled without double flats or sharps", () => {
50  for (const target of ["Ab", "Db", "Gbmaj7", "F#m", "C#"]) {
51    for (const r of routes(undefined, target)) assert(!/𝄫|𝄪|♭♭|♯♯/.test(r), `${target}: ${r}`);
52  }
53  assert(routes(undefined, "Ab").includes("subV: A7"));
54});