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 <stdlib.h>
23 #include "ixheaac_type_def.h"
24 #include "iusace_avq_enc.h"
25
iusace_gosset_compute_rank_and_sign(WORD32 * x,WORD32 * rank,WORD32 * sign_code)26 static VOID iusace_gosset_compute_rank_and_sign(WORD32 *x, WORD32 *rank, WORD32 *sign_code) {
27 WORD32 xs[8], a[8], q, d[8], w[8], A, B, idx, tmp, abs_i, abs_j;
28 WORD32 i, j, k;
29 for (i = 0; i < 8; i++) {
30 xs[i] = x[i];
31 }
32 for (k = 0; k < 7; k++) {
33 j = k;
34 for (i = k + 1; i < 8; i++) {
35 abs_j = abs(xs[j]);
36 abs_i = abs(xs[i]);
37 if (abs_i >= abs_j) {
38 if (abs_i > xs[j]) {
39 j = i;
40 }
41 }
42 }
43 if (j > k) {
44 tmp = xs[k];
45 xs[k] = xs[j];
46 xs[j] = tmp;
47 }
48 }
49 *sign_code = 0;
50 for (i = 0; i < 8; i++) {
51 if (xs[i] < 0) {
52 *sign_code += iusace_pow2_table[i];
53 }
54 }
55 a[0] = xs[0];
56 q = 1;
57 for (i = 1; i < 8; i++) {
58 if (xs[i] != xs[i - 1]) {
59 a[q] = xs[i];
60 q++;
61 }
62 }
63 for (i = 0; i < 8; i++) {
64 for (j = 0; j < q; j++) {
65 if (x[i] == a[j]) {
66 d[i] = j;
67 break;
68 }
69 }
70 }
71 *rank = 0;
72 for (j = 0; j < q; j++) {
73 w[j] = 0;
74 }
75 B = 1;
76 for (i = 7; i >= 0; i--) {
77 idx = d[i];
78 w[idx]++;
79 B *= w[idx];
80 A = 0;
81 for (j = 0; j < idx; j++) {
82 A += w[j];
83 }
84 if (A > 0) {
85 *rank += A * iusace_factorial_table[i] / B;
86 }
87 }
88 }
89
iusace_gosset_compute_base_idx(WORD32 * x,WORD32 ka,WORD32 * idx)90 static VOID iusace_gosset_compute_base_idx(WORD32 *x, WORD32 ka, WORD32 *idx) {
91 WORD32 rank, offset, code, i, ks;
92 iusace_gosset_compute_rank_and_sign(x, &rank, &code);
93 ks = -1;
94 for (i = iusace_iso_code_index_table[ka]; i < LEN_SIGN_LEADER; i++) {
95 if (code == iusace_iso_code_data_table[i]) {
96 ks = i;
97 break;
98 }
99 }
100 if (ks == -1) {
101 ks = 0;
102 }
103 offset = iusace_signed_leader_is[ks];
104 *idx = offset + rank;
105 return;
106 }
107
iusace_find_absolute_leader(WORD32 * y)108 static WORD32 iusace_find_absolute_leader(WORD32 *y) {
109 WORD32 i, nb, pos, ka;
110 WORD64 s, C[8], id;
111 for (i = 0; i < 8; i++) {
112 C[i] = (WORD64)y[i] * y[i];
113 }
114 s = 0;
115 for (i = 0; i < 8; i++) {
116 s += C[i];
117 }
118 s >>= 3;
119 ka = LEN_ABS_LEADER + 1;
120 if (s == 0) {
121 ka = LEN_ABS_LEADER;
122 } else {
123 if (s <= NB_SPHERE) {
124 id = 0;
125 for (i = 0; i < 8; i++) {
126 id += C[i] * C[i];
127 }
128 id = id >> 3;
129 nb = iusace_da_num_bits[s - 1];
130 pos = iusace_da_pos[s - 1];
131 for (i = 0; i < nb; i++) {
132 if (id == (long)iusace_da_id[pos]) {
133 ka = pos;
134 break;
135 }
136 pos++;
137 }
138 }
139 }
140 return (ka);
141 }
142
iusace_nearest_neighbor_2d(FLOAT32 * x,WORD32 * y)143 static VOID iusace_nearest_neighbor_2d(FLOAT32 *x, WORD32 *y) {
144 WORD32 i, j;
145 WORD64 sum;
146 FLOAT32 diff[8], em;
147 sum = 0;
148 for (i = 0; i < 8; i++) {
149 if (x[i] < 0) {
150 y[i] = -2 * (((WORD32)(1.0 - x[i])) >> 1);
151 } else {
152 y[i] = 2 * (((WORD32)(1.0 + x[i])) >> 1);
153 }
154 sum += y[i];
155 }
156 if (sum % 4) {
157 FLOAT32 s;
158 em = 0;
159 j = 0;
160 for (i = 0; i < 8; i++) {
161 diff[i] = x[i] - y[i];
162 s = (FLOAT32)fabs(diff[i]);
163 if (em < s) {
164 em = s;
165 j = i;
166 }
167 }
168 if (diff[j] < 0) {
169 y[j] -= 2;
170 } else {
171 y[j] += 2;
172 }
173 }
174 return;
175 }
176
iusace_find_nearest_neighbor(FLOAT32 * bk,WORD32 * ck)177 VOID iusace_find_nearest_neighbor(FLOAT32 *bk, WORD32 *ck) {
178 WORD32 i, y1[8], y2[8];
179 FLOAT32 e1k, e2k, x1[8], tmp;
180
181 iusace_nearest_neighbor_2d(bk, y1);
182
183 for (i = 0; i < 8; i++) {
184 x1[i] = bk[i] - 1.0f;
185 }
186 iusace_nearest_neighbor_2d(x1, y2);
187 for (i = 0; i < 8; i++) {
188 y2[i] += 1;
189 }
190 /* Compute e1k = (Bk - y1k)^2 and e2k = (Bk � y2k)^2 */
191 e1k = e2k = 0.0;
192 for (i = 0; i < 8; i++) {
193 tmp = bk[i] - y1[i];
194 e1k += tmp * tmp;
195 tmp = bk[i] - y2[i];
196 e2k += tmp * tmp;
197 }
198
199 /* Select best lattice point */
200 if (e1k < e2k) {
201 for (i = 0; i < 8; i++) {
202 ck[i] = y1[i];
203 }
204 } else {
205 for (i = 0; i < 8; i++) {
206 ck[i] = y2[i];
207 }
208 }
209 return;
210 }
211
iusace_vononoi_idx(WORD32 * kv,WORD32 m,WORD32 * y)212 static VOID iusace_vononoi_idx(WORD32 *kv, WORD32 m, WORD32 *y) {
213 WORD32 i, v[8], tmp, sum, *ptr1, *ptr2;
214 FLOAT32 z[8];
215 for (i = 0; i < 8; i++) {
216 y[i] = kv[7];
217 }
218 z[7] = (FLOAT32)y[7] / m;
219 sum = 0;
220 for (i = 6; i >= 1; i--) {
221 tmp = kv[i] << 1;
222 sum += tmp;
223 y[i] += tmp;
224 z[i] = (FLOAT32)y[i] / m;
225 }
226 y[0] += (4 * kv[0] + sum);
227 z[0] = (FLOAT32)(y[0] - 2) / m;
228 iusace_find_nearest_neighbor(z, v);
229 ptr1 = y;
230 ptr2 = v;
231 for (i = 0; i < 8; i++) {
232 *ptr1++ -= m * *ptr2++;
233 }
234 }
235
iusace_compute_coord(WORD32 * y,WORD32 * k)236 static VOID iusace_compute_coord(WORD32 *y, WORD32 *k) {
237 WORD32 i, tmp, sum;
238 k[7] = y[7];
239 tmp = y[7];
240 sum = 5 * y[7];
241 for (i = 6; i >= 1; i--) {
242 k[i] = (y[i] - tmp) >> 1;
243 sum -= y[i];
244 }
245 k[0] = (y[0] + sum) >> 2;
246 }
247
iusace_apply_voronoi_ext(WORD32 * x,WORD32 * n,WORD32 * idx,WORD32 * k)248 VOID iusace_apply_voronoi_ext(WORD32 *x, WORD32 *n, WORD32 *idx, WORD32 *k) {
249 WORD32 ka, c[8];
250 WORD32 i, r, m, v[8], c_tmp[8], k_mod[8], k_tmp[8], iter, ka_tmp, n_tmp, mask;
251 FLOAT32 sphere;
252 ka = iusace_find_absolute_leader(x);
253 *n = iusace_da_nq[ka];
254 if (*n <= 4) {
255 for (i = 0; i < 8; i++) {
256 c[i] = x[i];
257 }
258 } else {
259 sphere = 0.0;
260 for (i = 0; i < 8; i++) {
261 sphere += (FLOAT32)x[i] * (FLOAT32)x[i];
262 }
263 sphere *= 0.125;
264 r = 1;
265 sphere *= 0.25;
266 while (sphere > 11.0) {
267 r++;
268 sphere *= 0.25;
269 }
270 iusace_compute_coord(x, k_mod);
271 m = 1 << r;
272 mask = m - 1;
273 for (iter = 0; iter < 2; iter++) {
274 for (i = 0; i < 8; i++) {
275 k_tmp[i] = k_mod[i] & mask;
276 }
277 iusace_vononoi_idx(k_tmp, m, v);
278 for (i = 0; i < 8; i++) {
279 c_tmp[i] = (x[i] - v[i]) / m;
280 }
281 ka_tmp = iusace_find_absolute_leader(c_tmp);
282 n_tmp = iusace_da_nq[ka_tmp];
283 if (n_tmp > 4) {
284 r++;
285 m = m << 1;
286 mask = ((mask << 1) + 1);
287 } else {
288 if (n_tmp < 3) {
289 n_tmp = 3;
290 }
291 ka = ka_tmp;
292 *n = n_tmp + 2 * r;
293 for (i = 0; i < 8; i++) {
294 k[i] = k_tmp[i];
295 }
296 for (i = 0; i < 8; i++) {
297 c[i] = c_tmp[i];
298 }
299 r--;
300 m = m >> 1;
301 mask = mask >> 1;
302 }
303 }
304 }
305
306 if (*n > 0) {
307 iusace_gosset_compute_base_idx(c, ka, idx);
308 }
309 return;
310 }
311
iusace_alg_vec_quant(FLOAT32 * ptr_input,WORD32 * ptr_out,WORD32 * ptr_lpc_idx)312 VOID iusace_alg_vec_quant(FLOAT32 *ptr_input, WORD32 *ptr_out, WORD32 *ptr_lpc_idx) {
313 WORD32 i, l, nq, pos, c[8], kv[8];
314 FLOAT32 x1[8];
315 WORD32 lpc_index;
316
317 pos = 2;
318 for (l = 0; l < 2; l++) {
319 for (i = 0; i < 8; i++) {
320 x1[i] = ptr_input[l * 8 + i];
321 kv[i] = 0;
322 }
323
324 iusace_find_nearest_neighbor(x1, c);
325
326 iusace_apply_voronoi_ext(c, &nq, &lpc_index, kv);
327
328 for (i = 0; i < 8; i++) {
329 ptr_out[l * 8 + i] = c[i];
330 }
331
332 ptr_lpc_idx[l] = nq;
333
334 if (nq > 0) {
335 ptr_lpc_idx[pos++] = lpc_index;
336 for (i = 0; i < 8; i++) {
337 ptr_lpc_idx[pos++] = kv[i];
338 }
339 }
340 }
341
342 return;
343 }
344