/src/libxaac/encoder/iusace_lpc.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
21 | | #include <math.h> |
22 | | #include "ixheaac_type_def.h" |
23 | | #include "iusace_bitbuffer.h" |
24 | | #include "iusace_cnst.h" |
25 | | #include "iusace_tns_usac.h" |
26 | | #include "iusace_psy_mod.h" |
27 | | #include "iusace_block_switch_const.h" |
28 | | #include "iusace_rom.h" |
29 | | |
30 | 156M | static FLOAT32 iusace_lpc_eval_chebyshev_polyn(FLOAT32 x, FLOAT32 *coefs, WORD32 order) { |
31 | 156M | WORD32 i; |
32 | 156M | FLOAT32 b0, b1, b2, x2; |
33 | 156M | x2 = 2.0f * x; |
34 | 156M | b2 = 1.0f; |
35 | 156M | b1 = x2 + coefs[1]; |
36 | 1.09G | for (i = 2; i < order; i++) { |
37 | 937M | b0 = x2 * b1 - b2 + coefs[i]; |
38 | 937M | b2 = b1; |
39 | 937M | b1 = b0; |
40 | 937M | } |
41 | 156M | return (x * b1 - b2 + 0.5f * coefs[order]); |
42 | 156M | } |
43 | | |
44 | 811k | VOID iusace_lpc_2_lsp_conversion(FLOAT32 *lpc, FLOAT32 *lsp, FLOAT32 *prev_lsp) { |
45 | 811k | FLOAT32 sum_polyn[(ORDER_BY_2) + 1], diff_polyn[(ORDER_BY_2) + 1]; |
46 | 811k | FLOAT32 *p1_lpc, *p2_lpc, *p_sum_polyn, *p_diff_polyn; |
47 | 811k | WORD32 i, j = 0, num_found_freeq = 0, is_first_polyn = 0; |
48 | 811k | FLOAT32 x_low, y_low, x_high, y_high, x_mid, y_mid, x_lin_interp; |
49 | | |
50 | 811k | p_sum_polyn = sum_polyn; |
51 | 811k | p_diff_polyn = diff_polyn; |
52 | 811k | *p_sum_polyn++ = 1.0f; |
53 | 811k | *p_diff_polyn++ = 1.0f; |
54 | 811k | sum_polyn[0] = 1.0f; |
55 | 811k | diff_polyn[0] = 1.0f; |
56 | 811k | p1_lpc = lpc + 1; |
57 | 811k | p2_lpc = lpc + ORDER; |
58 | 7.29M | for (i = 0; i <= ORDER_BY_2 - 1; i++) { |
59 | 6.48M | *p_sum_polyn = *p1_lpc + *p2_lpc - *(p_sum_polyn - 1); |
60 | 6.48M | p_sum_polyn++; |
61 | 6.48M | *p_diff_polyn = *p1_lpc++ - *p2_lpc-- + *(p_diff_polyn - 1); |
62 | 6.48M | p_diff_polyn++; |
63 | 6.48M | } |
64 | 811k | p_sum_polyn = sum_polyn; |
65 | 811k | x_low = iusace_chebyshev_polyn_grid[0]; |
66 | 811k | y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2); |
67 | | |
68 | 91.4M | while ((num_found_freeq < ORDER) && (j < CHEBYSHEV_NUM_POINTS)) { |
69 | 90.6M | j++; |
70 | 90.6M | x_high = x_low; |
71 | 90.6M | y_high = y_low; |
72 | 90.6M | x_low = iusace_chebyshev_polyn_grid[j]; |
73 | 90.6M | y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2); |
74 | | |
75 | 90.6M | if (y_low * y_high <= 0.0) /* if sign change new root exists */ |
76 | 12.9M | { |
77 | 12.9M | j--; |
78 | 64.8M | for (i = 0; i < CHEBYSHEV_NUM_ITER; i++) { |
79 | 51.9M | x_mid = 0.5f * (x_low + x_high); |
80 | 51.9M | y_mid = iusace_lpc_eval_chebyshev_polyn(x_mid, p_sum_polyn, ORDER_BY_2); |
81 | 51.9M | if (y_low * y_mid <= 0.0) { |
82 | 26.4M | y_high = y_mid; |
83 | 26.4M | x_high = x_mid; |
84 | 26.4M | } else { |
85 | 25.4M | y_low = y_mid; |
86 | 25.4M | x_low = x_mid; |
87 | 25.4M | } |
88 | 51.9M | } |
89 | | |
90 | | /* linear interpolation for evaluating the root */ |
91 | 12.9M | x_lin_interp = x_low - y_low * (x_high - x_low) / (y_high - y_low); |
92 | | |
93 | 12.9M | lsp[num_found_freeq] = x_lin_interp; |
94 | 12.9M | num_found_freeq++; |
95 | | |
96 | 12.9M | is_first_polyn = 1 - is_first_polyn; |
97 | 12.9M | p_sum_polyn = is_first_polyn ? diff_polyn : sum_polyn; |
98 | | |
99 | 12.9M | x_low = x_lin_interp; |
100 | 12.9M | y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2); |
101 | 12.9M | } |
102 | 90.6M | } |
103 | | |
104 | | /* Check if ORDER roots found */ |
105 | | /* if not use the LSPs from previous frame */ |
106 | 811k | if (num_found_freeq < ORDER) { |
107 | 0 | for (i = 0; i < ORDER; i++) lsp[i] = prev_lsp[i]; |
108 | 0 | } |
109 | 811k | } |
110 | | |
111 | 11.0M | static VOID iusace_compute_coeff_poly_f(FLOAT32 *lsp, FLOAT32 *poly1, FLOAT32 *poly2) { |
112 | 11.0M | FLOAT32 b1, b2; |
113 | 11.0M | FLOAT32 *ptr_lsp; |
114 | 11.0M | WORD32 i, j; |
115 | | |
116 | 11.0M | ptr_lsp = lsp; |
117 | 11.0M | poly1[0] = poly2[0] = 1.0f; |
118 | | |
119 | 99.6M | for (i = 1; i <= ORDER_BY_2; i++) { |
120 | 88.6M | b1 = -2.0f * (*ptr_lsp++); |
121 | 88.6M | b2 = -2.0f * (*ptr_lsp++); |
122 | 88.6M | poly1[i] = (b1 * poly1[i - 1]) + (2.0f * poly1[i - 2]); |
123 | 88.6M | poly2[i] = (b2 * poly2[i - 1]) + (2.0f * poly2[i - 2]); |
124 | 398M | for (j = i - 1; j > 0; j--) { |
125 | 310M | poly1[j] += (b1 * poly1[j - 1]) + poly1[j - 2]; |
126 | 310M | poly2[j] += (b2 * poly2[j - 1]) + poly2[j - 2]; |
127 | 310M | } |
128 | 88.6M | } |
129 | 11.0M | } |
130 | | |
131 | 11.0M | VOID iusace_lsp_to_lp_conversion(FLOAT32 *lsp, FLOAT32 *lp_flt_coff_a) { |
132 | 11.0M | WORD32 i; |
133 | 11.0M | FLOAT32 *ppoly_f1, *ppoly_f2; |
134 | 11.0M | FLOAT32 *plp_flt_coff_a_bott, *plp_flt_coff_a_top; |
135 | 11.0M | FLOAT32 poly1[ORDER_BY_2 + 2], poly2[ORDER_BY_2 + 2]; |
136 | | |
137 | 11.0M | poly1[0] = 0.0f; |
138 | 11.0M | poly2[0] = 0.0f; |
139 | | |
140 | 11.0M | iusace_compute_coeff_poly_f(lsp, &poly1[1], &poly2[1]); |
141 | | |
142 | 11.0M | ppoly_f1 = poly1 + ORDER_BY_2 + 1; |
143 | 11.0M | ppoly_f2 = poly2 + ORDER_BY_2 + 1; |
144 | | |
145 | 99.6M | for (i = 0; i < ORDER_BY_2; i++) { |
146 | 88.6M | ppoly_f1[0] += ppoly_f1[-1]; |
147 | 88.6M | ppoly_f2[0] -= ppoly_f2[-1]; |
148 | 88.6M | ppoly_f1--; |
149 | 88.6M | ppoly_f2--; |
150 | 88.6M | } |
151 | | |
152 | 11.0M | plp_flt_coff_a_bott = lp_flt_coff_a; |
153 | 11.0M | *plp_flt_coff_a_bott++ = 1.0f; |
154 | 11.0M | plp_flt_coff_a_top = lp_flt_coff_a + ORDER; |
155 | 11.0M | ppoly_f1 = poly1 + 2; |
156 | 11.0M | ppoly_f2 = poly2 + 2; |
157 | 99.6M | for (i = 0; i < ORDER_BY_2; i++) { |
158 | 88.6M | *plp_flt_coff_a_bott++ = 0.5f * (*ppoly_f1 + *ppoly_f2); |
159 | 88.6M | *plp_flt_coff_a_top-- = 0.5f * (*ppoly_f1++ - *ppoly_f2++); |
160 | 88.6M | } |
161 | 11.0M | } |
162 | | |
163 | 811k | VOID iusace_levinson_durbin_algo(FLOAT32 *auto_corr_input, FLOAT32 *lpc) { |
164 | 811k | WORD32 i, j; |
165 | 811k | FLOAT32 lpc_val, sum, sigma; |
166 | 811k | FLOAT32 reflection_coeffs[LEV_DUR_MAX_ORDER]; |
167 | | |
168 | 811k | lpc[0] = 1.0f; |
169 | | |
170 | 811k | reflection_coeffs[0] = -auto_corr_input[1] / auto_corr_input[0]; |
171 | 811k | lpc[1] = reflection_coeffs[0]; |
172 | 811k | sigma = auto_corr_input[0] + auto_corr_input[1] * reflection_coeffs[0]; |
173 | | |
174 | 12.9M | for (i = 2; i <= ORDER; i++) { |
175 | 12.1M | sum = 0.0f; |
176 | 121M | for (j = 0; j < i; j++) sum += auto_corr_input[i - j] * lpc[j]; |
177 | 12.1M | reflection_coeffs[i - 1] = -sum / sigma; |
178 | | |
179 | 12.1M | sigma = sigma * (1.0f - reflection_coeffs[i - 1] * reflection_coeffs[i - 1]); |
180 | | |
181 | 12.1M | if (sigma <= 1.0E-09f) { |
182 | 0 | for (j = i; j <= ORDER; j++) { |
183 | 0 | reflection_coeffs[j - 1] = 0.0f; |
184 | 0 | lpc[j] = 0.0f; |
185 | 0 | } |
186 | 0 | break; |
187 | 0 | } |
188 | | |
189 | 64.0M | for (j = 1; j <= (i / 2); j++) { |
190 | 51.9M | lpc_val = lpc[j] + reflection_coeffs[i - 1] * lpc[i - j]; |
191 | 51.9M | lpc[i - j] += reflection_coeffs[i - 1] * lpc[j]; |
192 | 51.9M | lpc[j] = lpc_val; |
193 | 51.9M | } |
194 | | |
195 | 12.1M | lpc[i] = reflection_coeffs[i - 1]; |
196 | 12.1M | } |
197 | 811k | } |
198 | | |
199 | 42.9M | VOID iusace_get_weighted_lpc(FLOAT32 *lpc, FLOAT32 *weighted_lpc) { |
200 | 42.9M | WORD32 i; |
201 | 773M | for (i = 0; i <= ORDER; i++) { |
202 | 730M | weighted_lpc[i] = iusace_gamma_table[i] * lpc[i]; |
203 | 730M | } |
204 | 42.9M | } |
205 | | |
206 | 1.00M | VOID iusace_lsp_2_lsf_conversion(FLOAT32 *lsp, FLOAT32 *lsf) { |
207 | 1.00M | WORD32 i; |
208 | 17.1M | for (i = 0; i < ORDER; i++) { |
209 | 16.1M | lsf[i] = (FLOAT32)(acos(lsp[i]) * LSP_2_LSF_SCALE); |
210 | 16.1M | } |
211 | 1.00M | } |
212 | | |
213 | 811k | VOID iusace_lsf_2_lsp_conversion(FLOAT32 *lsf, FLOAT32 *lsp) { |
214 | 811k | WORD32 i; |
215 | 13.7M | for (i = 0; i < ORDER; i++) lsp[i] = (FLOAT32)cos((FLOAT64)lsf[i] * (FLOAT64)PI_BY_6400); |
216 | 811k | } |