32 lines
1.3 KiB
JavaScript
32 lines
1.3 KiB
JavaScript
// Canonical pitch representation: sharps only.
|
|
// Flats are derived via ENHARMONIC for display purposes only.
|
|
export const CHROMATIC = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
|
|
export const ENHARMONIC = { 'C#': 'Db', 'D#': 'Eb', 'F#': 'Gb', 'G#': 'Ab', 'A#': 'Bb' };
|
|
export const NATURAL = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];
|
|
|
|
// Standard tuning, index 0 = lowest string.
|
|
// 6-string: strings 6→1 (low E → high e)
|
|
// 7-string: strings 7→1 (low B → high e)
|
|
export const OPEN_NOTES = {
|
|
6: ['E', 'A', 'D', 'G', 'B', 'E'],
|
|
7: ['B', 'E', 'A', 'D', 'G', 'B', 'E'],
|
|
};
|
|
|
|
export function getNoteAt(stringIdx, fret, numStrings) {
|
|
const openIdx = CHROMATIC.indexOf(OPEN_NOTES[numStrings][stringIdx]);
|
|
return CHROMATIC[(openIdx + fret) % 12];
|
|
}
|
|
|
|
// Returns "D#/Eb" for accidentals unless sharpsOnly is set.
|
|
export function noteDisplay(note, sharpsOnly) {
|
|
if (sharpsOnly || !ENHARMONIC[note]) return note;
|
|
return `${note}/${ENHARMONIC[note]}`;
|
|
}
|
|
|
|
// Returns 9 answer choices including the correct note (all in sharp form).
|
|
export function getAnswerChoices(correct, naturalOnly) {
|
|
const pool = naturalOnly ? NATURAL : CHROMATIC;
|
|
const others = pool.filter(n => n !== correct).sort(() => Math.random() - 0.5).slice(0, 8);
|
|
return [...others, correct].sort(() => Math.random() - 0.5);
|
|
}
|