Skip to content

Commit 61ea083

Browse files
DRC: math: Replace exponential function for performance
For DRC performance, replace "exp_small_fixed()" with "sofm_exp_int32()". Included supporting change to include "sofm_exp_int32()" within exp_fixed() and removed "exp_small_fixed()" from future use. Signed-off-by: shastry <malladi.sastry@intel.com>
1 parent 1b81841 commit 61ea083

File tree

12 files changed

+214
-110
lines changed

12 files changed

+214
-110
lines changed

src/audio/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ config COMP_DRC
278278
bool "Dynamic Range Compressor component"
279279
select CORDIC_FIXED
280280
select NUMBERS_NORM
281-
select MATH_DECIBELS
282281
select COMP_BLOB
282+
select MATH_EXP
283283
default n
284284
help
285285
Select for Dynamic Range Compressor (DRC) component. A DRC can be used

src/audio/drc/drc_generic.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sof/audio/drc/drc_math.h>
1111
#include <sof/audio/format.h>
1212
#include <sof/math/decibels.h>
13+
#include <sof/math/exp_fcn.h>
1314
#include <sof/math/numbers.h>
1415
#include <stdint.h>
1516

@@ -35,7 +36,7 @@ static int32_t knee_curveK(const struct sof_drc_params *p, int32_t x)
3536
* beta = -expf(k * linear_threshold) / k
3637
* gamma = -k * x
3738
*/
38-
knee_exp_gamma = exp_fixed(Q_MULTSR_32X32((int64_t)x, -p->K, 31, 20, 27)); /* Q12.20 */
39+
knee_exp_gamma = sofm_exp_fixed(Q_MULTSR_32X32((int64_t)x, -p->K, 31, 20, 27)); /* Q12.20 */
3940
return p->knee_alpha + Q_MULTSR_32X32((int64_t)p->knee_beta, knee_exp_gamma, 24, 20, 24);
4041
}
4142

@@ -65,8 +66,10 @@ static int32_t volume_gain(const struct sof_drc_params *p, int32_t x)
6566
* => y/x = ratio_base * x^(s - 1)
6667
* => y/x = ratio_base * e^(log(x) * (s - 1))
6768
*/
68-
exp_knee = exp_fixed(Q_MULTSR_32X32((int64_t)drc_log_fixed(Q_SHIFT_RND(x, 31, 26)),
69-
(p->slope - ONE_Q30), 26, 30, 27)); /* Q12.20 */
69+
exp_knee = sofm_exp_fixed(
70+
Q_MULTSR_32X32((int64_t)
71+
drc_log_fixed(Q_SHIFT_RND(x, 31, 26)),
72+
(p->slope - ONE_Q30), 26, 30, 27)); /* Q12.20 */
7073
y = Q_MULTSR_32X32((int64_t)p->ratio_base, exp_knee, 30, 20, 30);
7174
}
7275

src/audio/drc/drc_hifi3.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sof/audio/drc/drc_math.h>
1111
#include <sof/audio/format.h>
1212
#include <sof/math/decibels.h>
13+
#include <sof/math/exp_fcn.h>
1314
#include <sof/math/numbers.h>
1415
#include <stdint.h>
1516

@@ -41,7 +42,7 @@ static int32_t knee_curveK(const struct sof_drc_params *p, int32_t x)
4142
* gamma = -k * x
4243
*/
4344
gamma = drc_mult_lshift(x, -p->K, drc_get_lshift(31, 20, 27));
44-
knee_exp_gamma = exp_fixed(gamma);
45+
knee_exp_gamma = sofm_exp_fixed(gamma);
4546
knee_curve_k = drc_mult_lshift(p->knee_beta, knee_exp_gamma, drc_get_lshift(24, 20, 24));
4647
knee_curve_k = AE_ADD32(knee_curve_k, p->knee_alpha);
4748
return knee_curve_k;
@@ -77,7 +78,7 @@ static int32_t volume_gain(const struct sof_drc_params *p, int32_t x)
7778
tmp = AE_SRAI32R(x, 5); /* Q1.31 -> Q5.26 */
7879
tmp = drc_log_fixed(tmp); /* Q6.26 */
7980
tmp2 = AE_SUB32(p->slope, ONE_Q30); /* Q2.30 */
80-
exp_knee = exp_fixed(drc_mult_lshift(tmp, tmp2, drc_get_lshift(26, 30, 27)));
81+
exp_knee = sofm_exp_fixed(drc_mult_lshift(tmp, tmp2, drc_get_lshift(26, 30, 27)));
8182
y = drc_mult_lshift(p->ratio_base, exp_knee, drc_get_lshift(30, 20, 30));
8283
}
8384

