/****************************************************************************** * * * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ #include <stdio.h> #include <stdlib.h> #include <float.h> #include <math.h> #include <assert.h> #include <string.h> #include <ixheaacd_type_def.h> #include "ixheaacd_constants.h" #include <ixheaacd_basic_ops32.h> #include <ixheaacd_basic_ops40.h> #include "ixheaacd_acelp_com.h" extern const WORD32 ixheaacd_factorial_7[8]; extern const WORD32 ixheaacd_iso_code_index_table[LEN_ABS_LEADER]; extern const UWORD8 ixheaacd_iso_code_data_table[LEN_SIGN_LEADER]; extern const UWORD32 ixheaacd_signed_leader_is[LEN_SIGN_LEADER]; extern const WORD32 ixheaacd_iso_code_num_table[], ixheaacd_pos_abs_leaders_a3[], ixheaacd_pos_abs_leaders_a4[]; extern const UWORD8 ixheaacd_absolute_leader_tab_da[][8]; extern const UWORD32 ixheaacd_cardinality_offset_table_i3[], ixheaacd_cardinality_offset_tab_i4[]; static VOID ixheaacd_nearest_neighbor_2d(WORD32 x[], WORD32 y[], WORD32 count, WORD32 *rem) { WORD32 i, j, sum; WORD32 s, e[8], em; WORD32 rem_temp[8]; memcpy(rem_temp, rem, 8 * sizeof(WORD32)); sum = 0; for (i = 0; i < 8; i++) { if (x[i] < 0) { y[i] = -2 * (((WORD32)(1 - x[i])) >> 1); } else { y[i] = 2 * (((WORD32)(1 + x[i])) >> 1); } sum += y[i]; if (x[i] % 2 != 0) { if (x[i] < 0) { rem_temp[i] = ixheaacd_negate32_sat( ixheaacd_sub32_sat(rem_temp[i], (1 << count))); } else { rem_temp[i] = ixheaacd_sub32_sat(rem_temp[i], (1 << count)); } } } if (sum % 4) { em = 0; j = 0; for (i = 0; i < 8; i++) { e[i] = rem_temp[i]; } for (i = 0; i < 8; i++) { if (e[i] < 0) { s = -e[i]; } else { s = e[i]; } if (em < s) { em = s; j = i; } } if (e[j] < 0) { y[j] -= 2; rem_temp[j] = ixheaacd_add32_sat(rem_temp[j], (2 << count)); } else { y[j] += 2; rem_temp[j] = ixheaacd_sub32_sat(rem_temp[j], (2 << count)); } } memcpy(rem, rem_temp, 8 * sizeof(WORD32)); return; } VOID ixheaacd_voronoi_search(WORD32 x[], WORD32 y[], WORD32 count, WORD32 *rem1, WORD32 *rem2) { WORD32 i, y0[8], y1[8]; WORD32 x1[8], tmp; WORD32 e0, e1; ixheaacd_nearest_neighbor_2d(x, y0, count, rem1); for (i = 0; i < 8; i++) { if (x[i] == 0) { if (rem2[i] == 0) { x1[i] = x[i] - 1; } else { x1[i] = 0; rem2[i] = ixheaacd_sub32_sat(rem2[i], (1 << count)); } } else { x1[i] = x[i] - 1; } } ixheaacd_nearest_neighbor_2d(x1, y1, count, rem2); for (i = 0; i < 8; i++) { y1[i] += 1; } e0 = e1 = 0; for (i = 0; i < 8; i++) { tmp = rem1[i]; e0 = ixheaacd_add32_sat(ixheaacd_sat64_32((WORD64)tmp * (WORD64)tmp), e0); tmp = rem2[i]; e1 = ixheaacd_add32_sat(ixheaacd_sat64_32((WORD64)tmp * (WORD64)tmp), e1); } if (e0 < e1) { for (i = 0; i < 8; i++) { y[i] = y0[i]; } } else { for (i = 0; i < 8; i++) { y[i] = y1[i]; } } return; } VOID ixheaacd_voronoi_idx_dec(WORD32 *kv, WORD32 m, WORD32 *y, WORD32 count) { WORD32 i, v[8], tmp, sum, *ptr1, *ptr2; WORD32 z[8]; WORD32 rem1[8], rem2[8]; for (i = 0; i < 8; i++) y[i] = kv[7]; z[7] = y[7] >> count; rem1[7] = y[7] & (m - 1); sum = 0; for (i = 6; i >= 1; i--) { tmp = ixheaacd_shl32_sat(kv[i], 1); sum = ixheaacd_add32_sat(sum, tmp); y[i] = ixheaacd_add32_sat(y[i], tmp); z[i] = y[i] >> count; rem1[i] = y[i] & (m - 1); } y[0] = ixheaacd_add32_sat( y[0], ixheaacd_add32_sat(ixheaacd_sat64_32((WORD64)4 * (WORD64)kv[0]), sum)); z[0] = (y[0] - 2) >> count; if (m != 0) rem1[0] = (y[0] - 2) % m; else rem1[0] = (y[0] - 2); memcpy(rem2, rem1, 8 * sizeof(WORD32)); ixheaacd_voronoi_search(z, v, count, rem1, rem2); ptr1 = y; ptr2 = v; for (i = 0; i < 8; i++) { *ptr1++ -= ixheaacd_sat64_32((WORD64)m * (WORD64)*ptr2++); } } static VOID ixheaacd_gosset_rank_of_permutation(WORD32 rank, WORD32 *xs) { WORD32 i, j, a[8], w[8], base, fac, fac_b, target; j = 0; w[j] = 1; a[j] = xs[0]; base = 1; for (i = 1; i < 8; i++) { if (xs[i] != xs[i - 1]) { j++; w[j] = 1; a[j] = xs[i]; } else { w[j]++; base *= w[j]; } } if (w[0] == 8) { for (i = 0; i < 8; i++) xs[i] = a[0]; } else { target = rank * base; fac_b = 1; for (i = 0; i < 8; i++) { fac = fac_b * ixheaacd_factorial_7[i]; j = -1; do { target -= w[++j] * fac; } while (target >= 0); xs[i] = a[j]; target += w[j] * fac; fac_b *= w[j]; w[j]--; } } return; } static WORD32 ixheaacd_get_abs_leader_tbl(const UWORD32 *table, UWORD32 code_book_ind, WORD32 size) { WORD32 i; for (i = 4; i < size; i += 4) { if (code_book_ind < table[i]) break; } if (i > size) i = size; if (code_book_ind < table[i - 2]) i -= 2; if (code_book_ind < table[i - 1]) i--; i--; return (i); } static VOID ixheaacd_gosset_decode_base_index(WORD32 n, UWORD32 code_book_ind, WORD32 *ya) { WORD32 i, im, t, sign_code, idx = 0, ks, rank; if (n < 2) { for (i = 0; i < 8; i++) ya[i] = 0; } else { switch (n) { case 2: case 3: i = ixheaacd_get_abs_leader_tbl(ixheaacd_cardinality_offset_table_i3, code_book_ind, LEN_I3); idx = ixheaacd_pos_abs_leaders_a3[i]; break; case 4: i = ixheaacd_get_abs_leader_tbl(ixheaacd_cardinality_offset_tab_i4, code_book_ind, LEN_I4); idx = ixheaacd_pos_abs_leaders_a4[i]; break; } for (i = 0; i < 8; i++) ya[i] = ixheaacd_absolute_leader_tab_da[idx][i]; t = ixheaacd_iso_code_index_table[idx]; im = ixheaacd_iso_code_num_table[idx]; ks = ixheaacd_get_abs_leader_tbl(ixheaacd_signed_leader_is + t, code_book_ind, im); sign_code = 2 * ixheaacd_iso_code_data_table[t + ks]; for (i = 7; i >= 0; i--) { ya[i] *= (1 - (sign_code & 2)); sign_code >>= 1; } rank = code_book_ind - ixheaacd_signed_leader_is[t + ks]; ixheaacd_gosset_rank_of_permutation(rank, ya); } return; } VOID ixheaacd_rotated_gosset_mtx_dec(WORD32 qn, WORD32 code_book_idx, WORD32 *kv, WORD32 *b) { if (qn <= 4) { ixheaacd_gosset_decode_base_index(qn, code_book_idx, b); } else { WORD32 i, m, c[8]; WORD32 count = 0; while (qn > 4) { count++; qn -= 2; } if (count >= 31) m = MAX_32; else m = 1 << count; ixheaacd_gosset_decode_base_index(qn, code_book_idx, b); ixheaacd_voronoi_idx_dec(kv, m, c, count); for (i = 0; i < 8; i++) { b[i] = ixheaacd_add32_sat(ixheaacd_sat64_32((WORD64)m * (WORD64)b[i]), c[i]); } } return; }