| /****************************************************************************** |
| * * |
| * 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] = ixheaacd_negate32_sat( |
| ixheaacd_shl32_sat((ixheaacd_sub32_sat(1, x[i]) >> 1), 1)); |
| } else { |
| y[i] = ixheaacd_shl32_sat((ixheaacd_add32_sat(1, x[i]) >> 1), 1); |
| } |
| sum = ixheaacd_add32_sat(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] = ixheaacd_add32_sat(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] = ixheaacd_sub32_sat(x[i], 1); |
| } |
| } |
| |
| ixheaacd_nearest_neighbor_2d(x1, y1, count, rem2); |
| |
| for (i = 0; i < 8; i++) { |
| y1[i] = ixheaacd_add32_sat(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] = (ixheaacd_sub32_sat(y[0], 2)) >> count; |
| if (m != 0) |
| rem1[0] = (ixheaacd_sub32_sat(y[0], 2)) % m; |
| else |
| rem1[0] = ixheaacd_sub32_sat(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_sub32_sat(*ptr1, |
| ixheaacd_sat64_32((WORD64)m * (WORD64)*ptr2++)); |
| ptr1++; |
| } |
| } |
| |
| 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; |
| } |