Note Index
These functions are intended within the scope of all the notes on a standard keyboard – using the SPN notation, c0 through B8 (108 notes) where c0 has noteIndex 0, and b8 has noteIndex 107, and use a tempered scaled based on the standard A4 at 440hz.
You can supply either a frequency, or a note index, and get back this ‘note’ object. Both sharp and flat scale notations are given so you can use the appropriate one for the key. This one is for Ab (or G#) at SPN7.
{ "accidental": true, "flatScale": { "base": "A", "name": "Ab", "spn": "Ab7" }, "frequency": 3322.437580639563, "noteIndex": 92, "octave": 7, "octaveIndex": 8, "sharpScale": { "base": "G", "name": "G#", "spn": "G#7" }, "waveLength": 0.10383942260055587 }
The code
Given a note index (0-107), make a note object
/** * get notation & frequency from a note number * @param {number} noteIndex between 0 - C0 and 107 - B8 * @return {object} note */ ns.getNote = function (noteIndex) { const sharpScale = "CcDdEFfGgAaB"; const flatScale = "CdDeEFgGaAbB"; const octaveIndex = noteIndex % 12; const accidental = isAccident(sharpScale.slice (octaveIndex, octaveIndex+1)); const octave = Math.floor(noteIndex/12); const frequency = ns.getNoteFrequency(noteIndex); const speedOfSound = 345; // m/s return { noteIndex:noteIndex, octaveIndex:noteIndex % 12, accidental:accidental, flatScale: names (flatScale, "b"), sharpScale:names (sharpScale, "#"), octave:octave, frequency:frequency, waveLength:speedOfSound/frequency }; function names (scale, a) { return { base:scale.slice (octaveIndex, octaveIndex+1).toUpperCase(), spn:scale.slice (octaveIndex, octaveIndex+1).toUpperCase()+(accidental ? a : '') + octave, name:scale.slice (octaveIndex, octaveIndex+1).toUpperCase()+(accidental ? a : '') }; } function isAccident(c) { return c.toUpperCase(c) !== c; } };
Figure out the frequency of a given note index
/** * get the frequency of a given note using a tempered scale */ ns.getNoteFrequency = function (noteIndex) { // a4 note Index const a4 = 9 + 4 * 12; // freq of a4 const a4Freq = 440; // base const tr2 = Math.pow(2,1/12); // semitones from a4 const s = noteIndex - a4; // result return a4Freq * Math.pow (tr2 , s); };
Generate a note object for the nearest note that corresponds to this frequency
/** * get the note of a frequency * @param {number} frequency in hz * @return {object} note */ ns.getNoteFromFrequency = function (frequency , sharp) { // a4 note Index const a4 = 9 + 4 * 12; // freq of a4 const a4Freq = 440; // base const tr2 = Math.pow(2,1/12); // calc note index const noteIndex = Math.log(frequency/a4Freq) / Math.log (tr2) + a4; // round off to nearest note and get as a note return ns.getNote(Math.round(noteIndex)); };