### From notes to frequencies and back again

This is part of a bigger project that I'll write up at some later date. These functions from it might be of some use to anyone who wants to identify a pitch from an audio input. The whole topic of pitch identification is a long story with lots of maths, but eventually you will want to convert between a frequency and a  note.

#### 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));`

`  };`

`Learning Apps Script, (and transitioning from VBA) are covered comprehensively in my my book, Going Gas - from VBA to Apps script, available All formats are available now from O'Reilly,Amazon and all good bookshops. You can also read a preview on O'Reilly. If you prefer Video style learning I also have two courses available. also published by O'Reilly. Google Apps Script for Developers and Google Apps Script for Beginners.JOT_postEvent('registerForRpc', this, ['626725908455324789', 1304673173, '//2k026imuihnrho207b8ideld4uc88ppu-a-sites-opensocial.googleusercontent.com/gadgets/ifr?url\x3dhttps://storage.googleapis.com/goinggas.com/public/hosting/sites/xliberation/xml/sitesense.xml\x26container\x3denterprise\x26view\x3ddefault\x26lang\x3den\x26country\x3dALL\x26sanitize\x3d0\x26v\x3d7c2aebd66054096e\x26libs\x3dcore:dynamic-height\x26mid\x3d77\x26parent\x3dhttp://downloads.mcpher.com/Home/excelquirks/gassnips/notefrequencies#up_client\x3dca-pub-0073976545556837\x26up_slot\x3d5457792947\x26st\x3de%3DAIHE3cBSc8U%252FqiTjjyJgiuHCm0q0IksbQeV6pziijl1OzmPJEoYCA1SDXxbewctgPiZDym00etS1clel52SS%252BWFCoeI7N4Nj3XhGTJq92d6Pv3%252BeHUqqNCzMl3nduVzjge8emKmpcQDH%26c%3Denterprise\x26rpctoken\x3d626725908455324789'])JOT_postEvent('registerForRpc', this, ['626725908455324789', 1044560974, '//2k026imuihnrho207b8ideld4uc88ppu-a-sites-opensocial.googleusercontent.com/gadgets/ifr?url\x3dhttps://storage.googleapis.com/goinggas.com/public/hosting/sites/xliberation/xml/sitesense.xml\x26container\x3denterprise\x26view\x3ddefault\x26lang\x3den\x26country\x3dALL\x26sanitize\x3d0\x26v\x3d7c2aebd66054096e\x26libs\x3dcore:dynamic-height\x26mid\x3d77\x26parent\x3dhttp://downloads.mcpher.com/Home/excelquirks/gassnips/notefrequencies#up_client\x3dca-pub-0073976545556837\x26up_slot\x3d5457792947\x26st\x3de%3DAIHE3cCFhVgnYqhvBXjDA4nA5l0UMmQl3UvyAY2zU26f2phOTl319wIyw54f%252FCrBwAXBknm0obUFqQdaZHltSKP%252F5QjUg25y5ZQW5p51li9uF4TSe5Z3ha4rAh31Vd7wPELSPSuGWSex%26c%3Denterprise\x26rpctoken\x3d626725908455324789'])JOT_postEvent('registerForRpc', this, ['626725908455324789', 2131010439, '//2k026imuihnrho207b8ideld4uc88ppu-a-sites-opensocial.googleusercontent.com/gadgets/ifr?url\x3dhttps://storage.googleapis.com/goinggas.com/public/hosting/sites/xliberation/xml/sitesense.xml\x26container\x3denterprise\x26view\x3ddefault\x26lang\x3den\x26country\x3dALL\x26sanitize\x3d0\x26v\x3d7c2aebd66054096e\x26libs\x3dcore:dynamic-height\x26mid\x3d77\x26parent\x3dhttp://downloads.mcpher.com/Home/excelquirks/gassnips/notefrequencies#up_client\x3dca-pub-0073976545556837\x26up_slot\x3d5457792947\x26st\x3de%3DAIHE3cB68bOoFDI6Bi0gBk5WJeJPEyejPlzn9Oz8M%252FwMKj4RIVriBWYDFQE2oSFU86j6jLzKQGyUqD3okLpN9qkuhHTA%252BAyNoKjVf7f%252F8H3S42IF94pSY4lqeZz7NRlJhkH14c6a1D%252Bv%26c%3Denterprise\x26rpctoken\x3d626725908455324789'])`