diff --git a/packages/midi/index.ts b/packages/midi/index.ts index bf09ddb3..c6b42d12 100644 --- a/packages/midi/index.ts +++ b/packages/midi/index.ts @@ -133,8 +133,10 @@ export function pcsetNearest(notes: number[] | string) { return (midi: number): number | undefined => { const ch = chroma(midi); for (let i = 0; i < 12; i++) { - if (set.includes(ch + i)) return midi + i; - if (set.includes(ch - i)) return midi - i; + const chUp = (ch + i) % 12; + const chDown = (ch - i + 12) % 12; + if (set.includes(chUp)) return midi + i; + if (set.includes(chDown)) return midi - i; } return undefined; }; diff --git a/packages/midi/test.ts b/packages/midi/test.ts index 0f744dd4..90746f8e 100644 --- a/packages/midi/test.ts +++ b/packages/midi/test.ts @@ -58,10 +58,24 @@ describe("midi", () => { test("find nearest upwards", () => { const nearest = Midi.pcsetNearest([0, 5, 7]); expect([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(nearest)).toEqual([ - 0, 0, 0, 5, 5, 5, 7, 7, 7, 7, 7, 7, 12, + 0, 0, 0, 5, 5, 5, 7, 7, 7, 7, 12, 12, 12, ]); }); + test("chromatic to nearest C minor pentatonic", () => { + const nearest = Midi.pcsetNearest("100101010010"); + expect([36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47].map(nearest)).toEqual([ + 36, 36, 39, 39, 41, 41, 43, 43, 43, 46, 46, 48 + ]); + }); + + test("chromatic to nearest half octave", () => { + const nearest = Midi.pcsetNearest("100000100000"); + expect([36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47].map(nearest)).toEqual([ + 36, 36, 36, 42, 42, 42, 42, 42, 42, 48, 48, 48 + ]); + }) + test("empty pcsets returns the note", () => { expect([10, 30, 40].map(Midi.pcsetNearest([]))).toEqual([]); });