src/audio/drc/drc_math_generic.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <sof/audio/drc/drc_math.h>
88
#include <sof/audio/format.h>
99
#include <sof/math/decibels.h>
10+
#include <sof/math/exp_fcn.h>
1011
#include <sof/math/numbers.h>
1112
#include <sof/math/trig.h>
1213

@@ -219,8 +220,6 @@ inline int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y
219220
#undef qc
220221
}
221222

222-
#endif /* DRC_GENERIC */
223-
224223
/*
225224
* Input x is Q6.26; valid range: (0.0, 32.0); x <= 0 is not supported
226225
* y is Q2.30: (-2.0, 2.0)
@@ -233,8 +232,8 @@ inline int32_t drc_pow_fixed(int32_t x, int32_t y)
233232
return 0;
234233

235234
/* x^y = expf(y * log(x)) */
236-
return exp_fixed(q_mult(y, drc_log_fixed(x), 30, 26, 27));
235+
return sofm_exp_fixed(q_mult(y, drc_log_fixed(x), 30, 26, 27));
237236
}
238-
237+
#endif
239238
#undef q_multq
240239
#undef q_mult

src/include/sof/math/decibels.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111

1212
#include <stdint.h>
1313

14-
#define EXP_FIXED_INPUT_QY 27
15-
#define EXP_FIXED_OUTPUT_QY 20
16-
#define DB2LIN_FIXED_INPUT_QY 24
17-
#define DB2LIN_FIXED_OUTPUT_QY 20
18-
19-
int32_t exp_fixed(int32_t x); /* Input is Q5.27, output is Q12.20 */
2014
int32_t db2lin_fixed(int32_t x); /* Input is Q8.24, output is Q12.20 */
2115

2216
#endif /* __SOF_MATH_DECIBELS_H__ */

src/include/sof/math/exp_fcn.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@
2626

2727
#endif
2828

29-
int32_t sofm_exp_int32(int32_t x);
30-
29+
int32_t sofm_exp_int32(int32_t x); /* Input is Q4.28, Output is Q9.23 */
30+
int32_t sofm_exp_fixed(int32_t x); /* Input is Q5.27, output is Q12.20 */
3131
#endif

src/math/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ config MATH_EXP
4747
an input range of -5 to +5 gives positive numbers between 0.00673794699908547 and
4848
148.413159102577. The precision of this function is 1e-4.
4949

50+
config MATH_EXP_SMALL_FXD
51+
bool "Small Exponential functions"
52+
default n
53+
help
54+
By selecting this, the 32-bit exp_small_fixed() function can be used to calculate
55+
exponential values. With a mean thdn of -131.205(dBc), an exponential function with
56+
an input range of -2 to +2 gives positive numbers between 0.135335255 and
57+
7.38905609. The precision of this function is 1e-6.
58+
5059
config NATURAL_LOGARITHM_FIXED
5160
bool "Natural Logarithm function"
5261
default n

src/math/auditory/auditory.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <rtos/alloc.h>
99
#include <sof/math/auditory.h>
1010
#include <sof/math/decibels.h>
11+
#include <sof/math/exp_fcn.h>
1112
#include <sof/math/fft.h>
1213
#include <sof/math/log.h>
1314
#include <sof/math/numbers.h>
@@ -80,7 +81,7 @@ int16_t psy_mel_to_hz(int16_t mel)
8081
return 0;
8182

8283
exp_arg = Q_MULTSR_32X32((int64_t)mel, ONE_OVER_MELDIV_Q31, 2, 31, 27);
83-
exp = exp_fixed(exp_arg) - ONE_Q20;
84+
exp = sofm_exp_fixed(exp_arg) - ONE_Q20;
8485
hz = Q_MULTSR_32X32((int64_t)exp, 700, 20, 0, 0);
8586
return hz;
8687
}

src/math/decibels.c

