1 /******************************************************************************
2 *
3 * Copyright (C) 2023 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20 #ifndef IXHEAACD_MPS_BASIC_OP_H
21 #define IXHEAACD_MPS_BASIC_OP_H
22
23 #define NORM32 (0x40000000)
24 #define INV_SQRT_2_Q31 (1518500250)
25 #define Q_SQRT_TAB (15)
26 #define LOG2XQ17 (5171707904LL)
27 #define LOG_COEFF1 (27890)
28 #define LOG_COEFF2 (16262)
29 #define LOG_COEFF3 (7574)
30 #define LOG_COEFF4 (1786)
31
32 #define TRIG_TABLE_CONV_FAC 326
33
ixheaacd_mps_get_rshift_bits(WORD64 a)34 static PLATFORM_INLINE WORD32 ixheaacd_mps_get_rshift_bits(WORD64 a) {
35 WORD32 temp_1, temp_2;
36 temp_1 = (WORD32)(a >> 32);
37 temp_2 = ixheaacd_norm32(temp_1);
38 if (temp_2 < 31) {
39 return (32 - temp_2);
40 } else {
41 temp_2 = (WORD32)(a);
42 if ((temp_1 ^ temp_2) < 0) {
43 return 1;
44 } else {
45 return 0;
46 }
47 }
48 }
49
ixheaacd_mps_narrow(WORD64 a,WORD16 * qfac)50 static PLATFORM_INLINE WORD32 ixheaacd_mps_narrow(WORD64 a, WORD16 *qfac) {
51 WORD32 x;
52 x = ixheaacd_mps_get_rshift_bits(a);
53 *qfac = 20 - x;
54 return (WORD32)((WORD64)a >> x);
55 }
56
ixheaacd_mps_sqrt(WORD32 num,WORD16 * q,const WORD32 * sqrt_tab)57 static PLATFORM_INLINE WORD32 ixheaacd_mps_sqrt(WORD32 num, WORD16 *q, const WORD32 *sqrt_tab) {
58 WORD32 index, answer, temp;
59 WORD k;
60
61 if (num == 0) return 0;
62
63 k = ixheaacd_norm32(num);
64 temp = ixheaacd_shr32(ixheaacd_shl32(num, k), 21);
65 *q += k;
66 index = temp & 0x1FF;
67 answer = sqrt_tab[index];
68 if (*q & 1) {
69 *q -= 1;
70 answer = ixheaacd_mult32_shl(answer, INV_SQRT_2_Q31);
71 }
72 *q = *q >> 1;
73 *q += Q_SQRT_TAB;
74 return answer;
75 }
76
ixheaacd_mps_reshape_add32(WORD32 op1,WORD32 op2,WORD16 * qop1,WORD16 qop2)77 static PLATFORM_INLINE WORD32 ixheaacd_mps_reshape_add32(WORD32 op1, WORD32 op2, WORD16 *qop1,
78 WORD16 qop2) {
79 WORD64 tempresult;
80 if (0 == op2) {
81 return op1;
82 }
83 if (0 == op1) {
84 *qop1 = qop2;
85 return op2;
86 }
87 if (*qop1 < qop2) {
88 if ((qop2 - *qop1) > 31)
89 op2 = 0;
90 else
91 op2 = op2 >> (qop2 - *qop1);
92 tempresult = (WORD64)op1 + (WORD64)op2;
93 } else {
94 if ((*qop1 - qop2) > 31)
95 op1 = 0;
96 else
97 op1 = op1 >> (*qop1 - qop2);
98 *qop1 = qop2;
99 tempresult = (WORD64)op1 + (WORD64)op2;
100 }
101 if (tempresult > (WORD32)0x7fffffff || tempresult < (WORD32)0x80000000) {
102 tempresult = tempresult >> 1;
103 *qop1 -= 1;
104 }
105 return (WORD32)tempresult;
106 }
107
ixheaacd_mps_add32(WORD32 a,WORD32 b,WORD16 * q_a,WORD16 q_b)108 static PLATFORM_INLINE WORD32 ixheaacd_mps_add32(WORD32 a, WORD32 b, WORD16 *q_a, WORD16 q_b) {
109 WORD64 temp_result;
110
111 if (a == 0 || b == 0) {
112 if (b == 0) {
113 return a;
114 } else {
115 *q_a = q_b;
116 return b;
117 }
118 }
119 if (*q_a > q_b) {
120 if (((*q_a) - q_b) > 31) {
121 a = 0;
122 *q_a = q_b;
123 } else {
124 a = (a >> ((*q_a) - q_b));
125 *q_a = q_b;
126 }
127 } else {
128 if ((q_b - (*q_a)) > 31) {
129 b = 0;
130 } else {
131 b = (b >> (q_b - (*q_a)));
132 q_b = *q_a;
133 }
134 }
135 temp_result = (WORD64)a + (WORD64)b;
136 if (temp_result > (WORD32)0x7fffffff || temp_result < (WORD32)0x80000000) {
137 temp_result = temp_result >> 1;
138 *q_a -= 1;
139 }
140
141 return (WORD32)temp_result;
142 }
143
ixheaacd_mps_mult32(WORD32 a,WORD32 b,WORD16 * q_a,WORD16 q_b)144 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32(WORD32 a, WORD32 b, WORD16 *q_a, WORD16 q_b) {
145 WORD64 temp_result;
146 WORD32 temp;
147
148 if (a == 0 || b == 0) {
149 temp_result = 0;
150 *q_a = 15;
151 return (WORD32)temp_result;
152 }
153
154 *q_a = *q_a + q_b;
155
156 temp_result = (WORD64)a * (WORD64)b;
157 temp = ixheaacd_mps_get_rshift_bits(temp_result);
158 if (0 != temp) {
159 *q_a -= temp;
160 temp_result = temp_result >> temp;
161 }
162
163 return (WORD32)temp_result;
164 }
165
ixheaacd_mps_mult32x32(WORD32 a,WORD32 b,WORD16 * q_a,WORD16 q_b)166 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32x32(WORD32 a, WORD32 b, WORD16 *q_a,
167 WORD16 q_b) {
168 WORD64 temp_result;
169 if (a == 0 || b == 0) {
170 temp_result = 0;
171 *q_a = 15;
172 return (WORD32)temp_result;
173 }
174 *q_a = *q_a + q_b;
175
176 temp_result = (WORD64)a * (WORD64)b;
177 while (temp_result > (WORD32)0x7fffffff || temp_result < (WORD32)0x80000000) {
178 temp_result = temp_result >> 1;
179 *q_a -= 1;
180 }
181
182 return (WORD32)temp_result;
183 }
184
ixheaacd_mps_mult32_shr_n(WORD32 a,WORD32 b,WORD16 n)185 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32_shr_n(WORD32 a, WORD32 b, WORD16 n) {
186 WORD32 result;
187 WORD64 temp_result;
188
189 temp_result = (WORD64)a * (WORD64)b;
190 result = (WORD32)(temp_result >> n);
191
192 return (result);
193 }
194
ixheaacd_mps_mult32_shr_30(WORD32 a,WORD32 b)195 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32_shr_30(WORD32 a, WORD32 b) {
196 WORD32 result;
197 WORD64 temp_result;
198
199 temp_result = (WORD64)a * (WORD64)b;
200 result = (WORD32)(temp_result >> 30);
201
202 return (result);
203 }
204
ixheaacd_mps_mult32_shr_16(WORD32 a,WORD32 b)205 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32_shr_16(WORD32 a, WORD32 b) {
206 WORD32 result;
207 WORD64 temp_result;
208
209 temp_result = (WORD64)a * (WORD64)b;
210 result = (WORD32)(temp_result >> 16);
211 return (result);
212 }
213
ixheaacd_mps_mult32x16_shr_16(WORD32 a,WORD32 b)214 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32x16_shr_16(WORD32 a, WORD32 b) {
215 WORD32 result;
216 WORD64 temp_result;
217 temp_result = (WORD64)a * (WORD64)b;
218 result = (WORD32)(temp_result >> 16);
219 return (result);
220 }
221
ixheaacd_mps_mult32_shr_15(WORD32 a,WORD32 b)222 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32_shr_15(WORD32 a, WORD32 b) {
223 WORD32 result;
224 WORD64 temp_result;
225 temp_result = (WORD64)a * (WORD64)b;
226 result = (WORD32)(temp_result >> 15);
227
228 return (result);
229 }
230
ixheaacd_mps_mult32_shr_14(WORD32 a,WORD32 b)231 static PLATFORM_INLINE WORD32 ixheaacd_mps_mult32_shr_14(WORD32 a, WORD32 b) {
232 WORD32 result;
233 WORD64 temp_result;
234
235 temp_result = (WORD64)a * (WORD64)b;
236 result = (WORD32)(temp_result >> 16);
237 result = result << 2;
238
239 return (result);
240 }
241
ixheaacd_mps_div_32(WORD32 a,WORD32 b,WORD16 * q_format)242 static PLATFORM_INLINE WORD32 ixheaacd_mps_div_32(WORD32 a, WORD32 b, WORD16 *q_format) {
243 WORD32 quotient;
244 UWORD32 mantissa_nr, mantissa_dr;
245 LOOPINDEX i;
246 WORD q_nr, q_dr;
247
248 quotient = 0;
249
250 if (0 == b) {
251 *q_format = 0;
252 return (a);
253 }
254
255 quotient = 0;
256
257 q_nr = ixheaacd_norm32(a);
258 mantissa_nr = (UWORD32)a << (q_nr);
259 q_dr = ixheaacd_norm32(b);
260 mantissa_dr = (UWORD32)b << (q_dr);
261 *q_format = (WORD)(30 + q_nr - q_dr);
262
263 for (i = 0; i < 31; i++) {
264 quotient <<= 1;
265
266 if (mantissa_nr >= mantissa_dr) {
267 mantissa_nr -= mantissa_dr;
268 quotient += 1;
269 }
270 mantissa_nr <<= 1;
271 }
272
273 if ((a ^ b) < 0) {
274 return -(quotient);
275 }
276
277 return quotient;
278 }
279
ixheaacd_mps_convert_to_qn(WORD32 temp,WORD16 qtemp,WORD16 n)280 static WORD32 ixheaacd_mps_convert_to_qn(WORD32 temp, WORD16 qtemp, WORD16 n) {
281 WORD64 result;
282 if (qtemp == n)
283 return temp;
284 else if (qtemp > n)
285 temp = (WORD32)((WORD64)temp >> (qtemp - n));
286 else {
287 result = (WORD32)((WORD64)temp << (n - qtemp));
288 if (result > (WORD32)0x7fffffff || result < (WORD32)0x80000000) {
289 return 0;
290 } else
291 temp = (WORD32)result;
292 }
293 return temp;
294 }
295
ixheaacd_mps_div32_in_q15(WORD32 num,WORD32 den)296 static PLATFORM_INLINE WORD32 ixheaacd_mps_div32_in_q15(WORD32 num, WORD32 den) {
297 WORD32 quotient;
298 WORD16 q_quotient;
299
300 quotient = ixheaacd_mps_div_32(num, den, &q_quotient);
301 quotient = ixheaacd_mps_convert_to_qn(quotient, q_quotient, 15);
302 return quotient;
303 }
304
ixheaacd_mps_log10(WORD32 a,WORD16 q_a)305 static PLATFORM_INLINE WORD32 ixheaacd_mps_log10(WORD32 a, WORD16 q_a) {
306 WORD32 x;
307 WORD16 q_x;
308 WORD32 j, k, temp;
309 WORD16 q_num;
310 q_num = ixheaacd_norm32(a);
311 a = a << q_num;
312 x = ixheaacd_mps_div_32(a, NORM32, &q_x);
313
314 if (q_x > 16)
315 x = x >> (q_x - 16);
316 else
317 x = x << (16 - q_x);
318
319 q_num = 30 - (q_num + q_a);
320
321 j = x - ONE_IN_Q16;
322 k = ixheaacd_mps_mult32_shr_16(SQRT_THREE_Q15, j);
323 temp = ixheaacd_mps_mult32_shr_16(j, j);
324 k -= ixheaacd_mps_mult32_shr_16(LOG_COEFF1, temp);
325 temp = ixheaacd_mps_mult32_shr_16(temp, j);
326 k += ixheaacd_mps_mult32_shr_16(LOG_COEFF2, temp);
327 temp = ixheaacd_mps_mult32_shr_16(temp, j);
328 k -= ixheaacd_mps_mult32_shr_16(LOG_COEFF3, temp);
329 temp = ixheaacd_mps_mult32_shr_16(temp, j);
330 k += ixheaacd_mps_mult32_shr_16(LOG_COEFF4, temp);
331
332 k += (WORD32)(q_num * ((WORD32)LOG2XQ17));
333
334 return (k >> 1);
335 }
336
ixheaacd_mps_cos(WORD32 a,const WORD32 * cosine_tab)337 static PLATFORM_INLINE WORD32 ixheaacd_mps_cos(WORD32 a, const WORD32 *cosine_tab) {
338 WORD32 temp_result;
339
340 if (a < 0) {
341 a = -a;
342 }
343
344 a = a % TWO_PI_IN_Q15;
345
346 temp_result = cosine_tab[((a * TRIG_TABLE_CONV_FAC) >> 15)];
347 return temp_result;
348 }
349
ixheaacd_mps_sin(WORD32 a,const WORD32 * sine_tab)350 static PLATFORM_INLINE WORD32 ixheaacd_mps_sin(WORD32 a, const WORD32 *sine_tab) {
351 WORD32 temp_result, flag = 0;
352
353 if (a < 0) {
354 a = -a;
355 flag = 1;
356 }
357
358 a = a % TWO_PI_IN_Q15;
359
360 temp_result = sine_tab[((a * TRIG_TABLE_CONV_FAC) >> 15)];
361 if (flag) temp_result = -temp_result;
362
363 return temp_result;
364 }
365
ixheaacd_mps_comp(WORD32 a,WORD32 b,WORD16 * q_a,WORD16 q_b)366 static PLATFORM_INLINE WORD32 ixheaacd_mps_comp(WORD32 a, WORD32 b, WORD16 *q_a, WORD16 q_b) {
367 if (a == 0 || b == 0) {
368 if (a == 0) {
369 if (b < 0)
370 return 1;
371 else
372 return 0;
373 } else if (b == 0) {
374 if (a > 0)
375 return 1;
376 else
377 return 0;
378 }
379 }
380
381 if (*q_a > q_b) {
382 a = (a >> ((*q_a) - q_b));
383 } else {
384 b = (b >> (q_b - (*q_a)));
385 }
386
387 if (a > b)
388 return 1;
389 else
390 return 0;
391 }
392
393 #endif /* IXHEAACD_MPS_BASIC_OP_H */
394