piecewise linear tables for frequency sweep?

DSP, Plug-in and Host development discussion.
KVRist
37 posts since 16 Mar, 2021

Post Sun Aug 01, 2021 12:17 pm

hi,

i've a synth with N freq knobs, which each map the linear Freq control (0.0, 1.0) in pow() scale (as most of the synth out there).

I'd like to save some cpu change the pow calculation to a piecewise linear segments (such X points, and interpolate between them).

do you have some already made table with the list of proper values for sweep freq in the range between 20/20k hz?

just to get rid make my own, reinveinting the wheel...
(sure someone already make them for musical target).

thanks :)

KVRAF
6462 posts since 12 Feb, 2006 from Helsinki, Finland

Post Sun Aug 01, 2021 12:53 pm

Generating a table like this is very simple and can be done at initialization, something like this:

Code: Select all

for(int i = 0; i < numberOfPoints; ++i)
{
   table[i] = (20.0/samplerate) * pow(20e3/20., i / double(numberOfPoints));
}
Now, whether it's a great idea is another question.

It turns out that you'll need quite a large table for reasonable tuning and that's going to be less than ideal for cache, which means that it might end up being a pessimisation. The cache efficiency can be improved by tabuluating just one octave and then adding the integer part into the floating point exponent, but even then the table will likely be worse than a single-octave polynomial approximation (such as this one: viewtopic.php?p=7161124#p7161124).

If you don't need audio-rate modulation then computing the actual values (the obvious way) every 16 samples (or so) and then smoothing over time with linear interpolation is a tried and true method as well. If you do want audio-rate modulation, then I'd suggest using SIMD to do things in bulk, otherwise you're probably going to be spending most of your CPU on modulation no matter what.
Preferred pronouns would be "it/it" because according to this country, I'm a piece of human trash.

KVRist
431 posts since 21 Jun, 2013

Post Sun Aug 01, 2021 10:17 pm

It's better to avoid using pow in audio code. pow(x,y)=exp(y*log(x)), and in that particular case log(x) is constant. Pow is a lot slower than exp+log due to increased precision requirements (which doesn't really matter in audio) and exp alone is dirt cheap with simd.

In general, it's better to avoid expensive calculations per sample (such as math functions) when possible. In that particular case you can convert pow to a multiply: pow(y, base+partial)=pow(y,base)*pow(y,partial) , and update pow(y,partial) only when the value actually changes (which is far less demanding than recalculating pow per sample).

KVRist

Topic Starter

37 posts since 16 Mar, 2021

Post Sun Aug 01, 2021 11:41 pm

mystran wrote:
Sun Aug 01, 2021 12:53 pm
It turns out that you'll need quite a large table for reasonable tuning and that's going to be less than ideal for cache
why should i need "large" table? i mean, a 20/20k sweep is about 10 octaves range. i.e. 11 points.
is that so "horrible" to sweep linear each octave? where it could sound "shit"? any example to let me understand this would be very nice, thanks :)

and yes (for everyone): i do modulation at audio rate, so "control rate" recalculation can't be take in consideration.

KVRist
431 posts since 21 Jun, 2013

Post Mon Aug 02, 2021 12:35 am

markzzz wrote:
Sun Aug 01, 2021 11:41 pm
and yes (for everyone): i do modulation at audio rate, so "control rate" recalculation can't be take in consideration.
In that case SIMD exp is your only option (like that exp_mp function). Lookup table would be both slower and less precise.

KVRist

Topic Starter

37 posts since 16 Mar, 2021

Post Mon Aug 02, 2021 7:32 am

***double post***
Last edited by markzzz on Mon Aug 02, 2021 7:34 am, edited 1 time in total.

KVRist

Topic Starter

37 posts since 16 Mar, 2021

Post Mon Aug 02, 2021 7:33 am

2DaT wrote:
Mon Aug 02, 2021 12:35 am
In that case SIMD exp is your only option (like that exp_mp function). Lookup table would be both slower and less precise.
also for lookup table with few values? such if i use 16 "const" float values, shouldn't they be treated as registers and avoid memory access? keeping precision apart for a moment, the speed should be better, isn't?

KVRAF
6462 posts since 12 Feb, 2006 from Helsinki, Finland

Post Mon Aug 02, 2021 8:48 am

First of all, there's no good reason to ever approximate more than one octave, because the integer part of a base-2 exponent can be done by adding it into the floating point exponent field directly. That's how the efficient approximations work: they take the integer part, put it into the exponent, then take the fractional part and compute a polynomial approximation.

If you're trying to use this stuff for tuning, then you'll probably want at least around 1 cent accuracy (which is not great, but it's a start), which means about 1200 entries per octave. In single precision that's about 5kB which is not terrible (although far from ideal), but it means you can't easily use SIMD without expensive gathers. For audio rate modulation you really want to use SIMD and it turns out that you can compute a decent polynomial approximation over one octave in about the same time you'll lookup those values from a much less accurate table.. and that's for scalar, so expect even 4-way SSE to run about 4 times faster.

Lookup tables were great in the 90s, but these days they are the wrong solution to most problems.
Preferred pronouns would be "it/it" because according to this country, I'm a piece of human trash.

Return to “DSP and Plug-in Development”