From 106dd6ce6a1e55f104d90ab85946a63008a50f7e Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 18 May 2017 14:15:10 -0700 Subject: [PATCH] Fast fixed-point log2 approximation --- libraries/audio/src/AudioDynamics.h | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/libraries/audio/src/AudioDynamics.h b/libraries/audio/src/AudioDynamics.h index 2306fecf24..4c2f890c67 100644 --- a/libraries/audio/src/AudioDynamics.h +++ b/libraries/audio/src/AudioDynamics.h @@ -252,6 +252,69 @@ static inline int32_t peaklog2(float* input0, float* input1, float* input2, floa return (e << LOG2_FRACBITS) - (c2 >> 3); } +// +// Count Leading Zeros +// Emulates the CLZ (ARM) and LZCNT (x86) instruction +// +static inline int CLZ(uint32_t x) { + + if (x == 0) { + return 32; + } + + int e = 0; + if (x < 0x00010000) { + x <<= 16; + e += 16; + } + if (x < 0x01000000) { + x <<= 8; + e += 8; + } + if (x < 0x10000000) { + x <<= 4; + e += 4; + } + if (x < 0x40000000) { + x <<= 2; + e += 2; + } + if (x < 0x80000000) { + e += 1; + } + return e; +} + +// +// Compute -log2(x) for x=[0,1] in Q31, result in Q26 +// x = 0 returns 0x7fffffff +// x < 0 undefined +// +static inline int32_t fixlog2(int32_t x) { + + if (x == 0) { + return 0x7fffffff; + } + + // split into e and x - 1.0 + int e = CLZ((uint32_t)x); + x <<= e; // normalize to [0x80000000, 0xffffffff] + x &= 0x7fffffff; // x - 1.0 + + int k = x >> (31 - LOG2_TABBITS); + + // polynomial for log2(1+x) over x=[0,1] + int32_t c0 = log2Table[k][0]; + int32_t c1 = log2Table[k][1]; + int32_t c2 = log2Table[k][2]; + + c1 += MULHI(c0, x); + c2 += MULHI(c1, x); + + // reconstruct result in Q26 + return (e << LOG2_FRACBITS) - (c2 >> 3); +} + // // Compute exp2(-x) for x=[0,32] in Q26, result in Q31 // x < 0 undefined