- Install Deno
- Run
deno run https://gist.githubusercontent.com/5t111111/698c87f8ee518f4db737bd00502695f1/raw/get-music-key-from-notes.ts C E F
The above will output:
{ candidates: [ "C", "F", "Dm", "Am" ] }
/* | |
* Get music key (scale) from notes used | |
* | |
* Usage: | |
* | |
* deno run https://gist.githubusercontent.com/5t111111/698c87f8ee518f4db737bd00502695f1/raw/get-music-key-from-notes.ts C E F | |
* | |
* The above example shows you `{ candidates: [ "C", "F", "Dm", "Am" ] }` | |
*/ | |
const notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]; | |
const majorIntervals = [0, 2, 2, 1, 2, 2, 2]; | |
const majorIntervalsFromRoot = majorIntervals.map((interval, idx) => | |
majorIntervals.slice(0, idx + 1).reduce<number>((acc, curr) => acc + curr, 0) | |
); | |
const minorIntervals = [0, 2, 1, 2, 2, 1, 2]; | |
const minorIntervalsFromRoot = minorIntervals.map((interval, idx) => | |
minorIntervals.slice(0, idx + 1).reduce<number>((acc, curr) => acc + curr, 0) | |
); | |
const getNotesOfScale = (intervals: number[], root: string) => | |
intervals.reduce<string[]>((acc, curr) => { | |
const index = notes.findIndex((elem) => elem === root) + curr; | |
const noteIndex = index >= 12 ? index - 12 : index; | |
acc.push(notes[noteIndex]); | |
return acc; | |
}, []); | |
const majorScales = notes | |
.map((note) => { | |
const notesOfScale = getNotesOfScale(majorIntervalsFromRoot, note); | |
return { | |
[note]: notesOfScale, | |
}; | |
}) | |
.reduce((acc, curr) => Object.assign(acc, curr), {}); | |
const minorScales = notes | |
.map((note) => { | |
const notesOfScale = getNotesOfScale(minorIntervalsFromRoot, note); | |
return { | |
[`${note}m`]: notesOfScale, | |
}; | |
}) | |
.reduce((acc, curr) => Object.assign(acc, curr), {}); | |
const scales = Object.assign(majorScales, minorScales); | |
// console.log(scales); | |
const notesToFind: string[] = Array.from( | |
new Set(Deno.args.filter((arg) => notes.includes(arg))) | |
); | |
let candidates: string[] = []; | |
for (const scaleKey in scales) { | |
if (notesToFind.every((curr) => scales[scaleKey].includes(curr))) { | |
candidates.push(scaleKey); | |
} | |
} | |
console.log({ candidates }); |