1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2021 Google LLC. All rights reserved.
4 //
5 // Author: Pin-chih Lin <johnylin@google.com>
6
7 #include <sof/audio/drc/drc_math.h>
8 #include <sof/math/numbers.h>
9
10 #if DRC_HIFI3
11
12 #include <xtensa/tie/xt_hifi3.h>
13
14 #define ONE_OVER_SQRT2_Q30 759250112 /* Q_CONVERT_FLOAT(0.70710678118654752f, 30); 1/sqrt(2) */
15 #define LOG10_FUNC_A5_Q26 75959200 /* Q_CONVERT_FLOAT(1.131880283355712890625f, 26) */
16 #define LOG10_FUNC_A4_Q26 -285795039 /* Q_CONVERT_FLOAT(-4.258677959442138671875f, 26) */
17 #define LOG10_FUNC_A3_Q26 457435200 /* Q_CONVERT_FLOAT(6.81631565093994140625f, 26) */
18 #define LOG10_FUNC_A2_Q26 -410610303 /* Q_CONVERT_FLOAT(-6.1185703277587890625f, 26) */
19 #define LOG10_FUNC_A1_Q26 244982704 /* Q_CONVERT_FLOAT(3.6505267620086669921875f, 26) */
20 #define LOG10_FUNC_A0_Q26 -81731487 /* Q_CONVERT_FLOAT(-1.217894077301025390625f, 26) */
21 #define HALF_Q25 16777216 /* Q_CONVERT_FLOAT(0.5, 25) */
22 #define LOG10_2_Q26 20201782 /* Q_CONVERT_FLOAT(0.301029995663981195214f, 26) */
23 #define NEG_1K_Q21 -2097151999 /* Q_CONVERT_FLOAT(-1000.0f, 21) */
24 #define LOG_10_Q29 1236190976 /* Q_CONVERT_FLOAT(2.3025850929940457f, 29) */
25 #define NEG_30_Q26 -2013265919 /* Q_CONVERT_FLOAT(-30.0f, 26) */
26 #define ASIN_FUNC_A7L_Q30 126897672 /* Q_CONVERT_FLOAT(0.1181826665997505187988281f, 30) */
27 #define ASIN_FUNC_A5L_Q30 43190596 /* Q_CONVERT_FLOAT(4.0224377065896987915039062e-2f, 30) */
28 #define ASIN_FUNC_A3L_Q30 184887136 /* Q_CONVERT_FLOAT(0.1721895635128021240234375f, 30) */
29 #define ASIN_FUNC_A1L_Q30 1073495040 /* Q_CONVERT_FLOAT(0.99977016448974609375f, 30) */
30 #define ASIN_FUNC_A7H_Q26 948097024 /* Q_CONVERT_FLOAT(14.12774658203125f, 26) */
31 #define ASIN_FUNC_A5H_Q26 -2024625535 /* Q_CONVERT_FLOAT(-30.1692714691162109375f, 26) */
32 #define ASIN_FUNC_A3H_Q26 1441234048 /* Q_CONVERT_FLOAT(21.4760608673095703125f, 26) */
33 #define ASIN_FUNC_A1H_Q26 -261361631 /* Q_CONVERT_FLOAT(-3.894591808319091796875f, 26) */
34 #define SQRT2_Q30 1518500224 /* Q_CONVERT_FLOAT(1.4142135623730950488f, 30); sqrt(2) */
35 #define INV_FUNC_A5_Q25 -92027983 /* Q_CONVERT_FLOAT(-2.742647647857666015625f, 25) */
36 #define INV_FUNC_A4_Q25 470207584 /* Q_CONVERT_FLOAT(14.01327800750732421875f, 25) */
37 #define INV_FUNC_A3_Q25 -998064895 /* Q_CONVERT_FLOAT(-29.74465179443359375f, 25) */
38 #define INV_FUNC_A2_Q25 1126492160 /* Q_CONVERT_FLOAT(33.57208251953125f, 25) */
39 #define INV_FUNC_A1_Q25 -713042175 /* Q_CONVERT_FLOAT(-21.25031280517578125f, 25) */
40 #define INV_FUNC_A0_Q25 239989712 /* Q_CONVERT_FLOAT(7.152250766754150390625f, 25) */
41
42 /*
43 * Input depends on precision_x
44 * Output range [0.5, 1); regulated to Q2.30
45 */
rexp_fixed(ae_f32 x,int32_t precision_x,int32_t * e)46 static inline ae_f32 rexp_fixed(ae_f32 x, int32_t precision_x, int32_t *e)
47 {
48 int32_t bit = 31 - AE_NSAZ32_L(x);
49
50 *e = bit - precision_x;
51
52 return AE_SRAA32(x, bit - 30);
53 }
54
55 /*
56 * Input is Q6.26: max 32.0
57 * Output range ~ (-inf, 1.505); regulated to Q6.26: (-32.0, 32.0)
58 */
log10_fixed(ae_f32 x)59 static inline ae_f32 log10_fixed(ae_f32 x)
60 {
61 /* Coefficients obtained from:
62 * fpminimax(log10(x), 5, [|SG...|], [1/2;sqrt(2)/2], absolute);
63 * max err ~= 6.088e-8
64 */
65 int32_t e;
66 int32_t lshift;
67 ae_f32 exp; /* Q7.25 */
68 ae_f32 acc; /* Q6.26 */
69 ae_f32 tmp; /* Q6.26 */
70
71 x = rexp_fixed(x, 26, &e); /* Q2.30 */
72 exp = e << 25; /* Q_CONVERT_FLOAT(e, 25) */
73
74 if ((int32_t)x > (int32_t)ONE_OVER_SQRT2_Q30) {
75 lshift = drc_get_lshift(30, 30, 30);
76 x = drc_mult_lshift(x, ONE_OVER_SQRT2_Q30, lshift);
77 exp = AE_ADD32(exp, HALF_Q25);
78 }
79
80 lshift = drc_get_lshift(26, 30, 26);
81 acc = drc_mult_lshift(LOG10_FUNC_A5_Q26, x, lshift);
82 acc = AE_ADD32(acc, LOG10_FUNC_A4_Q26);
83 acc = drc_mult_lshift(acc, x, lshift);
84 acc = AE_ADD32(acc, LOG10_FUNC_A3_Q26);
85 acc = drc_mult_lshift(acc, x, lshift);
86 acc = AE_ADD32(acc, LOG10_FUNC_A2_Q26);
87 acc = drc_mult_lshift(acc, x, lshift);
88 acc = AE_ADD32(acc, LOG10_FUNC_A1_Q26);
89 acc = drc_mult_lshift(acc, x, lshift);
90 acc = AE_ADD32(acc, LOG10_FUNC_A0_Q26);
91
92 lshift = drc_get_lshift(25, 26, 26);
93 tmp = drc_mult_lshift(exp, LOG10_2_Q26, lshift);
94 acc = AE_ADD32(acc, tmp);
95
96 return acc;
97 }
98
99 /*
100 * Input is Q6.26: max 32.0
101 * Output range ~ (-inf, 30.1030); regulated to Q11.21: (-1024.0, 1024.0)
102 */
drc_lin2db_fixed(int32_t linear)103 inline int32_t drc_lin2db_fixed(int32_t linear)
104 {
105 ae_f32 log10_linear;
106
107 /* For negative or zero, just return a very small dB value. */
108 if (linear <= 0)
109 return NEG_1K_Q21;
110
111 log10_linear = log10_fixed(linear); /* Q6.26 */
112 return drc_mult_lshift(20 << 26, log10_linear, drc_get_lshift(26, 26, 21));
113 }
114
115 /*
116 * Input is Q6.26: max 32.0
117 * Output range ~ (-inf, 3.4657); regulated to Q6.26: (-32.0, 32.0)
118 */
drc_log_fixed(int32_t x)119 inline int32_t drc_log_fixed(int32_t x)
120 {
121 ae_f32 log10_x;
122
123 if (x <= 0)
124 return NEG_30_Q26;
125
126 /* log(x) = log(10) * log10(x) */
127 log10_x = log10_fixed(x); /* Q6.26 */
128 return drc_mult_lshift(LOG_10_Q29, log10_x, drc_get_lshift(29, 26, 26));
129 }
130
131 #ifndef DRC_USE_CORDIC_ASIN
132 /*
133 * Input is Q2.30; valid range: [-1.0, 1.0]
134 * Output range: [-1.0, 1.0]; regulated to Q2.30: (-2.0, 2.0)
135 */
drc_asin_fixed(int32_t x)136 inline int32_t drc_asin_fixed(int32_t x)
137 {
138 /* Coefficients obtained from:
139 * If x <= 1/sqrt(2), then
140 * fpminimax(asin(x), [|1,3,5,7|], [|SG...|], [-1e-30;1/sqrt(2)], absolute)
141 * max err ~= 1.89936e-5
142 * Else then
143 * fpminimax(asin(x), [|1,3,5,7|], [|SG...|], [1/sqrt(2);1], absolute)
144 * max err ~= 3.085226e-2
145 */
146 int32_t lshift;
147 ae_f32 in = x; /* Q2.30 */
148 ae_f32 in2; /* Q2.30 */
149 ae_f32 A7, A5, A3, A1;
150 int32_t qc;
151 ae_f32 acc;
152
153 lshift = drc_get_lshift(30, 30, 30);
154 in2 = drc_mult_lshift(in, in, lshift);
155
156 if (ABS((int32_t)in) <= ONE_OVER_SQRT2_Q30) {
157 A7 = ASIN_FUNC_A7L_Q30;
158 A5 = ASIN_FUNC_A5L_Q30;
159 A3 = ASIN_FUNC_A3L_Q30;
160 A1 = ASIN_FUNC_A1L_Q30;
161 qc = 30;
162 } else {
163 A7 = ASIN_FUNC_A7H_Q26;
164 A5 = ASIN_FUNC_A5H_Q26;
165 A3 = ASIN_FUNC_A3H_Q26;
166 A1 = ASIN_FUNC_A1H_Q26;
167 qc = 26;
168 }
169
170 lshift = drc_get_lshift(qc, 30, qc);
171 acc = drc_mult_lshift(A7, in2, lshift);
172 acc = AE_ADD32(acc, A5);
173 acc = drc_mult_lshift(acc, in2, lshift);
174 acc = AE_ADD32(acc, A3);
175 acc = drc_mult_lshift(acc, in2, lshift);
176 acc = AE_ADD32(acc, A1);
177 acc = drc_mult_lshift(acc, in, lshift);
178 lshift = drc_get_lshift(qc, 30, 30);
179 return drc_mult_lshift(acc, TWO_OVER_PI_Q30, lshift);
180 }
181 #endif /* !DRC_USE_CORDIC_ASIN */
182
183 /*
184 * Input depends on precision_x
185 * Output depends on precision_y
186 */
drc_inv_fixed(int32_t x,int32_t precision_x,int32_t precision_y)187 inline int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y)
188 {
189 /* Coefficients obtained from:
190 * fpminimax(1/x, 5, [|SG...|], [sqrt(2)/2;1], absolute);
191 * max err ~= 1.00388e-6
192 */
193 ae_f32 in;
194 int32_t lshift;
195 int32_t e;
196 int32_t precision_inv;
197 int32_t sqrt2_extracted = 0;
198 ae_f32 acc;
199
200 in = rexp_fixed(x, precision_x, &e); /* Q2.30 */
201
202 if (ABS((int32_t)in) < ONE_OVER_SQRT2_Q30) {
203 lshift = drc_get_lshift(30, 30, 30);
204 in = drc_mult_lshift(in, SQRT2_Q30, lshift);
205 sqrt2_extracted = 1;
206 }
207
208 lshift = drc_get_lshift(25, 30, 25);
209 acc = drc_mult_lshift(INV_FUNC_A5_Q25, in, lshift);
210 acc = AE_ADD32(acc, INV_FUNC_A4_Q25);
211 acc = drc_mult_lshift(acc, in, lshift);
212 acc = AE_ADD32(acc, INV_FUNC_A3_Q25);
213 acc = drc_mult_lshift(acc, in, lshift);
214 acc = AE_ADD32(acc, INV_FUNC_A2_Q25);
215 acc = drc_mult_lshift(acc, in, lshift);
216 acc = AE_ADD32(acc, INV_FUNC_A1_Q25);
217 acc = drc_mult_lshift(acc, in, lshift);
218 acc = AE_ADD32(acc, INV_FUNC_A0_Q25);
219
220 if (sqrt2_extracted)
221 acc = drc_mult_lshift(acc, SQRT2_Q30, lshift);
222
223 precision_inv = e + 25;
224 acc = AE_SLAA32S(acc, precision_y - precision_inv);
225 return acc;
226 }
227
228 #endif /* DRC_HIFI3 */
229