/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 | 138M | static FLOAT32 iusace_lpc_eval_chebyshev_polyn(FLOAT32 x, FLOAT32 *coefs, WORD32 order) { |
31 | 138M | WORD32 i; |
32 | 138M | FLOAT32 b0, b1, b2, x2; |
33 | 138M | x2 = 2.0f * x; |
34 | 138M | b2 = 1.0f; |
35 | 138M | b1 = x2 + coefs[1]; |
36 | 968M | for (i = 2; i < order; i++) { |
37 | 830M | b0 = x2 * b1 - b2 + coefs[i]; |
38 | 830M | b2 = b1; |
39 | 830M | b1 = b0; |
40 | 830M | } |
41 | 138M | return (x * b1 - b2 + 0.5f * coefs[order]); |
42 | 138M | } |
43 | | |
44 | 722k | VOID iusace_lpc_2_lsp_conversion(FLOAT32 *lpc, FLOAT32 *lsp, FLOAT32 *prev_lsp) { |
45 | 722k | FLOAT32 sum_polyn[(ORDER_BY_2) + 1], diff_polyn[(ORDER_BY_2) + 1]; |
46 | 722k | FLOAT32 *p1_lpc, *p2_lpc, *p_sum_polyn, *p_diff_polyn; |
47 | 722k | WORD32 i, j = 0, num_found_freeq = 0, is_first_polyn = 0; |
48 | 722k | FLOAT32 x_low, y_low, x_high, y_high, x_mid, y_mid, x_lin_interp; |
49 | | |
50 | 722k | p_sum_polyn = sum_polyn; |
51 | 722k | p_diff_polyn = diff_polyn; |
52 | 722k | *p_sum_polyn++ = 1.0f; |
53 | 722k | *p_diff_polyn++ = 1.0f; |
54 | 722k | sum_polyn[0] = 1.0f; |
55 | 722k | diff_polyn[0] = 1.0f; |
56 | 722k | p1_lpc = lpc + 1; |
57 | 722k | p2_lpc = lpc + ORDER; |
58 | 6.50M | for (i = 0; i <= ORDER_BY_2 - 1; i++) { |
59 | 5.78M | *p_sum_polyn = *p1_lpc + *p2_lpc - *(p_sum_polyn - 1); |
60 | 5.78M | p_sum_polyn++; |
61 | 5.78M | *p_diff_polyn = *p1_lpc++ - *p2_lpc-- + *(p_diff_polyn - 1); |
62 | 5.78M | p_diff_polyn++; |
63 | 5.78M | } |
64 | 722k | p_sum_polyn = sum_polyn; |
65 | 722k | x_low = iusace_chebyshev_polyn_grid[0]; |
66 | 722k | y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2); |
67 | | |
68 | 80.5M | while ((num_found_freeq < ORDER) && (j < CHEBYSHEV_NUM_POINTS)) { |
69 | 79.8M | j++; |
70 | 79.8M | x_high = x_low; |
71 | 79.8M | y_high = y_low; |
72 | 79.8M | x_low = iusace_chebyshev_polyn_grid[j]; |
73 | 79.8M | y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2); |
74 | | |
75 | 79.8M | if (y_low * y_high <= 0.0) /* if sign change new root exists */ |
76 | 11.5M | { |
77 | 11.5M | j--; |
78 | 57.8M | for (i = 0; i < CHEBYSHEV_NUM_ITER; i++) { |
79 | 46.2M | x_mid = 0.5f * (x_low + x_high); |
80 | 46.2M | y_mid = iusace_lpc_eval_chebyshev_polyn(x_mid, p_sum_polyn, ORDER_BY_2); |
81 | 46.2M | if (y_low * y_mid <= 0.0) { |
82 | 23.2M | y_high = y_mid; |
83 | 23.2M | x_high = x_mid; |
84 | 23.2M | } else { |
85 | 23.0M | y_low = y_mid; |
86 | 23.0M | x_low = x_mid; |
87 | 23.0M | } |
88 | 46.2M | } |
89 | | |
90 | | /* linear interpolation for evaluating the root */ |
91 | 11.5M | x_lin_interp = x_low - y_low * (x_high - x_low) / (y_high - y_low); |
92 | | |
93 | 11.5M | lsp[num_found_freeq] = x_lin_interp; |
94 | 11.5M | num_found_freeq++; |
95 | | |
96 | 11.5M | is_first_polyn = 1 - is_first_polyn; |
97 | 11.5M | p_sum_polyn = is_first_polyn ? diff_polyn : sum_polyn; |
98 | | |
99 | 11.5M | x_low = x_lin_interp; |
100 | 11.5M | y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2); |
101 | 11.5M | } |
102 | 79.8M | } |
103 | | |
104 | | /* Check if ORDER roots found */ |
105 | | /* if not use the LSPs from previous frame */ |
106 | 722k | if (num_found_freeq < ORDER) { |
107 | 0 | for (i = 0; i < ORDER; i++) lsp[i] = prev_lsp[i]; |
108 | 0 | } |
109 | 722k | } |
110 | | |
111 | 9.87M | static VOID iusace_compute_coeff_poly_f(FLOAT32 *lsp, FLOAT32 *poly1, FLOAT32 *poly2) { |
112 | 9.87M | FLOAT32 b1, b2; |
113 | 9.87M | FLOAT32 *ptr_lsp; |
114 | 9.87M | WORD32 i, j; |
115 | | |
116 | 9.87M | ptr_lsp = lsp; |
117 | 9.87M | poly1[0] = poly2[0] = 1.0f; |
118 | | |
119 | 88.8M | for (i = 1; i <= ORDER_BY_2; i++) { |
120 | 78.9M | b1 = -2.0f * (*ptr_lsp++); |
121 | 78.9M | b2 = -2.0f * (*ptr_lsp++); |
122 | 78.9M | poly1[i] = (b1 * poly1[i - 1]) + (2.0f * poly1[i - 2]); |
123 | 78.9M | poly2[i] = (b2 * poly2[i - 1]) + (2.0f * poly2[i - 2]); |
124 | 355M | for (j = i - 1; j > 0; j--) { |
125 | 276M | poly1[j] += (b1 * poly1[j - 1]) + poly1[j - 2]; |
126 | 276M | poly2[j] += (b2 * poly2[j - 1]) + poly2[j - 2]; |
127 | 276M | } |
128 | 78.9M | } |
129 | 9.87M | } |
130 | | |
131 | 9.87M | VOID iusace_lsp_to_lp_conversion(FLOAT32 *lsp, FLOAT32 *lp_flt_coff_a) { |
132 | 9.87M | WORD32 i; |
133 | 9.87M | FLOAT32 *ppoly_f1, *ppoly_f2; |
134 | 9.87M | FLOAT32 *plp_flt_coff_a_bott, *plp_flt_coff_a_top; |
135 | 9.87M | FLOAT32 poly1[ORDER_BY_2 + 2], poly2[ORDER_BY_2 + 2]; |
136 | | |
137 | 9.87M | poly1[0] = 0.0f; |
138 | 9.87M | poly2[0] = 0.0f; |
139 | | |
140 | 9.87M | iusace_compute_coeff_poly_f(lsp, &poly1[1], &poly2[1]); |
141 | | |
142 | 9.87M | ppoly_f1 = poly1 + ORDER_BY_2 + 1; |
143 | 9.87M | ppoly_f2 = poly2 + ORDER_BY_2 + 1; |
144 | | |
145 | 88.8M | for (i = 0; i < ORDER_BY_2; i++) { |
146 | 78.9M | ppoly_f1[0] += ppoly_f1[-1]; |
147 | 78.9M | ppoly_f2[0] -= ppoly_f2[-1]; |
148 | 78.9M | ppoly_f1--; |
149 | 78.9M | ppoly_f2--; |
150 | 78.9M | } |
151 | | |
152 | 9.87M | plp_flt_coff_a_bott = lp_flt_coff_a; |
153 | 9.87M | *plp_flt_coff_a_bott++ = 1.0f; |
154 | 9.87M | plp_flt_coff_a_top = lp_flt_coff_a + ORDER; |
155 | 9.87M | ppoly_f1 = poly1 + 2; |
156 | 9.87M | ppoly_f2 = poly2 + 2; |
157 | 88.8M | for (i = 0; i < ORDER_BY_2; i++) { |
158 | 78.9M | *plp_flt_coff_a_bott++ = 0.5f * (*ppoly_f1 + *ppoly_f2); |
159 | 78.9M | *plp_flt_coff_a_top-- = 0.5f * (*ppoly_f1++ - *ppoly_f2++); |
160 | 78.9M | } |
161 | 9.87M | } |
162 | | |
163 | 722k | VOID iusace_levinson_durbin_algo(FLOAT32 *auto_corr_input, FLOAT32 *lpc) { |
164 | 722k | WORD32 i, j; |
165 | 722k | FLOAT32 lpc_val, sum, sigma; |
166 | 722k | FLOAT32 reflection_coeffs[LEV_DUR_MAX_ORDER]; |
167 | | |
168 | 722k | lpc[0] = 1.0f; |
169 | | |
170 | 722k | reflection_coeffs[0] = -auto_corr_input[1] / auto_corr_input[0]; |
171 | 722k | lpc[1] = reflection_coeffs[0]; |
172 | 722k | sigma = auto_corr_input[0] + auto_corr_input[1] * reflection_coeffs[0]; |
173 | | |
174 | 11.5M | for (i = 2; i <= ORDER; i++) { |
175 | 10.8M | sum = 0.0f; |
176 | 108M | for (j = 0; j < i; j++) sum += auto_corr_input[i - j] * lpc[j]; |
177 | 10.8M | reflection_coeffs[i - 1] = -sum / sigma; |
178 | | |
179 | 10.8M | sigma = sigma * (1.0f - reflection_coeffs[i - 1] * reflection_coeffs[i - 1]); |
180 | | |
181 | 10.8M | 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 | 57.0M | for (j = 1; j <= (i / 2); j++) { |
190 | 46.2M | lpc_val = lpc[j] + reflection_coeffs[i - 1] * lpc[i - j]; |
191 | 46.2M | lpc[i - j] += reflection_coeffs[i - 1] * lpc[j]; |
192 | 46.2M | lpc[j] = lpc_val; |
193 | 46.2M | } |
194 | | |
195 | 10.8M | lpc[i] = reflection_coeffs[i - 1]; |
196 | 10.8M | } |
197 | 722k | } |
198 | | |
199 | 37.6M | VOID iusace_get_weighted_lpc(FLOAT32 *lpc, FLOAT32 *weighted_lpc) { |
200 | 37.6M | WORD32 i; |
201 | 677M | for (i = 0; i <= ORDER; i++) { |
202 | 639M | weighted_lpc[i] = iusace_gamma_table[i] * lpc[i]; |
203 | 639M | } |
204 | 37.6M | } |
205 | | |
206 | 897k | VOID iusace_lsp_2_lsf_conversion(FLOAT32 *lsp, FLOAT32 *lsf) { |
207 | 897k | WORD32 i; |
208 | 15.2M | for (i = 0; i < ORDER; i++) { |
209 | 14.3M | lsf[i] = (FLOAT32)(acos(lsp[i]) * LSP_2_LSF_SCALE); |
210 | 14.3M | } |
211 | 897k | } |
212 | | |
213 | 722k | VOID iusace_lsf_2_lsp_conversion(FLOAT32 *lsf, FLOAT32 *lsp) { |
214 | 722k | WORD32 i; |
215 | 12.2M | for (i = 0; i < ORDER; i++) lsp[i] = (FLOAT32)cos((FLOAT64)lsf[i] * (FLOAT64)PI_BY_6400); |
216 | 722k | } |