Files
Tobias Nauen e79260231f first commit
2026-04-29 15:57:37 +02:00

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);
}