# Frequency to Note calculation in Lua?

**URL:** <https://forum.electra.one/t/frequency-to-note-calculation-in-lua/1928>\
**Category:** General discussion\
**Created:** [March 4, 2023, 1:19pm UTC](https://forum.electra.one/t/frequency-to-note-calculation-in-lua/1928 "2023-03-04T13:19:26Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Flyweight](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.electra.one/flyweight/32/342_2.png) [@Flyweight](https://forum.electra.one/u/Flyweight)\
**Post date:** [March 4, 2023, 1:19pm UTC](https://forum.electra.one/t/frequency-to-note-calculation-in-lua/1928/1 "2023-03-04T13:19:26Z")

</div>

Can anyone suggest a way how-to calculate from pitch to note in Lua?

I am working on a Ensoniq Mirage template.  
The template displays sample time, frequency, lowest frequency and note.  
The Note comes from a table, written by hand into a list.

[https://www.phys.unsw.edu.au/music/note/](https://www.phys.unsw.edu.au/music/note/)

Here is written howto calculate from frequency to note

> **[Musical pitch notation from frequency with Python code](https://www.johndcook.com/blog/2016/02/10/musical-pitch-notation/)**
>
> Starting with the frequency of a note, find its musical notation in so-called scientific pitch notation.

`h = 12 log2(P / C0).`

Now I found Lua has only has natural or base10 log. no log base 2

Here is a possible way todo it with 2 logs.

> <https://stackoverflow.com/questions/24101708/custom-logarithm-lua-answer-has-trick-that-can-be-used-on-almost-any-language>

`logb(a) = logc(a) / logc(b)`

Here is a python example

```python
from math import log2, pow

A4 = 440
C0 = A4*pow(2, -4.75)
name = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
    
def pitch(freq):
    h = round(12*log2(freq/C0))
    octave = h // 12
    n = h % 12
    return name[n] + str(octave)

```

Anyhow thanks for any hints on this

---

<div class="post-metadata">

**Author:** ![martin](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.electra.one/martin/32/145_2.png) [@martin](https://forum.electra.one/u/martin)\
**Post date:** [March 4, 2023, 2:30pm UTC](https://forum.electra.one/t/frequency-to-note-calculation-in-lua/1928/2 "2023-03-04T14:30:09Z")

</div>

not around any computer where I could test, but I think lua `math.log` has base as second optional argument. try print log(8, 2)

---

<div class="post-metadata">

**Author:** ![Flyweight](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.electra.one/flyweight/32/342_2.png) [@Flyweight](https://forum.electra.one/u/Flyweight)\
**Post date:** [March 4, 2023, 2:59pm UTC](https://forum.electra.one/t/frequency-to-note-calculation-in-lua/1928/3 "2023-03-04T14:59:37Z")

</div>

Great thanks, that does work.  
Now I can try to make it work.

Thanks

---

<div class="post-metadata">

**Author:** ![markus.schloesser](https://avatars.discourse-cdn.com/v4/letter/m/8e7dd6/32.png) [@markus.schloesser](https://forum.electra.one/u/markus.schloesser)\
**Post date:** [March 5, 2023, 2:39am UTC](https://forum.electra.one/t/frequency-to-note-calculation-in-lua/1928/4 "2023-03-05T02:39:50Z")

</div>

I’d ask ChatGPT that, seriously, I’ve been working with python code all day and the amount of fixes it delivered is mind blowing. Sometimes you have to correct it, but it is very helpful and impressive

---

<div class="post-metadata">

**Author:** ![Flyweight](https://dub1.discourse-cdn.com/flex017/user_avatar/forum.electra.one/flyweight/32/342_2.png) [@Flyweight](https://forum.electra.one/u/Flyweight)\
**Post date:** [March 5, 2023, 10:14am UTC](https://forum.electra.one/t/frequency-to-note-calculation-in-lua/1928/5 "2023-03-05T10:14:14Z")

</div>

Hmmm chatGPT was not giving anything working untill I input the working python code and gave the formula.  
Once at least the note came out I asked to include offset in cents.  
Haven’t tested it properly but this is what I got and it seem to work. !!!

Its surprising how confident chatGPT give the wrong answers 🙂  
But still in the end i got what i wanted.  
Pretty cool!

```lua
local A4 = 440
local C0 = A4 * 2^(-4.75)
local name = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}

function pitch(freq)

    if freq < 27.5 or freq > 4186.01 then
        error("Frequency out of range: " .. freq)
    end

    local h = math.floor(12 * math.log(freq / C0, 2) + 0.5)
    local octave = math.floor(h / 12)
    local n = h % 12 + 1
    local cents_offset = math.floor(1200 * math.log(freq / (C0 * 2^(h/12)), 2) + 0.5)
    return name[n] .. octave, cents_offset
end

--usage
local freq = 261.63 
local note, offset = pitch(freq)
print(note, offset)

freq = 440
note, offset = pitch(freq)
print(note, offset)

freq = 444
note, offset = pitch(freq)
print(note, offset)

```

For the Mirage to get sample frequency into the note range we do

```auto
--Ensoniq Mirage Sample frequency range
if freq < 5000 or freq > 50000 then
        error("Input frequency out of range: " .. freq)
    end

    -- Divide the input frequency by 256 to get it into the note range
    freq = freq / 256

```

Pretty cool I got all the tools to generate a note with offset so the Mirage can sample ‘perfect’ loops.

This is not tested yet.

```lua
function get_pitch_bend_value(cents_offset, bend_range)
    -- Calculate the pitch bend units per cent
    local pitch_bend_units_per_cent = 8192 / bend_range / 100

    -- Calculate the pitch bend value based on the cents offset
    local pitch_bend_value = math.floor(cents_offset * pitch_bend_units_per_cent)

    -- Convert the pitch bend value to a signed 14-bit integer
    pitch_bend_value = pitch_bend_value + 8192

    -- Clamp the pitch bend value to the range of 0 to 16383
    pitch_bend_value = math.min(16383, math.max(0, pitch_bend_value))

    return pitch_bend_value
end

-- Generate pitch bend value for a 100 cent up bend with a pitch bend range of 2 semitones
local pitch_bend_value = get_pitch_bend_value(-100, 200)
print("The pitchbend value " .. pitch_bend_value)

pitchbendUnits = pitch_bend_value - 8192

print(pitchbendAmound)

```

But all the data can be then used to send a midi note and a bend message to trigger the exact frequency that fits into the Mirage.
