mirror of
https://github.com/ittiam-systems/libxaac.git
synced 2026-04-02 20:30:47 +07:00
216 lines
6.4 KiB
C
216 lines
6.4 KiB
C
/******************************************************************************
|
|
* *
|
|
* Copyright (C) 2023 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 <math.h>
|
|
#include "ixheaac_type_def.h"
|
|
#include "iusace_bitbuffer.h"
|
|
#include "iusace_cnst.h"
|
|
#include "iusace_tns_usac.h"
|
|
#include "iusace_psy_mod.h"
|
|
#include "iusace_block_switch_const.h"
|
|
#include "iusace_rom.h"
|
|
|
|
static FLOAT32 iusace_lpc_eval_chebyshev_polyn(FLOAT32 x, FLOAT32 *coefs, WORD32 order) {
|
|
WORD32 i;
|
|
FLOAT32 b0, b1, b2, x2;
|
|
x2 = 2.0f * x;
|
|
b2 = 1.0f;
|
|
b1 = x2 + coefs[1];
|
|
for (i = 2; i < order; i++) {
|
|
b0 = x2 * b1 - b2 + coefs[i];
|
|
b2 = b1;
|
|
b1 = b0;
|
|
}
|
|
return (x * b1 - b2 + 0.5f * coefs[order]);
|
|
}
|
|
|
|
VOID iusace_lpc_2_lsp_conversion(FLOAT32 *lpc, FLOAT32 *lsp, FLOAT32 *prev_lsp) {
|
|
FLOAT32 sum_polyn[(ORDER_BY_2) + 1], diff_polyn[(ORDER_BY_2) + 1];
|
|
FLOAT32 *p1_lpc, *p2_lpc, *p_sum_polyn, *p_diff_polyn;
|
|
WORD32 i, j = 0, num_found_freeq = 0, is_first_polyn = 0;
|
|
FLOAT32 x_low, y_low, x_high, y_high, x_mid, y_mid, x_lin_interp;
|
|
|
|
p_sum_polyn = sum_polyn;
|
|
p_diff_polyn = diff_polyn;
|
|
*p_sum_polyn++ = 1.0f;
|
|
*p_diff_polyn++ = 1.0f;
|
|
sum_polyn[0] = 1.0f;
|
|
diff_polyn[0] = 1.0f;
|
|
p1_lpc = lpc + 1;
|
|
p2_lpc = lpc + ORDER;
|
|
for (i = 0; i <= ORDER_BY_2 - 1; i++) {
|
|
*p_sum_polyn = *p1_lpc + *p2_lpc - *(p_sum_polyn - 1);
|
|
p_sum_polyn++;
|
|
*p_diff_polyn = *p1_lpc++ - *p2_lpc-- + *(p_diff_polyn - 1);
|
|
p_diff_polyn++;
|
|
}
|
|
p_sum_polyn = sum_polyn;
|
|
x_low = iusace_chebyshev_polyn_grid[0];
|
|
y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2);
|
|
|
|
while ((num_found_freeq < ORDER) && (j < CHEBYSHEV_NUM_POINTS)) {
|
|
j++;
|
|
x_high = x_low;
|
|
y_high = y_low;
|
|
x_low = iusace_chebyshev_polyn_grid[j];
|
|
y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2);
|
|
|
|
if (y_low * y_high <= 0.0) /* if sign change new root exists */
|
|
{
|
|
j--;
|
|
for (i = 0; i < CHEBYSHEV_NUM_ITER; i++) {
|
|
x_mid = 0.5f * (x_low + x_high);
|
|
y_mid = iusace_lpc_eval_chebyshev_polyn(x_mid, p_sum_polyn, ORDER_BY_2);
|
|
if (y_low * y_mid <= 0.0) {
|
|
y_high = y_mid;
|
|
x_high = x_mid;
|
|
} else {
|
|
y_low = y_mid;
|
|
x_low = x_mid;
|
|
}
|
|
}
|
|
|
|
/* linear interpolation for evaluating the root */
|
|
x_lin_interp = x_low - y_low * (x_high - x_low) / (y_high - y_low);
|
|
|
|
lsp[num_found_freeq] = x_lin_interp;
|
|
num_found_freeq++;
|
|
|
|
is_first_polyn = 1 - is_first_polyn;
|
|
p_sum_polyn = is_first_polyn ? diff_polyn : sum_polyn;
|
|
|
|
x_low = x_lin_interp;
|
|
y_low = iusace_lpc_eval_chebyshev_polyn(x_low, p_sum_polyn, ORDER_BY_2);
|
|
}
|
|
}
|
|
|
|
/* Check if ORDER roots found */
|
|
/* if not use the LSPs from previous frame */
|
|
if (num_found_freeq < ORDER) {
|
|
for (i = 0; i < ORDER; i++) lsp[i] = prev_lsp[i];
|
|
}
|
|
}
|
|
|
|
static VOID iusace_compute_coeff_poly_f(FLOAT32 *lsp, FLOAT32 *poly1, FLOAT32 *poly2) {
|
|
FLOAT32 b1, b2;
|
|
FLOAT32 *ptr_lsp;
|
|
WORD32 i, j;
|
|
|
|
ptr_lsp = lsp;
|
|
poly1[0] = poly2[0] = 1.0f;
|
|
|
|
for (i = 1; i <= ORDER_BY_2; i++) {
|
|
b1 = -2.0f * (*ptr_lsp++);
|
|
b2 = -2.0f * (*ptr_lsp++);
|
|
poly1[i] = (b1 * poly1[i - 1]) + (2.0f * poly1[i - 2]);
|
|
poly2[i] = (b2 * poly2[i - 1]) + (2.0f * poly2[i - 2]);
|
|
for (j = i - 1; j > 0; j--) {
|
|
poly1[j] += (b1 * poly1[j - 1]) + poly1[j - 2];
|
|
poly2[j] += (b2 * poly2[j - 1]) + poly2[j - 2];
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID iusace_lsp_to_lp_conversion(FLOAT32 *lsp, FLOAT32 *lp_flt_coff_a) {
|
|
WORD32 i;
|
|
FLOAT32 *ppoly_f1, *ppoly_f2;
|
|
FLOAT32 *plp_flt_coff_a_bott, *plp_flt_coff_a_top;
|
|
FLOAT32 poly1[ORDER_BY_2 + 2], poly2[ORDER_BY_2 + 2];
|
|
|
|
poly1[0] = 0.0f;
|
|
poly2[0] = 0.0f;
|
|
|
|
iusace_compute_coeff_poly_f(lsp, &poly1[1], &poly2[1]);
|
|
|
|
ppoly_f1 = poly1 + ORDER_BY_2 + 1;
|
|
ppoly_f2 = poly2 + ORDER_BY_2 + 1;
|
|
|
|
for (i = 0; i < ORDER_BY_2; i++) {
|
|
ppoly_f1[0] += ppoly_f1[-1];
|
|
ppoly_f2[0] -= ppoly_f2[-1];
|
|
ppoly_f1--;
|
|
ppoly_f2--;
|
|
}
|
|
|
|
plp_flt_coff_a_bott = lp_flt_coff_a;
|
|
*plp_flt_coff_a_bott++ = 1.0f;
|
|
plp_flt_coff_a_top = lp_flt_coff_a + ORDER;
|
|
ppoly_f1 = poly1 + 2;
|
|
ppoly_f2 = poly2 + 2;
|
|
for (i = 0; i < ORDER_BY_2; i++) {
|
|
*plp_flt_coff_a_bott++ = 0.5f * (*ppoly_f1 + *ppoly_f2);
|
|
*plp_flt_coff_a_top-- = 0.5f * (*ppoly_f1++ - *ppoly_f2++);
|
|
}
|
|
}
|
|
|
|
VOID iusace_levinson_durbin_algo(FLOAT32 *auto_corr_input, FLOAT32 *lpc) {
|
|
WORD32 i, j;
|
|
FLOAT32 lpc_val, sum, sigma;
|
|
FLOAT32 reflection_coeffs[LEV_DUR_MAX_ORDER];
|
|
|
|
lpc[0] = 1.0f;
|
|
|
|
reflection_coeffs[0] = -auto_corr_input[1] / auto_corr_input[0];
|
|
lpc[1] = reflection_coeffs[0];
|
|
sigma = auto_corr_input[0] + auto_corr_input[1] * reflection_coeffs[0];
|
|
|
|
for (i = 2; i <= ORDER; i++) {
|
|
sum = 0.0f;
|
|
for (j = 0; j < i; j++) sum += auto_corr_input[i - j] * lpc[j];
|
|
reflection_coeffs[i - 1] = -sum / sigma;
|
|
|
|
sigma = sigma * (1.0f - reflection_coeffs[i - 1] * reflection_coeffs[i - 1]);
|
|
|
|
if (sigma <= 1.0E-09f) {
|
|
for (j = i; j <= ORDER; j++) {
|
|
reflection_coeffs[j - 1] = 0.0f;
|
|
lpc[j] = 0.0f;
|
|
}
|
|
break;
|
|
}
|
|
|
|
for (j = 1; j <= (i / 2); j++) {
|
|
lpc_val = lpc[j] + reflection_coeffs[i - 1] * lpc[i - j];
|
|
lpc[i - j] += reflection_coeffs[i - 1] * lpc[j];
|
|
lpc[j] = lpc_val;
|
|
}
|
|
|
|
lpc[i] = reflection_coeffs[i - 1];
|
|
}
|
|
}
|
|
|
|
VOID iusace_get_weighted_lpc(FLOAT32 *lpc, FLOAT32 *weighted_lpc) {
|
|
WORD32 i;
|
|
for (i = 0; i <= ORDER; i++) {
|
|
weighted_lpc[i] = iusace_gamma_table[i] * lpc[i];
|
|
}
|
|
}
|
|
|
|
VOID iusace_lsp_2_lsf_conversion(FLOAT32 *lsp, FLOAT32 *lsf) {
|
|
WORD32 i;
|
|
for (i = 0; i < ORDER; i++) {
|
|
lsf[i] = (FLOAT32)(acos(lsp[i]) * LSP_2_LSF_SCALE);
|
|
}
|
|
}
|
|
|
|
VOID iusace_lsf_2_lsp_conversion(FLOAT32 *lsf, FLOAT32 *lsp) {
|
|
WORD32 i;
|
|
for (i = 0; i < ORDER; i++) lsp[i] = (FLOAT32)cos((FLOAT64)lsf[i] * (FLOAT64)PI_BY_6400);
|
|
}
|