Lines changed: 2 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,11 @@
66

77
#include <sof/audio/format.h>
88
#include <sof/math/decibels.h>
9+
#include <sof/math/exp_fcn.h>
910
#include <stdint.h>
1011

11-
#define ONE_Q20 Q_CONVERT_FLOAT(1.0, 20) /* Use Q12.20 */
12-
#define ONE_Q23 Q_CONVERT_FLOAT(1.0, 23) /* Use Q9.23 */
13-
#define TWO_Q27 Q_CONVERT_FLOAT(2.0, 27) /* Use Q5.27 */
14-
#define MINUS_TWO_Q27 Q_CONVERT_FLOAT(-2.0, 27) /* Use Q5.27 */
1512
#define LOG10_DIV20_Q27 Q_CONVERT_FLOAT(0.1151292546, 27) /* Use Q5.27 */
1613

17-
/* Exponent function for small values of x. This function calculates
18-
* fairly accurately exponent for x in range -2.0 .. +2.0. The iteration
19-
* uses first 11 terms of Taylor series approximation for exponent
20-
* function. With the current scaling the numerator just remains under
21-
* 64 bits with the 11 terms.
22-
*
23-
* See https://en.wikipedia.org/wiki/Exponential_function#Computation
24-
*
25-
* The input is Q3.29
26-
* The output is Q9.23
27-
*/
28-
29-
static int32_t exp_small_fixed(int32_t x)
30-
{
31-
int64_t p;
32-
int64_t num = Q_SHIFT_RND(x, 29, 23);
33-
int32_t y0 = (int32_t)num;
34-
int32_t den = 1;
35-
int32_t inc;
36-
int k;
37-
38-
/* Numerator is x^k, denominator is k! */
39-
for (k = 2; k < 12; k++) {
40-
p = num * x; /* Q9.23 x Q3.29 -> Q12.52 */
41-
num = Q_SHIFT_RND(p, 52, 23);
42-
den = den * k;
43-
inc = (int32_t)(num / den);
44-
y0 += inc;
45-
}
46-
47-
return y0 + ONE_Q23;
48-
}
49-
5014
/* Decibels to linear conversion: The function uses exp() to calculate
5115
* the linear value. The argument is multiplied by log(10)/20 to
5216
* calculate equivalent of 10^(db/20).
@@ -68,50 +32,5 @@ int32_t db2lin_fixed(int32_t db)
6832

6933
/* Q8.24 x Q5.27, result needs to be Q5.27 */
7034
arg = (int32_t)Q_MULTSR_32X32((int64_t)db, LOG10_DIV20_Q27, 24, 27, 27);
71-
return exp_fixed(arg);
72-
}
73-
74-
/* Fixed point exponent function for approximate range -11.5 .. 7.6
75-
* that corresponds to decibels range -100 .. +66 dB.
76-
*
77-
* The functions uses rule exp(x) = exp(x/2) * exp(x/2) to reduce
78-
* the input argument for private small value exp() function that is
79-
* accurate with input range -2.0 .. +2.0. The number of possible
80-
* divisions by 2 is computed into variable n. The returned value is
81-
* exp()^(2^n).
82-
*
83-
* Input is Q5.27, -16.0 .. +16.0, but note the input range limitation
84-
* Output is Q12.20, 0.0 .. +2048.0
85-
*/
86-
87-
int32_t exp_fixed(int32_t x)
88-
{
89-
int32_t xs;
90-
int32_t y;
91-
int32_t y0;
92-
int i;
93-
int n = 0;
94-
95-
if (x < Q_CONVERT_FLOAT(-11.5, 27))
96-
return 0;
97-
98-
if (x > Q_CONVERT_FLOAT(7.6245, 27))
99-
return INT32_MAX;
100-
101-
/* x is Q5.27 */
102-
xs = x;
103-
while (xs >= TWO_Q27 || xs <= MINUS_TWO_Q27) {
104-
xs >>= 1;
105-
n++;
106-
}
107-
108-
/* exp_small_fixed() input is Q3.29, while x1 is Q5.27
109-
* exp_small_fixed() output is Q9.23, while y0 is Q12.20
110-
*/
111-
y0 = Q_SHIFT_RND(exp_small_fixed(Q_SHIFT_LEFT(xs, 27, 29)), 23, 20);
112-
y = ONE_Q20;
113-
for (i = 0; i < (1 << n); i++)
114-
y = (int32_t)Q_MULTSR_32X32((int64_t)y, y0, 20, 20, 20);
115-
116-
return y;
35+
return sofm_exp_fixed(arg);
11736
}

