Performance of log10 and pow
-
- KVRist
- Topic Starter
- 188 posts since 13 Jun, 2004 from SW England
I have a written a plugin that uses log10 and pow to convert an amplitude to decibels and back again (with processing in between, obviously). I have discovered that the call to pow accounts for nearly half of my plug's CPU usage. Are there good, fast approximations for these functions suitable for such usage?
-
- KVRAF
- 2458 posts since 3 Oct, 2002 from SF CA USA NA Earth
What are you doing that needs you to be in decibels? Is that a per-sample operation? Can you rethink that processing to work in linear amplitude?gy wrote:I have a written a plugin that uses log10 and pow to convert an amplitude to decibels and back again (with processing in between, obviously). I have discovered that the call to pow accounts for nearly half of my plug's CPU usage. Are there good, fast approximations for these functions suitable for such usage?
(The fastest code is that which never runs...)
-
- KVRAF
- 4644 posts since 28 Nov, 2002 from Chicago
Ya'know, from now on that's gonna be my excuse for failing to finish applications on time at work:Borogove wrote: (The fastest code is that which never runs...)
"Well yeah, it isn't actually finished yet, so it doesn't exactly compile... but I see that as more of a performance feature at this time."
Someone shot the food. Remember: don't shoot food!
-
- KVRist
- Topic Starter
- 188 posts since 13 Jun, 2004 from SW England
It's a compressor and yes, for each sample I am performing one log10 and one pow operation. I can't see any way around using them so I am looking to speed them up, in particular the pow method.What are you doing that needs you to be in decibels? Is that a per-sample operation? Can you rethink that processing to work in linear amplitude?
- KVRist
- 137 posts since 1 Jan, 2004 from Germany
do u really need one log and one pow PER SAMPLE ?!?
sorry, but i can't believe it, even when it is a compressor ...
sorry, but i can't believe it, even when it is a compressor ...
-
- KVRist
- 192 posts since 4 Nov, 2003 from Philadelphia, PA USA
gy, most things don't need to be done every sample - even amplitude operations. You could figure it out every 4, 8 or 16 samples and interpolate in between. The difference shouldn't be audible. I have some code I've been using (forget where I found it) for doing fast pow(2, x) operations.. Here it is in case it's helpful.
void makefastpowtable()
{
for(int i=0; i<4097; i++)
tablefracpow2 = powf(2.0, ((float)i-2048)/2048.0);
}
float fastpow2(float x)
{
long *px = (long*)(&x);
const long lx = int(x);
float dx = x-(float)(lx);
int index = int(dx*2048.0)+2048;
index = index & 4095;
x = tablefracpow2[index];
*px += (lx<<23);
return x;
}
void makefastpowtable()
{
for(int i=0; i<4097; i++)
tablefracpow2 = powf(2.0, ((float)i-2048)/2048.0);
}
float fastpow2(float x)
{
long *px = (long*)(&x);
const long lx = int(x);
float dx = x-(float)(lx);
int index = int(dx*2048.0)+2048;
index = index & 4095;
x = tablefracpow2[index];
*px += (lx<<23);
return x;
}
David Wallin - White Noise Audio Software
http://www.bleepboxapp.com/
(groove box for iPhone)
http://www.whitenoiseaudio.com/
(VST plugins)
http://www.bleepboxapp.com/
(groove box for iPhone)
http://www.whitenoiseaudio.com/
(VST plugins)
-
- KVRAF
- 2458 posts since 3 Oct, 2002 from SF CA USA NA Earth
What are the per-sample operations between the log and the pow? They probably have equivalents which can be done on the untransformed value. To paraphrase Larry Wall, I suspect you're holding a loaded Uzi and asking what the most efficient way to club someone to death with it is.gy wrote:It's a compressor and yes, for each sample I am performing one log10 and one pow operation. I can't see any way around using them so I am looking to speed them up, in particular the pow method.What are you doing that needs you to be in decibels? Is that a per-sample operation? Can you rethink that processing to work in linear amplitude?
-
- KVRist
- Topic Starter
- 188 posts since 13 Jun, 2004 from SW England
Firstly, thanks everybody for answering.
Reducing the frequency of calculation and interpolating is an option, but this would obviously reduce the sensitivity of the compressor to fast transients.
It's a simple compression transfer function to reduce the gradient above a threshold. I could operate directly on the amplitude, but to achieve the same transformation there would be a logarithmic curve in the transfer function.What are the per-sample operations between the log and the pow?
Reducing the frequency of calculation and interpolating is an option, but this would obviously reduce the sensitivity of the compressor to fast transients.
-
- KVRist
- Topic Starter
- 188 posts since 13 Jun, 2004 from SW England
OK. Many thanks to WhiteNoise for the code. I replaced the look-up with a quadratic approximation, which removes the need for the table and its initialization. I find it to be slightly quicker, if slightly less accurate.
I have also adapted a fast log algorithm that works similarly, using the encoding of a float.
For anyone interested:
Thanks again, GY
I have also adapted a fast log algorithm that works similarly, using the encoding of a float.
For anyone interested:
Code: Select all
inline float FastLog10 (float p_X)
{
// Retrieve a coarse log value from the exponent of the encoded float
int* const intX = reinterpret_cast<int*>(&p_X);
const int coarseLog2 = ((*intX >> 23) & 0xFF) - 127;
// Set the exponent to 1
*intX &= 0x007FFFFF;
*intX |= 0x3F800000;
// Improve the coarse log value using a quadratic approximation
// of log over the range [1, 2]
static const float A = -(1.0f / 3.0f);
static const float B = 2.0f;
static const float C = -(5.0f / 3.0f);
p_X = (((A * p_X) + B) * p_X) + C + static_cast<float>(coarseLog2);
// Convert log to base 10 and return
static const float LogBase10of2 = 0.30102999566398119521373889472449f;
return (p_X * LogBase10of2);
}
inline float FastPow10 (float p_X)
{
// Change power of 10 to power of 2
static const float LogBase2of10 = 3.3219280948873623478703194294894f;
p_X *= LogBase2of10;
// Obtain the integer and fractional parts of the power
const int intX = static_cast<int>(p_X);
float fracX = p_X - static_cast<float>(intX);
// Use a quadratic approximation for the fractional power of 2
static const float A = 0.25f;
static const float B = 0.75f;
static const float C = 1.00f;
p_X = (((A * fracX) + B) * fracX) + C;
// Add the integral power directly to the exponent of the encoded float
int *intXPtr = reinterpret_cast<int*>(&p_X);
*intXPtr += (intX << 23);
return p_X;
}
-
- KVRist
- 192 posts since 4 Nov, 2003 from Philadelphia, PA USA
Welcome gy, good luck with your compressor!
David Wallin - White Noise Audio Software
http://www.bleepboxapp.com/
(groove box for iPhone)
http://www.whitenoiseaudio.com/
(VST plugins)
http://www.bleepboxapp.com/
(groove box for iPhone)
http://www.whitenoiseaudio.com/
(VST plugins)