34 lines
986 B
TypeScript
34 lines
986 B
TypeScript
const NOTE_NAMES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
|
|
const A4_FREQUENCY = 440;
|
|
const A4_MIDI_NOTE = 69;
|
|
|
|
export function noteToFrequency(noteName: string): number | null {
|
|
const match = noteName.match(/^([A-G]#?)(-?\d+)$/i);
|
|
if (!match) return null;
|
|
|
|
const [, note, octave] = match;
|
|
const noteIndex = NOTE_NAMES.indexOf(note.toUpperCase());
|
|
if (noteIndex === -1) return null;
|
|
|
|
const octaveNum = parseInt(octave, 10);
|
|
const midiNote = (octaveNum + 1) * 12 + noteIndex;
|
|
const semitonesDiff = midiNote - A4_MIDI_NOTE;
|
|
|
|
return A4_FREQUENCY * Math.pow(2, semitonesDiff / 12);
|
|
}
|
|
|
|
export function parseFrequencyInput(input: string): number | null {
|
|
const trimmed = input.trim();
|
|
|
|
const asNumber = parseFloat(trimmed);
|
|
if (!isNaN(asNumber) && asNumber > 0 && asNumber < 20000) {
|
|
return asNumber;
|
|
}
|
|
|
|
return noteToFrequency(trimmed);
|
|
}
|
|
|
|
export function formatFrequency(frequency: number): string {
|
|
return frequency.toFixed(2);
|
|
}
|