src/math/exp_fcn.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
*
77
*/
88

9+
#include <sof/audio/drc/drc_plat_conf.h>
10+
#include <sof/math/decibels.h>
11+
#include <sof/audio/format.h>
912
#include <sof/math/exp_fcn.h>
1013
#include <sof/math/numbers.h>
1114
#include <sof/common.h>
@@ -20,7 +23,7 @@
2023
#define SOFM_BIT_MASK_Q62P2 0x4000000000000000LL
2124
#define SOFM_CONVERG_ERROR 28823037607936LL // error smaller than 1e-4,1/2 ^ -44.7122876200884
2225
#define SOFM_BIT_MASK_LOW_Q27P5 0x8000000
23-
#define SOFM_QUOTIENT_SCALE BIT(30)
26+
#define SOFM_QUOTIENT_SCALE 0x400000000
2427
#define SOFM_TERMS_Q23P9 8388608
2528
#define SOFM_LSHIFT_BITS 8192
2629

@@ -176,6 +179,7 @@ static inline int64_t lomul_s64_sr_sat_near(int64_t a, int64_t b)
176179
*| 32 | 28 | 1 | 32 | 23 | 0 | 4.28 | 9.23 |
177180
*+------------------+-----------------+--------+--------+
178181
*/
182+
//static inline int32_t sofm_exp_int32(int32_t x)
179183
int32_t sofm_exp_int32(int32_t x)
180184
{
181185
uint64_t ou0Hi;
@@ -217,4 +221,52 @@ int32_t sofm_exp_int32(int32_t x)
217221
}
218222
return ts;
219223
}
224+
225+
#define ONE_Q20 Q_CONVERT_FLOAT(1.0, 20) /* Use Q12.20 */
226+
#define TWO_Q27 Q_CONVERT_FLOAT(2.0, 27) /* Use Q5.27 */
227+
#define MINUS_TWO_Q27 Q_CONVERT_FLOAT(-2.0, 27) /* Use Q5.27 */
228+
229+
/* Fixed point exponent function for approximate range -11.5 .. 7.6
230+
* that corresponds to decibels range -100 .. +66 dB.
231+
*
232+
* The functions uses rule exp(x) = exp(x/2) * exp(x/2) to reduce
233+
* the input argument for private small value exp() function that is
234+
* accurate with input range -2.0 .. +2.0. The number of possible
235+
* divisions by 2 is computed into variable n. The returned value is
236+
* exp()^(2^n).
237+
*
238+
* Input is Q5.27, -16.0 .. +16.0, but note the input range limitation
239+
* Output is Q12.20, 0.0 .. +2048.0
240+
*/
241+
int32_t sofm_exp_fixed(int32_t x)
242+
{
243+
int32_t xs;
244+
int32_t y;
245+
int32_t y0;
246+
int i;
247+
int n = 0;
248+
249+
if (x < Q_CONVERT_FLOAT(-11.5, 27))
250+
return 0;
251+
252+
if (x > Q_CONVERT_FLOAT(7.6245, 27))
253+
return INT32_MAX;
254+
255+
/* x is Q5.27 */
256+
xs = x;
257+
while (xs >= TWO_Q27 || xs <= MINUS_TWO_Q27) {
258+
xs >>= 1;
259+
n++;
260+
}
261+
262+
/* sofm_exp_int32() input is Q4.28, while x1 is Q5.27
263+
* sofm_exp_int32() output is Q9.23, while y0 is Q12.20
264+
*/
265+
y0 = Q_SHIFT_RND(sofm_exp_int32(Q_SHIFT_LEFT(xs, 27, 28)), 23, 20);
266+
y = ONE_Q20;
267+
for (i = 0; i < (1 << n); i++)
268+
y = (int32_t)Q_MULTSR_32X32((int64_t)y, y0, 20, 20, 20);
269+
270+
return y;
271+
}
220272
#endif

0 commit comments

Comments
 (0)