Review
(1) Algorithm
Since the octave and the note name are completely independant, you could mitigate boiler-plate concatenation and optimize reusability by using a class that stores the information for you. Additional complexity is required to determine the accidentals of a note given its degree and pitch. I have added the algorithm for this in my alternative solution.
const KEYS_NORMAL = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"]; let keys = KEYS_NORMAL.slice(-3); keys = keys.map( k => k + '0');
class Note {
constructor(degree, pitch) {
this.degree = degree;
this.pitch = pitch;
}
get Octave() {
return this.modulo(this.pitch);
}
set Octave(n) {
this.pitch = n * 12 + this.modulo(this.pitch);
}
modulo(n) {
return (n % 12 + 12) % 12;
}
..
}
(2) Algorithm
I like the idea of using interval patterns to identify scales.
majorSemiTones = [2,2,1,2,2,2]; minorSemiTones = [2,1,2,2,1,2];
However, when hardcoding them in the algorithm, there is not much room for extensibility and modularity.
if(scaleName.indexOf("m") > -1){ minor = true; intervals = this.minorSemiTones; }