Files

171 lines
2.9 KiB
TypeScript

export enum Note {
"C",
"C#",
"D",
"D#",
"E",
"F",
"F#",
"G",
"G#",
"A",
"A#",
"B",
}
export enum NoteNameBehavior {
"always",
"onpress",
"onhighlight",
"onhover",
"never",
}
export enum KeyPressStyle {
"subtle",
"vivid",
}
export type HighlightedKey = {
key: PianoKey;
// if not specified, the default color for highlighted notes will be used
bgColor?: string;
};
export class PianoKey {
public note: Note;
public octave?: number;
constructor(note: Note, octave?: number) {
this.note = note;
this.octave = octave;
}
public toString = () => {
return (this.note as unknown as string) + (this.octave || "");
};
}
export const strToKey = (str: string): PianoKey => {
let note: Note;
const isSimpleNote = str[1]! >= "0" && str[1]! <= "9";
// later we need to support different annotations
switch (isSimpleNote ? str[0] : str.substring(0, 2)) {
case "E":
note = Note.E;
break;
case "B":
note = Note.B;
break;
case "C":
note = Note.C;
break;
case "D":
note = Note.D;
break;
case "F":
note = Note.F;
break;
case "G":
note = Note.G;
break;
case "A":
note = Note.A;
break;
case "C#":
note = Note["C#"];
break;
case "D#":
note = Note["D#"];
break;
case "F#":
note = Note["F#"];
break;
case "G#":
note = Note["G#"];
break;
case "A#":
note = Note["A#"];
break;
default:
throw new Error("Invalid note name");
}
if ((isSimpleNote && !str[1]) || (!isSimpleNote && str.length < 3)) {
return new PianoKey(note);
}
const octave = parseInt(str.substring(isSimpleNote ? 1 : 2));
return new PianoKey(note, octave);
};
export const keyToStr = (key: PianoKey, showOctave: boolean = true): string => {
let s = "";
switch (key.note) {
case Note.C:
s += "C";
break;
case Note.D:
s += "D";
break;
case Note.E:
s += "E";
break;
case Note.F:
s += "F";
break;
case Note.G:
s += "G";
break;
case Note.A:
s += "A";
break;
case Note.B:
s += "B";
break;
case Note["C#"]:
s += "C#";
break;
case Note["D#"]:
s += "D#";
break;
case Note["F#"]:
s += "F#";
break;
case Note["G#"]:
s += "G#";
break;
case Note["A#"]:
s += "A#";
break;
default:
throw new Error("Invalid note name");
}
if (showOctave && key.octave) {
s += key.octave;
}
return s;
};
export const isAccidental = (key: PianoKey): boolean => {
return (
key.note === Note["C#"] ||
key.note === Note["D#"] ||
key.note === Note["F#"] ||
key.note === Note["G#"] ||
key.note === Note["A#"]
);
};
export const octaveKeys: Array<PianoKey> = [
new PianoKey(Note.C),
new PianoKey(Note["C#"]),
new PianoKey(Note.D),
new PianoKey(Note["D#"]),
new PianoKey(Note.E),
new PianoKey(Note.F),
new PianoKey(Note["F#"]),
new PianoKey(Note.G),
new PianoKey(Note["G#"]),
new PianoKey(Note.A),
new PianoKey(Note["A#"]),
new PianoKey(Note.B),
];