Ok, now that I've posted a few comments, I think I feel confident enough to start a topic that concerns fast ways to do pow(2.,x) for purposes of pitch to frequency and related conversions.

I've tried a lot of suggested functions here and elsewhere for the purpose, and it seems most of them are either

1. wildly inaccurate or only accurate near zero

2. not much faster (or even slower) than gcc's stock pow().

So I've used the trivial solution for now, namely converting pitch from float to a (say) 16-bit fixed point, then using the identity

a^(x+y) = a^x * a^y

to do separate table lookups for low and high bytes and multiply together (so 2 tables of 256 floats each, 2kB total). It needs one pre-multiply, float-to-int, two lookups, another float multiply, and some trivial integer bitsuffling.

Ofcourse with larger tables one gets more accuracy without extra operations, with more tables one needs less memory but with some extra operations.

Even if it isn't complicated at all, this took me a minute or two to figure out, so I'm just wondering why I haven't seen it mentioned anywhere? Did I just miss? Is it just considered too trivial? Or is there's some critical flaw?

I mean it seems to perform much better than most methods suggested, accuracy is more or less uniform on logarithmic scale, and the memory requirements aren't huge (YMMV).

10 posts

Page

**1**of**1**- KVRAF
- 4927 posts since 11 Feb, 2006, from Helsinki, Finland

- KVRAF
- 2456 posts since 3 Oct, 2002, from SF CA USA NA Earth

I prefer to use powf() directly, at control rate, and linearly interpolate in between.

Yours is a good trick, though. I recently saw a page on fast sin/cos that suggested something analogous, using the identity sincos(x+y)=sincos(x)*sincos(y) where sincos is a complex number. You pick sincos(x) from a table so as to leave y as small as possible, near zero where sin is nearly linear.

Yours is a good trick, though. I recently saw a page on fast sin/cos that suggested something analogous, using the identity sincos(x+y)=sincos(x)*sincos(y) where sincos is a complex number. You pick sincos(x) from a table so as to leave y as small as possible, near zero where sin is nearly linear.

- KVRAF
- 3415 posts since 15 Sep, 2002

>>I prefer to use powf() directly, at control rate, and linearly interpolate in between.

What is the ratio between your control rate and audiorate?

What is the ratio between your control rate and audiorate?

- KVRist
- 42 posts since 1 Jun, 2006

There was a thread about this recently where I suggested this approach. You make one table with precalculated semitone frequencies, and you make another table with 100 elements of precalculated cents (cent_table[i] = pow(2, i/1200)). Then calculate cent precision frequency of any pitch with

So a pitch of 76.45 would give you

You need two tables of 128/100 floats to do this. If you want better precision, just divide each semitone into something else than cents and make the second table larger. To get a precision of one tenth of a cent, just make the second table a 1000 position table and fill it with pow(2, i/(12*(1000))). You can get any precision you want simply by increasing/decreasing the size of the second table this way, but cent precision is probably accurate enough for most applications.

- Code: Select all
`freq = semitone_table[semitone_pitch]*cent_table[cents];`

So a pitch of 76.45 would give you

- Code: Select all
`freq = semitone_table[76]*cent_table[45];`

You need two tables of 128/100 floats to do this. If you want better precision, just divide each semitone into something else than cents and make the second table larger. To get a precision of one tenth of a cent, just make the second table a 1000 position table and fill it with pow(2, i/(12*(1000))). You can get any precision you want simply by increasing/decreasing the size of the second table this way, but cent precision is probably accurate enough for most applications.

Last edited by arwa02 on Sun Dec 17, 2006 2:16 am, edited 1 time in total.

/arwa02

- KVRAF
- 4927 posts since 11 Feb, 2006, from Helsinki, Finland

Yeah ok arwa. Must have missed the thread.

I actually thought of the semitone and cent tables as well, but decided against it. IMHO it buys nothing, and if modulations are summed as floats (or fixed points, doesn't matter really), having the table sizes be powers of two means getting the indexes is just shift and bitwise-and. For non-powers like 100 one needs an integer divide and remainder, which I admit might not be a huge loss.

I actually thought of the semitone and cent tables as well, but decided against it. IMHO it buys nothing, and if modulations are summed as floats (or fixed points, doesn't matter really), having the table sizes be powers of two means getting the indexes is just shift and bitwise-and. For non-powers like 100 one needs an integer divide and remainder, which I admit might not be a huge loss.

- KVRAF
- 3759 posts since 8 Mar, 2004, from Berlin, Germany

i use that macro:

all the time. and why not? or is you frequency-calculation supposed to be called at audio-rate? i need that calculation typically only when a new note comes in.

- Code: Select all
`//conversion from a MIDI-Note Number to a frequency in Hz:`

#define PITCH2FREQ(pitch) (440*( pow(2, ((((double)pitch)-69)/12))))

all the time. and why not? or is you frequency-calculation supposed to be called at audio-rate? i need that calculation typically only when a new note comes in.

- KVRAF
- 4927 posts since 11 Feb, 2006, from Helsinki, Finland

Exponential modulations are nice for some purposes.

<- plugins | forum

- KVRAF
- 3759 posts since 8 Mar, 2004, from Berlin, Germany

mystran wrote:Exponential modulations are nice for some purposes.

that's right. in particular, when the modulator is an envelope. but in this case, there is RC-solution (as currently discussed once more in another thread). and when the modulator is some LFO - mmmhh...couldn't we just multiply the (raised) LFO's output with the average frequency like:

freq = averageFreq * (1.0 + depth*lfoOut);

something like that? i think, i do this in my flanger in the exponential LFO-mode - but i'm not quite sure a the moment.

- KVRAF
- 2456 posts since 3 Oct, 2002, from SF CA USA NA Earth

braindoc wrote:i use that macro:

- Code: Select all
`//conversion from a MIDI-Note Number to a frequency in Hz:`

#define PITCH2FREQ(pitch) (440*( pow(2, ((((double)pitch)-69)/12))))

all the time. and why not? or is you frequency-calculation supposed to be called at audio-rate? i need that calculation typically only when a new note comes in.

Pitch bend, pitch envelope, LFO...

- KVRAF
- 2456 posts since 3 Oct, 2002, from SF CA USA NA Earth

mistertoast wrote:>>I prefer to use powf() directly, at control rate, and linearly interpolate in between.

What is the ratio between your control rate and audiorate?

32 or 64.