1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2020 Google LLC. All rights reserved.
4  *
5  * Author: Pin-chih Lin <johnylin@google.com>
6  */
7 #ifndef __SOF_AUDIO_DRC_DRC_MATH_H__
8 #define __SOF_AUDIO_DRC_DRC_MATH_H__
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <sof/audio/drc/drc_plat_conf.h>
13 #include <sof/audio/format.h>
14 #include <sof/math/numbers.h>
15 #include <sof/math/trig.h>
16 
17 /* Unmark this define to use cordic arc sine implementation. */
18 /* #define DRC_USE_CORDIC_ASIN */
19 
20 #if DRC_HIFI3
21 
22 #include <xtensa/tie/xt_hifi3.h>
23 
24 #define PI_OVER_TWO_Q30 1686629713 /* Q_CONVERT_FLOAT(1.57079632679489661923, 30); pi/2 */
25 #define TWO_OVER_PI_Q30 683565248 /* Q_CONVERT_FLOAT(0.63661977236758134, 30); 2/pi */
26 
27 /*
28  * A substitutive function of Q_MULTSR_32X32(a, b, qa, qb, qy) in HIFI manners.
29  *
30  * In AE_MULF32R, it takes the multiplication of 1.31 and 1.31 to 17.47, which means it does
31  * right-shift 15 bits. Let's consider a is .qa, b is .qb, then tmp will be .(qa+qb-15)
32  * In AE_ROUND32F48SSYM, it rounds 17.47 to 1.31, equally right-shifts 16 bits. Let's consider the
33  * output is .qy, then tmp here needs to be .(qy+16)
34  * If we set the left-shift bit from the former tmp to the latter tmp as "lshift", then:
35  *     (qa+qb-15) + lshift = (qy+16)
36  *     lshift = qy-qa-qb+31
37  */
drc_mult_lshift(int32_t a,int32_t b,int32_t lshift)38 static inline int32_t drc_mult_lshift(int32_t a, int32_t b, int32_t lshift)
39 {
40 	ae_f64 tmp;
41 	ae_f32 y;
42 
43 	tmp = AE_MULF32R_LL(a, b);
44 	tmp = AE_SLAA64S(tmp, lshift);
45 	y = AE_ROUND32F48SSYM(tmp);
46 	return y;
47 }
48 
drc_get_lshift(int32_t qa,int32_t qb,int32_t qy)49 static inline int32_t drc_get_lshift(int32_t qa, int32_t qb, int32_t qy)
50 {
51 	return qy - qa - qb + 31;
52 }
53 
54 /*
55  * Input is Q2.30: (-2.0, 2.0)
56  * Output range: (-1.0, 1.0); regulated to Q1.31: (-1.0, 1.0)
57  */
drc_sin_fixed(int32_t x)58 static inline int32_t drc_sin_fixed(int32_t x)
59 {
60 	const int32_t lshift = drc_get_lshift(30, 30, 28);
61 	int32_t denorm_x = drc_mult_lshift(x, PI_OVER_TWO_Q30, lshift);
62 	int32_t sin_val = sin_fixed_16b(denorm_x);
63 
64 	return sin_val << 16;
65 }
66 
67 #ifdef DRC_USE_CORDIC_ASIN
68 /*
69  * Input is Q2.30; valid range: [-1.0, 1.0]
70  * Output range: [-1.0, 1.0]; regulated to Q2.30: (-2.0, 2.0)
71  */
drc_asin_fixed(int32_t x)72 static inline int32_t drc_asin_fixed(int32_t x)
73 {
74 	const int32_t lshift = drc_get_lshift(30, 30, 30);
75 	int32_t asin_val = asin_fixed_16b(x); /* Q2.14, [-pi/2, pi/2] */
76 
77 	return drc_mult_lshift(asin_val << 16, TWO_OVER_PI_Q30, lshift);
78 }
79 #endif /* DRC_USE_CORDIC_ASIN */
80 
81 #else
82 
83 /*
84  * Input is Q2.30: (-2.0, 2.0)
85  * Output range: (-1.0, 1.0); regulated to Q1.31: (-1.0, 1.0)
86  */
drc_sin_fixed(int32_t x)87 static inline int32_t drc_sin_fixed(int32_t x)
88 {
89 	const int32_t PI_OVER_TWO = Q_CONVERT_FLOAT(1.57079632679489661923, 30);
90 	int32_t sin_val = sin_fixed_16b(Q_MULTSR_32X32((int64_t)x, PI_OVER_TWO, 30, 30, 28));
91 
92 	return sin_val << 16;
93 }
94 
95 #ifdef DRC_USE_CORDIC_ASIN
96 /*
97  * Input is Q2.30; valid range: [-1.0, 1.0]
98  * Output range: [-1.0, 1.0]; regulated to Q2.30: (-2.0, 2.0)
99  */
drc_asin_fixed(int32_t x)100 static inline int32_t drc_asin_fixed(int32_t x)
101 {
102 	const int32_t TWO_OVER_PI = Q_CONVERT_FLOAT(0.63661977236758134, 30); /* 2/pi */
103 	int32_t asin_val = asin_fixed_16b(x); /* Q2.14, [-pi/2, pi/2] */
104 
105 	return Q_MULTSR_32X32((int64_t)asin_val, TWO_OVER_PI, 14, 30, 30);
106 }
107 #endif /* DRC_USE_CORDIC_ASIN */
108 
109 #endif /* DRC_HIFI3 */
110 
111 int32_t drc_lin2db_fixed(int32_t linear); /* Input:Q6.26 Output:Q11.21 */
112 int32_t drc_log_fixed(int32_t x); /* Input:Q6.26 Output:Q6.26 */
113 int32_t drc_pow_fixed(int32_t x, int32_t y); /* Input:Q6.26, Q2.30 Output:Q12.20 */
114 int32_t drc_inv_fixed(int32_t x, int32_t precision_x, int32_t precision_y);
115 
116 #ifndef DRC_USE_CORDIC_ASIN
117 int32_t drc_asin_fixed(int32_t x); /* Input:Q2.30 Output:Q2.30 */
118 #endif /* !DRC_USE_CORDIC_ASIN */
119 
120 #endif //  __SOF_AUDIO_DRC_DRC_MATH_H__
121