From 2e9d3337f36b74ee7422e17a0d04b04cb0065585 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Wed, 22 Nov 2023 14:45:14 +0530 Subject: [PATCH] EVS files/functions imported [x] Some of EVS fixed point files/code pulled in as-is. [x] Changes made in IVAS floating code to maintain floating code and avoid conflicts with newly introduced fixed point code. [x] Floating code output is bit exact with base version IVAS code. [x] As EVS changes are taken as-is for initial fixed version creation, the changes are not broken into multiple commits. Hence, the changes involve more number of files. --- Workspace_msvc/lib_com.vcxproj | 2 + Workspace_msvc/lib_com.vcxproj.filters | 26 +- Workspace_msvc/lib_enc.vcxproj | 5 + Workspace_msvc/lib_enc.vcxproj.filters | 15 + lib_com/cnst.h | 5 + lib_com/codec_tcx_common.c | 621 ++++++------ lib_com/codec_tcx_common_flt.c | 332 +++++++ lib_com/prot.h | 76 +- lib_com/prot_fx2.h | 426 ++++++++- lib_com/rom_basop_util.c | 15 +- lib_com/rom_basop_util.h | 2 + lib_com/rom_com.c | 140 ++- lib_com/rom_com.h | 40 +- lib_com/stat_com.h | 2 +- lib_com/tcx_utils.c | 6 +- lib_com/tns_base.c | 1194 ++++++++++++++---------- lib_com/tns_base_flt.c | 849 +++++++++++++++++ lib_dec/dec_tcx.c | 8 +- lib_dec/nelp_dec.c | 2 +- lib_dec/tns_base_dec.c | 2 +- lib_enc/SNR_calc_fx.c | 543 +++++++++++ lib_enc/cod_tcx.c | 26 +- lib_enc/detect_transient_fx.c | 434 +++++++++ lib_enc/enc_ppp_fx.c | 235 +++++ lib_enc/gp_clip_fx.c | 459 +++++++++ lib_enc/isf_enc_amr_wb_fx.c | 571 +++++++++++ lib_enc/nelp_enc.c | 2 +- lib_enc/nelp_enc_fx.c | 1028 ++++++++++++++++++++ lib_enc/stat_enc.h | 3 + lib_enc/swb_bwe_enc_lr_fx.c | 1128 ++++++++++++++++++++++ lib_enc/tns_base_enc.c | 12 +- 31 files changed, 7368 insertions(+), 841 deletions(-) create mode 100644 lib_com/codec_tcx_common_flt.c create mode 100644 lib_com/tns_base_flt.c create mode 100644 lib_enc/SNR_calc_fx.c create mode 100644 lib_enc/detect_transient_fx.c create mode 100644 lib_enc/enc_ppp_fx.c create mode 100644 lib_enc/gp_clip_fx.c create mode 100644 lib_enc/isf_enc_amr_wb_fx.c create mode 100644 lib_enc/nelp_enc_fx.c create mode 100644 lib_enc/swb_bwe_enc_lr_fx.c diff --git a/Workspace_msvc/lib_com.vcxproj b/Workspace_msvc/lib_com.vcxproj index 64dd04a58..ee98364c9 100644 --- a/Workspace_msvc/lib_com.vcxproj +++ b/Workspace_msvc/lib_com.vcxproj @@ -139,6 +139,7 @@ + @@ -298,6 +299,7 @@ + diff --git a/Workspace_msvc/lib_com.vcxproj.filters b/Workspace_msvc/lib_com.vcxproj.filters index 495917759..1f2cfe90a 100644 --- a/Workspace_msvc/lib_com.vcxproj.filters +++ b/Workspace_msvc/lib_com.vcxproj.filters @@ -73,9 +73,6 @@ common_all_c - - common_all_c - common_all_c @@ -322,9 +319,6 @@ common_all_c - - common_all_c - common_all_c @@ -518,8 +512,12 @@ common_all_c - - + + common_all_c + + + common_all_c + common_all_c @@ -581,6 +579,18 @@ common_all_c + + common_all_c + + + common_all_c + + + common_all_c + + + common_all_c + diff --git a/Workspace_msvc/lib_enc.vcxproj b/Workspace_msvc/lib_enc.vcxproj index e3deeb989..e033d4a0e 100644 --- a/Workspace_msvc/lib_enc.vcxproj +++ b/Workspace_msvc/lib_enc.vcxproj @@ -140,6 +140,9 @@ + + + @@ -278,11 +281,13 @@ + + diff --git a/Workspace_msvc/lib_enc.vcxproj.filters b/Workspace_msvc/lib_enc.vcxproj.filters index e74f441c4..cba4641b3 100644 --- a/Workspace_msvc/lib_enc.vcxproj.filters +++ b/Workspace_msvc/lib_enc.vcxproj.filters @@ -596,6 +596,21 @@ enc_ivas_c + + enc_all_c + + + enc_evs_c + + + enc_evs_c + + + enc_evs_c + + + enc_all_c + diff --git a/lib_com/cnst.h b/lib_com/cnst.h index 104c639b3..26238754a 100644 --- a/lib_com/cnst.h +++ b/lib_com/cnst.h @@ -201,6 +201,8 @@ enum{ #define SBA_AGC_FORCE_DISABLE 0 #define SBA_AGC_DEFAULT -1 +extern const Word16 Idx2Freq_Tbl[]; + /*----------------------------------------------------------------------------------* * Layers *----------------------------------------------------------------------------------*/ @@ -2919,5 +2921,8 @@ extern const Word16 Idx2Freq_Tbl[]; #define L_PAST_MAX_12k8 144 /* maximum encoder past samples at 12k8Hz */ #define L_DIV 256 /* 20ms frame size (ACELP or short TCX frame) */ + +//tbs_vase.c +#define PRED_GAIN_E 8 /* clang-format on */ #endif /* CNST_H */ diff --git a/lib_com/codec_tcx_common.c b/lib_com/codec_tcx_common.c index c919067a3..e04cebb9a 100644 --- a/lib_com/codec_tcx_common.c +++ b/lib_com/codec_tcx_common.c @@ -1,206 +1,299 @@ -/****************************************************************************************************** - - (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository. All Rights Reserved. - - This software is protected by copyright law and by international treaties. - The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository retain full ownership rights in their respective contributions in - the software. This notice grants no license of any kind, including but not limited to patent - license, nor is any license granted by implication, estoppel or otherwise. - - Contributors are required to enter into the IVAS codec Public Collaboration agreement before making - contributions. - - This software is provided "AS IS", without any express or implied warranties. The software is in the - development stage. It is intended exclusively for experts who have experience with such software and - solely for the purpose of inspection. All implied warranties of non-infringement, merchantability - and fitness for a particular purpose are hereby disclaimed and excluded. - - Any dispute, controversy or claim arising under or in relation to providing this software shall be - submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in - accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and - the United Nations Convention on Contracts on the International Sales of Goods. - -*******************************************************************************************************/ - /*==================================================================================== - EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0 + EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0 ====================================================================================*/ #include +#include #include "options.h" -#include -#include "prot.h" -#include "wmc_auto.h" - -/*-------------------------------------------------------------------* - * tcxGetNoiseFillingTilt() - * - * - *-------------------------------------------------------------------*/ - -int16_t tcxGetNoiseFillingTilt( - const float A[], - const int16_t L_frame, - const int16_t mode, - float *noiseTiltFactor ) +#include "prot_fx2.h" +#include "prot_fx1.h" +#include "basop_util.h" +#include "rom_basop_util.h" + +#define inv_int InvIntTable + +Word16 tcxGetNoiseFillingTilt( + const Word16 A[], + const Word16 lpcorder, + const Word16 L_frame, + const Word16 mode, + Word16 *noiseTiltFactor +) { - int16_t firstLine; - - if ( mode ) - { - firstLine = L_frame / 6; - *noiseTiltFactor = 0.5625f; - } - else - { - firstLine = L_frame / 8; - *noiseTiltFactor = get_gain_flt( A + 1, A, M, NULL ); - *noiseTiltFactor = min( 1.0f, ( *noiseTiltFactor ) + 0.09375f ); - } - - return firstLine; + Word16 firstLine; + Word32 tmp; + Word16 As[M + 1]; + + + IF(mode != 0) + { + firstLine = idiv1616U(L_frame, 6); + *noiseTiltFactor = 18432/*0.5625f Q15*/; + move16(); + } + ELSE + { + firstLine = shr(L_frame, 3); + + Copy_Scale_sig(A, As, lpcorder + 1, sub(norm_s(A[0]),2)); + tmp = get_gain(As + 1, As, lpcorder); + BASOP_SATURATE_WARNING_OFF_EVS; + *noiseTiltFactor = add(round_fx(L_shl(tmp, 15)), 3072/*0.09375f Q15*/); + move16(); + BASOP_SATURATE_WARNING_ON_EVS; + } + + + return firstLine; } -/*-------------------------------------------------------------------* - * tcxFormantEnhancement() - * - * - *-------------------------------------------------------------------*/ void tcxFormantEnhancement( - float xn_buf[], - const float *gainlpc, - float spectrum[], - const int16_t L_frame ) + Word16 xn_buf[], + const Word16 gainlpc[], + const Word16 gainlpc_e[], + Word32 spectrum[], + Word16 *spectrum_e, + const Word16 L_frame, + const Word16 L_frameTCX +) { - int16_t k, i, j, l = 0; - float fac, step; - - k = L_frame / FDNS_NPTS; - - /* Formant enhancement via square root of the LPC gains */ - xn_buf[0] = (float) sqrt( gainlpc[0] ); - xn_buf[1] = (float) sqrt( gainlpc[1] ); - fac = 1.0f / min( xn_buf[0], xn_buf[1] ); - - for ( i = 1; i < FDNS_NPTS - 1; i++ ) - { - xn_buf[i + 1] = (float) sqrt( gainlpc[i + 1] ); - - if ( ( xn_buf[i - 1] <= xn_buf[i] ) && ( xn_buf[i + 1] <= xn_buf[i] ) ) - { - step = max( xn_buf[i - 1], xn_buf[i + 1] ); - step = ( 1.0f / step - fac ) / (float) ( i - l ); - xn_buf[l] = 1.0f; - fac += step; - for ( j = l + 1; j < i; j++ ) - { - xn_buf[j] = min( 1.0f, xn_buf[j] * fac ); - fac += step; - } - l = i; - } - } - - /* i = hTcxCfg->fdns_npts - 1; Completing changes to gains */ - step = min( xn_buf[i - 1], xn_buf[i] ); - step = ( 1.0f / step - fac ) / (float) ( i - l ); - xn_buf[l] = 1.0f; - fac += step; - for ( j = l + 1; j < i; j++ ) - { - xn_buf[j] = min( 1.0f, xn_buf[j] * fac ); - fac += step; - } - xn_buf[i] = 1.0f; - - /* Application of changed gains onto decoded MDCT lines */ - for ( i = j = 0; i < L_frame; j++ ) - { - for ( l = 0; l < k; i++, l++ ) - { - spectrum[i] *= xn_buf[j]; - } - } - - return; -} + Word16 i, j, k, l, n; + Word16 fac, fac0, fac1, fac_e, d, tmp; + Word16 xn_buf_e, xn_one, m, e; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + k = shr(L_frame, 6); /* FDNS_NPTS = 64 */ + l = 0; + move16(); + + /* get exponent */ + xn_buf_e = 0; + move16(); + FOR(i = 0; i < FDNS_NPTS; i++) + { + xn_buf_e = s_max(xn_buf_e, gainlpc_e[i]); + } + xn_buf_e = shr(add(xn_buf_e, 1), 1); /* max exponent after sqrt */ + xn_one = shr(0x4000, sub(xn_buf_e, 1)); /* 1.0 scaled to xn_buf_e */ + + /* Formant enhancement via square root of the LPC gains */ + e = gainlpc_e[0]; + move16(); + m = Sqrt16(gainlpc[0], &e); + xn_buf[0] = shl(m, sub(e, xn_buf_e)); + move16(); + + e = gainlpc_e[1]; + move16(); + m = Sqrt16(gainlpc[1], &e); + xn_buf[1] = shl(m, sub(e, xn_buf_e)); + move16(); + + fac0 = s_min(xn_buf[0], xn_buf[1]); + fac_e = xn_buf_e; + move16(); + fac0 = Inv16(fac0, &fac_e); + + FOR(i = 1; i < FDNS_NPTS - 1; i++) + { + e = gainlpc_e[i + 1]; + move16(); + m = Sqrt16(gainlpc[i + 1], &e); + xn_buf[i + 1] = shl(m, sub(e, xn_buf_e)); + move16(); + + test(); + IF((LE_16(xn_buf[i - 1], xn_buf[i])) && (LE_16(xn_buf[i + 1], xn_buf[i]))) + { + m = s_max(xn_buf[i - 1], xn_buf[i + 1]); + e = xn_buf_e; + move16(); + m = Inv16(m, &e); + + fac1 = m; + move16(); + tmp = sub(e, fac_e); + + if (tmp > 0) fac0 = shr(fac0, tmp); + if (tmp < 0) fac1 = shl(fac1, tmp); + + if (tmp > 0) + { + fac_e = e; + move16(); + } + + d = sub(fac1, fac0); + n = sub(i, l); + assert(n <= 64); + + xn_buf[l] = xn_one; + move16(); + FOR(j = 1; j < n; j++) + { + fac = add(fac0, mult(d, extract_l(L_mult0(j, inv_int[n])))); + BASOP_SATURATE_WARNING_OFF_EVS; +#ifdef BASOP_NOGLOB + xn_buf[l + j] = s_min(xn_one, shl_o(mult(xn_buf[l + j], fac), fac_e, &Overflow)); +#else + xn_buf[l + j] = s_min(xn_one, shl(mult(xn_buf[l + j], fac), fac_e)); +#endif + move16(); + BASOP_SATURATE_WARNING_ON_EVS; + } + + l = i; + move16(); + + fac0 = m; + move16(); + fac_e = e; + move16(); + } + } + /* i = FDNS_NPTS - 1; Completing changes to gains */ + m = s_min(xn_buf[i - 1], xn_buf[i]); + e = xn_buf_e; + move16(); + m = Inv16(m, &e); + + fac1 = m; + move16(); + tmp = sub(e, fac_e); + + if (tmp > 0) fac0 = shr(fac0, tmp); + if (tmp < 0) fac1 = shl(fac1, tmp); + + if (tmp > 0) + { + fac_e = e; + move16(); + } + + d = sub(fac1, fac0); + n = sub(i, l); + assert(n <= 64); + + xn_buf[l] = xn_one; + move16(); + FOR(j = 1; j < n; j++) + { + fac = add(fac0, mult(d, extract_l(L_mult0(j, inv_int[n])))); + BASOP_SATURATE_WARNING_OFF_EVS; + xn_buf[l + j] = s_min(xn_one, shl(mult(xn_buf[l + j], fac), fac_e)); + move16(); + BASOP_SATURATE_WARNING_ON_EVS; + } + + xn_buf[i] = xn_one; + move16(); + + /* Application of changed gains onto decoded MDCT lines */ + FOR(i = 0; i < L_frame; i += k) + { + FOR(l = 0; l < k; l++) + { + *spectrum = Mpy_32_16_1(*spectrum, *xn_buf); + move32(); + spectrum++; + } + xn_buf++; + } + + tmp = sub(L_frameTCX, L_frame); + FOR(i = 0; i < tmp; i++) + { + spectrum[i] = L_shr(spectrum[i], xn_buf_e); + move32(); + } + *spectrum_e = add(*spectrum_e, xn_buf_e); + move16(); -/*-------------------------------------------------------------------* - * tcxInvertWindowGrouping() - * - * - *-------------------------------------------------------------------*/ +} void tcxInvertWindowGrouping( - TCX_CONFIG_HANDLE hTcxCfg, - float xn_buf[], - float spectrum[], - const int16_t L_frame, - const int16_t fUseTns, - const int16_t last_core, - const int16_t index, - const int16_t frame_cnt, - const int16_t bfi ) + TCX_CONFIG_HANDLE hTcxCfg, /* i : configuration of TCX */ + Word32 xn_buf[], + Word32 spectrum[], + const Word16 L_frame, + const Word8 fUseTns, + const Word16 last_core, + const Word16 index, + const Word16 frame_cnt, + const Word16 bfi +) { - int16_t i, w, t_integer; - int16_t L_win, L_spec; - - if ( frame_cnt && !bfi && last_core != ACELP_CORE ) - { - /* fix sub-window overlap */ - hTcxCfg->tcx_last_overlap_mode = hTcxCfg->tcx_curr_overlap_mode; - } - - if ( ( ( !bfi ) && ( ( hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP ) || - ( ( hTcxCfg->tcx_curr_overlap_mode == FULL_OVERLAP ) && ( frame_cnt == 0 ) && ( index == 0 ) ) ) ) || - ( ( bfi ) && ( ( hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP ) && - !( hTcxCfg->tcx_curr_overlap_mode == FULL_OVERLAP ) ) ) ) - { - - /* ungroup sub-windows: deinterleave MDCT bins into separate windows */ - for ( t_integer = w = 0; w < 2; w++ ) - { - for ( i = w; i < L_frame; i += 2 ) - { - xn_buf[t_integer++] = spectrum[i]; - } - } - - mvr2r( xn_buf, spectrum, L_frame ); - - if ( hTcxCfg->fIsTNSAllowed && !bfi && fUseTns ) - { - L_win = L_frame >> 1; - L_spec = hTcxCfg->tnsConfig[0][0].iFilterBorders[0]; - - /* rearrange LF sub-window lines prior to TNS synthesis filtering */ - if ( L_spec < L_frame ) - { - mvr2r( spectrum + 8, spectrum + 16, L_spec / 2 - 8 ); - mvr2r( spectrum + L_frame / 2, spectrum + 8, 8 ); - mvr2r( spectrum + L_frame / 2 + 8, spectrum + L_spec / 2 + 8, L_spec / 2 - 8 ); - } - else - { - mvr2r( spectrum + 8, xn_buf, L_win ); - mvr2r( xn_buf, spectrum + 16, L_win - 8 ); - mvr2r( xn_buf + L_win - 8, spectrum + 8, 8 ); - } - } - } - - return; + Word16 i, L_win, L_spec; + Word32 *p; + + + L_win = shr(L_frame, 1); + L_spec = hTcxCfg->tnsConfig[0][0].iFilterBorders[0]; + move16(); + + test(); + test(); + if ((frame_cnt != 0) && (bfi == 0) && NE_16(last_core, ACELP_CORE)) /* fix sub-window overlap */ + { + hTcxCfg->tcx_last_overlap_mode = hTcxCfg->tcx_curr_overlap_mode; + move16(); + } + test(); test(); test(); test(); test(); test(); test(); + IF(((bfi == 0) && ((hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP) || + ((hTcxCfg->tcx_curr_overlap_mode == FULL_OVERLAP) && (frame_cnt == 0) && (index == 0)))) + || + ((bfi != 0) && ((hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP) && + !(hTcxCfg->tcx_curr_overlap_mode == FULL_OVERLAP)))) + { + /* ungroup sub-windows: deinterleave MDCT bins into separate windows */ + p = xn_buf; + FOR(i = 1; i < L_win; i += 2) + { + *p++ = spectrum[i]; + move32(); + } + + p = spectrum; + FOR(i = 0; i < L_frame; i += 2) + { + *p++ = spectrum[i]; + move32(); + } + + p = spectrum + L_frame - 1; + FOR(i = sub(L_frame, 1); i > L_win; i -= 2) + { + *p-- = spectrum[i]; + move32(); + } + Copy32(xn_buf, spectrum + L_win, shr(L_win, 1)); + + test(); + test(); + IF((hTcxCfg->fIsTNSAllowed != 0) && (bfi == 0) && (fUseTns != 0)) + { + /* rearrange LF sub-window lines prior to TNS synthesis filtering */ + IF(LT_16(L_spec, L_frame)) + { + Copy32(spectrum + 8, spectrum + 16, sub(shr(L_spec, 1), 8)); + Copy32(spectrum + L_frame / 2, spectrum + 8, 8); + Copy32(spectrum + L_frame / 2 + 8, spectrum + L_spec / 2 + 8, sub(shr(L_spec, 1), 8)); + } + ELSE + { + Copy32(spectrum + L_win, xn_buf, 8); + Copy32(spectrum + 8, spectrum + 16, sub(L_win, 8)); + Copy32(xn_buf, spectrum + 8, 8); + } + } + } + } +#ifdef IVAS_CODE_TCX_COM /*-------------------------------------------------------------------* * tcx5SpectrumInterleaving() @@ -209,24 +302,24 @@ void tcxInvertWindowGrouping( *-------------------------------------------------------------------*/ void tcx5SpectrumInterleaving( - const int16_t tcx5Size, - float *spectrum ) + const int16_t tcx5Size, + float* spectrum) { - int16_t i; - float interleaveBuf[N_TCX10_MAX]; + int16_t i; + float interleaveBuf[N_TCX10_MAX]; - set_f( interleaveBuf, 0.0f, N_TCX10_MAX ); + set_f(interleaveBuf, 0.0f, N_TCX10_MAX); - /* group sub-windows: interleave bins according to their frequencies */ - for ( i = 0; i < tcx5Size; i++ ) - { - interleaveBuf[2 * i] = spectrum[i]; - interleaveBuf[2 * i + 1] = spectrum[tcx5Size + i]; - } + /* group sub-windows: interleave bins according to their frequencies */ + for (i = 0; i < tcx5Size; i++) + { + interleaveBuf[2 * i] = spectrum[i]; + interleaveBuf[2 * i + 1] = spectrum[tcx5Size + i]; + } - mvr2r( interleaveBuf, spectrum, 2 * tcx5Size ); + mvr2r(interleaveBuf, spectrum, 2 * tcx5Size); - return; + return; } @@ -237,24 +330,24 @@ void tcx5SpectrumInterleaving( *-------------------------------------------------------------------*/ void tcx5SpectrumDeinterleaving( - const int16_t tcx5Size, - float *spectrum ) + const int16_t tcx5Size, + float* spectrum) { - int16_t i; - float interleaveBuf[N_TCX10_MAX]; + int16_t i; + float interleaveBuf[N_TCX10_MAX]; - set_f( interleaveBuf, 0.0f, N_TCX10_MAX ); + set_f(interleaveBuf, 0.0f, N_TCX10_MAX); - /* ungroup sub-windows: interleave bins according to their frequencies */ - for ( i = 0; i < tcx5Size; i++ ) - { - interleaveBuf[i] = spectrum[2 * i]; - interleaveBuf[tcx5Size + i] = spectrum[2 * i + 1]; - } + /* ungroup sub-windows: interleave bins according to their frequencies */ + for (i = 0; i < tcx5Size; i++) + { + interleaveBuf[i] = spectrum[2 * i]; + interleaveBuf[tcx5Size + i] = spectrum[2 * i + 1]; + } - mvr2r( interleaveBuf, spectrum, 2 * tcx5Size ); + mvr2r(interleaveBuf, spectrum, 2 * tcx5Size); - return; + return; } @@ -265,26 +358,26 @@ void tcx5SpectrumDeinterleaving( *-------------------------------------------------------------------*/ void tcx5TnsGrouping( - const int16_t L_frame, /* i : frame length (TCX5) */ - const int16_t L_spec, /* i : coded spec length (TCX5, derived from filter borders*/ - float *spectrum ) + const int16_t L_frame, /* i : frame length (TCX5) */ + const int16_t L_spec, /* i : coded spec length (TCX5, derived from filter borders*/ + float* spectrum) { - /* rearrange LF sub-window lines prior to TNS synthesis filtering */ - if ( L_spec < L_frame ) - { - mvr2r( spectrum + 8, spectrum + 16, L_spec - 8 ); - mvr2r( spectrum + L_frame, spectrum + 8, 8 ); - mvr2r( spectrum + L_frame + 8, spectrum + L_spec + 8, L_spec - 8 ); - } - else - { - float buff[8]; /* Buffer for the rearrangement of LF TCX5 */ - mvr2r( spectrum + L_spec, buff, 8 ); - mvr2r( spectrum + 8, spectrum + 16, L_spec - 8 ); - mvr2r( buff, spectrum + 8, 8 ); - } - - return; + /* rearrange LF sub-window lines prior to TNS synthesis filtering */ + if (L_spec < L_frame) + { + mvr2r(spectrum + 8, spectrum + 16, L_spec - 8); + mvr2r(spectrum + L_frame, spectrum + 8, 8); + mvr2r(spectrum + L_frame + 8, spectrum + L_spec + 8, L_spec - 8); + } + else + { + float buff[8]; /* Buffer for the rearrangement of LF TCX5 */ + mvr2r(spectrum + L_spec, buff, 8); + mvr2r(spectrum + 8, spectrum + 16, L_spec - 8); + mvr2r(buff, spectrum + 8, 8); + } + + return; } @@ -295,38 +388,40 @@ void tcx5TnsGrouping( *-------------------------------------------------------------------*/ void tcx5TnsUngrouping( - const int16_t L_frame, /* i : frame length (TCX5) */ - const int16_t L_spec, /* i : coded spec length (TCX5, derived from filter borders*/ - float *spectrum, - const int16_t enc_dec /* i : 0: encoder, else decoder */ + const int16_t L_frame, /* i : frame length (TCX5) */ + const int16_t L_spec, /* i : coded spec length (TCX5, derived from filter borders*/ + float* spectrum, + const int16_t enc_dec /* i : 0: encoder, else decoder */ ) { - /* undo rearrangement of LF sub-window lines prior to TNS analysis */ - if ( L_spec < L_frame ) - { - mvr2r( spectrum + L_spec + 8, spectrum + L_frame + 8, L_spec - 8 ); - mvr2r( spectrum + 8, spectrum + L_frame, 8 ); - mvr2r( spectrum + 16, spectrum + 8, L_spec - 8 ); - set_zero( spectrum + L_spec, L_frame - L_spec ); - set_zero( spectrum + L_frame + L_spec, L_frame - L_spec ); - } - else - { - float buff[8]; /* Buffer for the rearrangement of LF TCX5 */ - - mvr2r( spectrum + 8, buff, 8 ); - - if ( enc_dec == ENC ) - { - mvr2r( spectrum + 16, spectrum + 8, L_frame - 8 ); - mvr2r( buff, spectrum + L_frame, 8 ); - } - else - { - mvr2r( spectrum + 16, spectrum + 8, L_spec - 8 ); - mvr2r( buff, spectrum + L_spec, 8 ); - } - } - - return; + /* undo rearrangement of LF sub-window lines prior to TNS analysis */ + if (L_spec < L_frame) + { + mvr2r(spectrum + L_spec + 8, spectrum + L_frame + 8, L_spec - 8); + mvr2r(spectrum + 8, spectrum + L_frame, 8); + mvr2r(spectrum + 16, spectrum + 8, L_spec - 8); + set_zero(spectrum + L_spec, L_frame - L_spec); + set_zero(spectrum + L_frame + L_spec, L_frame - L_spec); + } + else + { + float buff[8]; /* Buffer for the rearrangement of LF TCX5 */ + + mvr2r(spectrum + 8, buff, 8); + + if (enc_dec == ENC) + { + mvr2r(spectrum + 16, spectrum + 8, L_frame - 8); + mvr2r(buff, spectrum + L_frame, 8); + } + else + { + mvr2r(spectrum + 16, spectrum + 8, L_spec - 8); + mvr2r(buff, spectrum + L_spec, 8); + } + } + + return; } + +#endif diff --git a/lib_com/codec_tcx_common_flt.c b/lib_com/codec_tcx_common_flt.c new file mode 100644 index 000000000..77bcaa9c9 --- /dev/null +++ b/lib_com/codec_tcx_common_flt.c @@ -0,0 +1,332 @@ +/****************************************************************************************************** + + (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/*==================================================================================== + EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0 + ====================================================================================*/ + +#include +#include "options.h" +#include +#include "prot.h" +#include "wmc_auto.h" + +/*-------------------------------------------------------------------* + * tcxGetNoiseFillingTilt() + * + * + *-------------------------------------------------------------------*/ + +int16_t tcxGetNoiseFillingTilt_flt( + const float A[], + const int16_t L_frame, + const int16_t mode, + float *noiseTiltFactor ) +{ + int16_t firstLine; + + if ( mode ) + { + firstLine = L_frame / 6; + *noiseTiltFactor = 0.5625f; + } + else + { + firstLine = L_frame / 8; + *noiseTiltFactor = get_gain_flt( A + 1, A, M, NULL ); + *noiseTiltFactor = min( 1.0f, ( *noiseTiltFactor ) + 0.09375f ); + } + + return firstLine; +} + +/*-------------------------------------------------------------------* + * tcxFormantEnhancement() + * + * + *-------------------------------------------------------------------*/ + +void tcxFormantEnhancement_flt( + float xn_buf[], + const float *gainlpc, + float spectrum[], + const int16_t L_frame ) +{ + int16_t k, i, j, l = 0; + float fac, step; + + k = L_frame / FDNS_NPTS; + + /* Formant enhancement via square root of the LPC gains */ + xn_buf[0] = (float) sqrt( gainlpc[0] ); + xn_buf[1] = (float) sqrt( gainlpc[1] ); + fac = 1.0f / min( xn_buf[0], xn_buf[1] ); + + for ( i = 1; i < FDNS_NPTS - 1; i++ ) + { + xn_buf[i + 1] = (float) sqrt( gainlpc[i + 1] ); + + if ( ( xn_buf[i - 1] <= xn_buf[i] ) && ( xn_buf[i + 1] <= xn_buf[i] ) ) + { + step = max( xn_buf[i - 1], xn_buf[i + 1] ); + step = ( 1.0f / step - fac ) / (float) ( i - l ); + xn_buf[l] = 1.0f; + fac += step; + for ( j = l + 1; j < i; j++ ) + { + xn_buf[j] = min( 1.0f, xn_buf[j] * fac ); + fac += step; + } + l = i; + } + } + + /* i = hTcxCfg->fdns_npts - 1; Completing changes to gains */ + step = min( xn_buf[i - 1], xn_buf[i] ); + step = ( 1.0f / step - fac ) / (float) ( i - l ); + xn_buf[l] = 1.0f; + fac += step; + for ( j = l + 1; j < i; j++ ) + { + xn_buf[j] = min( 1.0f, xn_buf[j] * fac ); + fac += step; + } + xn_buf[i] = 1.0f; + + /* Application of changed gains onto decoded MDCT lines */ + for ( i = j = 0; i < L_frame; j++ ) + { + for ( l = 0; l < k; i++, l++ ) + { + spectrum[i] *= xn_buf[j]; + } + } + + return; +} + +/*-------------------------------------------------------------------* + * tcxInvertWindowGrouping() + * + * + *-------------------------------------------------------------------*/ + +void tcxInvertWindowGrouping_flt( + TCX_CONFIG_HANDLE hTcxCfg, + float xn_buf[], + float spectrum[], + const int16_t L_frame, + const int16_t fUseTns, + const int16_t last_core, + const int16_t index, + const int16_t frame_cnt, + const int16_t bfi ) +{ + int16_t i, w, t_integer; + int16_t L_win, L_spec; + + if ( frame_cnt && !bfi && last_core != ACELP_CORE ) + { + /* fix sub-window overlap */ + hTcxCfg->tcx_last_overlap_mode = hTcxCfg->tcx_curr_overlap_mode; + } + + if ( ( ( !bfi ) && ( ( hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP ) || + ( ( hTcxCfg->tcx_curr_overlap_mode == FULL_OVERLAP ) && ( frame_cnt == 0 ) && ( index == 0 ) ) ) ) || + ( ( bfi ) && ( ( hTcxCfg->tcx_last_overlap_mode != FULL_OVERLAP ) && + !( hTcxCfg->tcx_curr_overlap_mode == FULL_OVERLAP ) ) ) ) + { + + /* ungroup sub-windows: deinterleave MDCT bins into separate windows */ + for ( t_integer = w = 0; w < 2; w++ ) + { + for ( i = w; i < L_frame; i += 2 ) + { + xn_buf[t_integer++] = spectrum[i]; + } + } + + mvr2r( xn_buf, spectrum, L_frame ); + + if ( hTcxCfg->fIsTNSAllowed && !bfi && fUseTns ) + { + L_win = L_frame >> 1; + L_spec = hTcxCfg->tnsConfig[0][0].iFilterBorders[0]; + + /* rearrange LF sub-window lines prior to TNS synthesis filtering */ + if ( L_spec < L_frame ) + { + mvr2r( spectrum + 8, spectrum + 16, L_spec / 2 - 8 ); + mvr2r( spectrum + L_frame / 2, spectrum + 8, 8 ); + mvr2r( spectrum + L_frame / 2 + 8, spectrum + L_spec / 2 + 8, L_spec / 2 - 8 ); + } + else + { + mvr2r( spectrum + 8, xn_buf, L_win ); + mvr2r( xn_buf, spectrum + 16, L_win - 8 ); + mvr2r( xn_buf + L_win - 8, spectrum + 8, 8 ); + } + } + } + + return; +} + + +/*-------------------------------------------------------------------* + * tcx5SpectrumInterleaving() + * + * + *-------------------------------------------------------------------*/ + +void tcx5SpectrumInterleaving( + const int16_t tcx5Size, + float *spectrum ) +{ + int16_t i; + float interleaveBuf[N_TCX10_MAX]; + + set_f( interleaveBuf, 0.0f, N_TCX10_MAX ); + + /* group sub-windows: interleave bins according to their frequencies */ + for ( i = 0; i < tcx5Size; i++ ) + { + interleaveBuf[2 * i] = spectrum[i]; + interleaveBuf[2 * i + 1] = spectrum[tcx5Size + i]; + } + + mvr2r( interleaveBuf, spectrum, 2 * tcx5Size ); + + return; +} + + +/*-------------------------------------------------------------------* + * tcx5SpectrumDeinterleaving() + * + * + *-------------------------------------------------------------------*/ + +void tcx5SpectrumDeinterleaving( + const int16_t tcx5Size, + float *spectrum ) +{ + int16_t i; + float interleaveBuf[N_TCX10_MAX]; + + set_f( interleaveBuf, 0.0f, N_TCX10_MAX ); + + /* ungroup sub-windows: interleave bins according to their frequencies */ + for ( i = 0; i < tcx5Size; i++ ) + { + interleaveBuf[i] = spectrum[2 * i]; + interleaveBuf[tcx5Size + i] = spectrum[2 * i + 1]; + } + + mvr2r( interleaveBuf, spectrum, 2 * tcx5Size ); + + return; +} + + +/*-------------------------------------------------------------------* + * tcx5TnsGrouping() + * + * + *-------------------------------------------------------------------*/ + +void tcx5TnsGrouping( + const int16_t L_frame, /* i : frame length (TCX5) */ + const int16_t L_spec, /* i : coded spec length (TCX5, derived from filter borders*/ + float *spectrum ) +{ + /* rearrange LF sub-window lines prior to TNS synthesis filtering */ + if ( L_spec < L_frame ) + { + mvr2r( spectrum + 8, spectrum + 16, L_spec - 8 ); + mvr2r( spectrum + L_frame, spectrum + 8, 8 ); + mvr2r( spectrum + L_frame + 8, spectrum + L_spec + 8, L_spec - 8 ); + } + else + { + float buff[8]; /* Buffer for the rearrangement of LF TCX5 */ + mvr2r( spectrum + L_spec, buff, 8 ); + mvr2r( spectrum + 8, spectrum + 16, L_spec - 8 ); + mvr2r( buff, spectrum + 8, 8 ); + } + + return; +} + + +/*-------------------------------------------------------------------* + * tcx5TnsUngrouping() + * + * + *-------------------------------------------------------------------*/ + +void tcx5TnsUngrouping( + const int16_t L_frame, /* i : frame length (TCX5) */ + const int16_t L_spec, /* i : coded spec length (TCX5, derived from filter borders*/ + float *spectrum, + const int16_t enc_dec /* i : 0: encoder, else decoder */ +) +{ + /* undo rearrangement of LF sub-window lines prior to TNS analysis */ + if ( L_spec < L_frame ) + { + mvr2r( spectrum + L_spec + 8, spectrum + L_frame + 8, L_spec - 8 ); + mvr2r( spectrum + 8, spectrum + L_frame, 8 ); + mvr2r( spectrum + 16, spectrum + 8, L_spec - 8 ); + set_zero( spectrum + L_spec, L_frame - L_spec ); + set_zero( spectrum + L_frame + L_spec, L_frame - L_spec ); + } + else + { + float buff[8]; /* Buffer for the rearrangement of LF TCX5 */ + + mvr2r( spectrum + 8, buff, 8 ); + + if ( enc_dec == ENC ) + { + mvr2r( spectrum + 16, spectrum + 8, L_frame - 8 ); + mvr2r( buff, spectrum + L_frame, 8 ); + } + else + { + mvr2r( spectrum + 16, spectrum + 8, L_spec - 8 ); + mvr2r( buff, spectrum + L_spec, 8 ); + } + } + + return; +} diff --git a/lib_com/prot.h b/lib_com/prot.h index 0f64e4760..d0299041a 100644 --- a/lib_com/prot.h +++ b/lib_com/prot.h @@ -8864,48 +8864,48 @@ void ReadFromBitstream( int16_t **pStream, int16_t *pnSize ); -void const *GetTnsFilterOrder( void const *p, const int16_t index, int16_t *pValue ); -void *SetTnsFilterOrder( void *p, const int16_t index, const int16_t value ); -void const *GetNumOfTnsFilters( void const *p, const int16_t index, int16_t *pValue ); -void *SetNumOfTnsFilters( void *p, const int16_t index, const int16_t value ); -void const *GetTnsEnabled( void const *p, const int16_t index, int16_t *pValue ); -void *SetTnsEnabled( void *p, const int16_t index, const int16_t value ); -void const *GetTnsEnabledSingleFilter( void const *p, const int16_t index, int16_t *pValue ); -void *SetTnsEnabledSingleFilter( void *p, const int16_t index, const int16_t value ); -void const *GetTnsFilterCoeff( void const *p, const int16_t index, int16_t *pValue ); -void *SetTnsFilterCoeff( void *p, const int16_t index, const int16_t value ); +//void const *GetTnsFilterOrder_flt( void const *p, const int16_t index, int16_t *pValue ); +//void *SetTnsFilterOrder_flt( void *p, const int16_t index, const int16_t value ); +void const *GetNumOfTnsFilters_flt (void const *p, const int16_t index, int16_t *pValue); +void *SetNumOfTnsFilters_flt( void *p, const int16_t index, const int16_t value ); +//void const *GetTnsEnabled_flt( void const *p, const int16_t index, int16_t *pValue ); +//void *SetTnsEnabled_flt( void *p, const int16_t index, const int16_t value ); +//void const *GetTnsEnabledSingleFilter_flt( void const *p, const int16_t index, int16_t *pValue ); +//void *SetTnsEnabledSingleFilter_flt( void *p, const int16_t index, const int16_t value ); +//void const *GetTnsFilterCoeff_flt( void const *p, const int16_t index, int16_t *pValue ); +//void *SetTnsFilterCoeff_flt( void *p, const int16_t index, const int16_t value ); void const *GetTnsOnWhite( void const *p, const int16_t index, int16_t *pValue ); void *SetTnsOnWhite( void *p, const int16_t index, const int16_t value ); -int16_t GetSWBTCX10TnsFilterCoeffBits( const int16_t value, const int16_t index ); -int16_t EncodeSWBTCX10TnsFilterCoeff( const int16_t value, const int16_t index ); -int16_t DecodeSWBTCX10TnsFilterCoeff( Decoder_State *st, const int16_t index, int16_t *pValue ); -int16_t GetSWBTCX20TnsFilterCoeffBits( const int16_t value, const int16_t index ); -int16_t EncodeSWBTCX20TnsFilterCoeff( const int16_t value, const int16_t index ); -int16_t DecodeSWBTCX20TnsFilterCoeff( Decoder_State *st, const int16_t index, int16_t *pValue ); - -int16_t GetWBTCX20TnsFilterCoeffBits( const int16_t value, const int16_t index ); -int16_t EncodeWBTCX20TnsFilterCoeff( const int16_t, const int16_t index ); -int16_t DecodeWBTCX20TnsFilterCoeff( Decoder_State *st, const int16_t index, int16_t *pValue ); - -int16_t GetTnsFilterOrderBitsSWBTCX10( const int16_t value, const int16_t index ); -int16_t EncodeTnsFilterOrderSWBTCX10( const int16_t value, const int16_t index ); -int16_t DecodeTnsFilterOrderSWBTCX10( Decoder_State *st, const int16_t index, int16_t *pValue ); -int16_t GetTnsFilterOrderBitsSWBTCX20( const int16_t value, const int16_t index ); -int16_t EncodeTnsFilterOrderSWBTCX20( const int16_t value, const int16_t index ); -int16_t DecodeTnsFilterOrderSWBTCX20( Decoder_State *st, const int16_t index, int16_t *pValue ); -int16_t GetTnsFilterOrderBits( const int16_t value, const int16_t index ); -int16_t EncodeTnsFilterOrder( const int16_t value, const int16_t index ); -int16_t DecodeTnsFilterOrder( Decoder_State *st, const int16_t index, int16_t *pValue ); - -void ResetTnsData( +//int16_t GetSWBTCX10TnsFilterCoeffBits_flt( const int16_t value, const int16_t index ); +//int16_t EncodeSWBTCX10TnsFilterCoeff_flt( const int16_t value, const int16_t index ); +int16_t DecodeSWBTCX10TnsFilterCoeff_flt( Decoder_State *st, const int16_t index, int16_t *pValue ); +//int16_t GetSWBTCX20TnsFilterCoeffBits_flt( const int16_t value, const int16_t index ); +//int16_t EncodeSWBTCX20TnsFilterCoeff_flt( const int16_t value, const int16_t index ); +int16_t DecodeSWBTCX20TnsFilterCoeff_flt( Decoder_State *st, const int16_t index, int16_t *pValue ); + +//int16_t GetWBTCX20TnsFilterCoeffBits_flt( const int16_t value, const int16_t index ); +//int16_t EncodeWBTCX20TnsFilterCoeff_flt( const int16_t, const int16_t index ); +int16_t DecodeWBTCX20TnsFilterCoeff_flt( Decoder_State *st, const int16_t index, int16_t *pValue ); + +//int16_t GetTnsFilterOrderBitsSWBTCX10_flt( const int16_t value, const int16_t index ); +//int16_t EncodeTnsFilterOrderSWBTCX10_flt( const int16_t value, const int16_t index ); +int16_t DecodeTnsFilterOrderSWBTCX10_flt( Decoder_State *st, const int16_t index, int16_t *pValue ); +//int16_t GetTnsFilterOrderBitsSWBTCX20_flt( const int16_t value, const int16_t index ); +//int16_t EncodeTnsFilterOrderSWBTCX20_flt( const int16_t value, const int16_t index ); +int16_t DecodeTnsFilterOrderSWBTCX20_flt( Decoder_State *st, const int16_t index, int16_t *pValue ); +//int16_t GetTnsFilterOrderBits_flt( const int16_t value, const int16_t index ); +//int16_t EncodeTnsFilterOrder_flt( const int16_t value, const int16_t index ); +int16_t DecodeTnsFilterOrder_flt( Decoder_State *st, const int16_t index, int16_t *pValue ); + +void ResetTnsData_flt( STnsData *pTnsData ); -void ClearTnsFilterCoefficients( +void ClearTnsFilterCoefficients_flt( STnsFilter *pTnsFilter ); -void InitTnsConfiguration( +void InitTnsConfiguration_flt( const int16_t bwidth, const int16_t frameLength, STnsConfig *pTnsConfig, @@ -8924,7 +8924,7 @@ int16_t DetectTnsFilt( float *predictionGain /* o : TNS prediction gain */ ); -void ApplyTnsFilter( +void ApplyTnsFilter_flt( STnsConfig const *pTnsConfig, STnsData const *pTnsData, float spectrum[], @@ -9322,19 +9322,19 @@ void decoder_LPD( float *ptr_bwe_exc /* o : excitation for SWB TBE */ ); -int16_t tcxGetNoiseFillingTilt( +int16_t tcxGetNoiseFillingTilt_flt( const float A[], const int16_t L_frame, const int16_t mode, float *noiseTiltFactor ); -void tcxFormantEnhancement( +void tcxFormantEnhancement_flt( float xn_buf[], const float *gainlpc, float spectrum[], const int16_t L_frame ); -void tcxInvertWindowGrouping( +void tcxInvertWindowGrouping_flt( TCX_CONFIG_HANDLE hTcxCfg, float xn_buf[], float spectrum[], diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index 5e9a6c986..8e8fc0175 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -131,10 +131,44 @@ Word16 deindex_lvq_fx( Word16 *p_no_scales ); +void permute_fx( + Word16 *pTmp1, /* i/o: vector whose components are to be permuted */ + const Word16 *perm /* i : permutation info (indexes that should be interchanged), max two perms */ +); + +void init_lvq_fx( + Word32 offset_scale1[][MAX_NO_SCALES + 1], + Word32 offset_scale2[][MAX_NO_SCALES + 1], + Word32 offset_scale1_p[][MAX_NO_SCALES + 1], + Word32 offset_scale2_p[][MAX_NO_SCALES + 1], + Word16 no_scales[][2], + Word16 no_scales_p[][2] +); + +Word16 deindex_lvq_cng_fx( + Word16 *index, /* i : index to be decoded, as an array of 3 short */ + Word16 *x_lvq, /* o : decoded codevector Q9*/ + Word16 idx_cv, /* i : relative mode_lvq, wrt START_CNG */ + Word16 no_bits, /* i : number of bits for lattice */ + Word32 * p_offset_scale1, + Word32 * p_offset_scale2, + Word16 * p_no_scales +); + /*========================================================================================================/ -swe_bwe_com_fx.c +swb_bwe_com_fx.c /========================================================================================================*/ +void calc_normal_length_fx( + const Word16 core, /* i : core */ + const Word16 *sp, /* i : i signal */ + const Word16 mode, /* i : i mode */ + const Word16 extl, /* i : extension layer */ + Word16 *L_swb_norm, /* o : normalize length */ + Word16 *prev_L_swb_norm, /*i/o : last normalize length */ + Word16 Q_syn +); + void calc_normal_length_fx_32( const Word16 core, /* i : core : Q0 */ const Word32 *sp, /* i : i signal : Q12 */ @@ -156,6 +190,118 @@ void hq_generic_decoding_fx( const Word16 *R ); +Word16 WB_BWE_gain_pred_fx( + Word16 *WB_fenv, /* o : WB frequency envelopes */ + const Word16 *core_dec_freq, /* i : Frequency domain core decoded signal */ + const Word16 coder_type, /* i : coding type */ + Word16 prev_coder_type, /* i : coding type of last frame */ + Word16 prev_WB_fenv, /* i : envelope for last frame */ + Word16 *voice_factors, /* i : voicing factors Q15 */ + const Word16 pitch_buf[], /* i : pitch buffer Q6 */ + Word32 last_core_brate, /* i : previous frame core bitrate */ + Word16 last_wb_bwe_ener, /* i : previous frame wb bwe signal energy */ + Word16 Q_syn + , Word16 last_extl_fx, + Word16 tilt_wb_fx +); + +Word32 calc_tilt_bwe_fx( /* o : Tilt in Q24 */ + const Word16 *sp0, /* i : i signal */ + const Word16 exp, /* i : Exp of inp signal */ + const Word16 N /* i : signal length */ +); + +void calc_norm_envelop_fx( + const Word16 SWB_signal[], /* i : SWB spectrum Q_syn*/ + Word32 *envelope, /* o : normalized envelope Q_syn*/ + const Word16 L_swb_norm, /* i : length of envelope Q0 */ + const Word16 SWB_flength, /* i : Length of i /output */ + const Word16 st_offset /* i : offset */ +); + +void WB_BWE_decoding_fx( + const Word16 *core_dec_freq, /* i : Frequency domain core decoded signal */ + Word16 *WB_fenv, /* i : WB frequency envelopes */ + Word32 *WB_signal32, /* o : WB signal in MDCT domain */ + const Word16 WB_flength, /* i : Length of i /output */ + const Word16 mode, /* i : classification for WB signal */ + const Word16 last_extl, /* i : extl. layer for last frame */ + Word32 *prev_Energy, /* i/o: energy for last frame */ + Word16 *prev_WB_fenv, /* i/o: envelope for last frame */ + Word16 *prev_L_wb_norm, /* i/o: length for last frame wb norm */ + const Word16 extl, /* i : extension layer */ + const Word16 coder_type, /* i : coding type */ + const Word32 total_brate, /* i : core layer bitrate */ + Word16 *Seed, /* i/o: random generator seed */ + Word16 *prev_flag, /* i/o: attenu flag of last frame */ + Word16 prev_coder_type, /* i : coding type of last frame */ + Word16 Q_syn, + Word16 *Q_syn_hb /*o : Q value of WB_signal_32 */ +); + +void SWB_BWE_decoding_fx( + const Word16 *core_dec_freq, /* i : Frequency domain core decoded signal */ + Word16 *SWB_fenv, /* i/o: SWB frequency envelopes */ + Word32 *SWB_signal, /* o : SWB signal in MDCT domain */ + const Word16 SWB_flength, /* i : Length of i /output */ + const Word16 mode, /* i : classification for SWB signal */ + Word16 *frica_flag, /* o : fricative signal flag */ + Word16 *prev_Energy, /* i/o: energy for last frame */ + Word16 *prev_SWB_fenv, /* i/o: envelope for last frame */ + Word16 *prev_L_swb_norm, /* i/o: length for last frame wb norm */ + const Word16 tilt_nb, /* i : tilt of synthesis wb signal */ + Word16 *Seed, /* i/o: random generator seed */ + const Word16 st_offset, /* i : offset value due to different core */ + Word16 *prev_weight, /* i/o: excitation weight value of last frame */ + const Word16 extl, /* i : extension layer */ + Word16 Q_syn + , const Word16 last_extl /* i : extension layer of last frame */ +); + +void time_envelop_shaping_fx( + Word16 werr[], /* i/o: SHB synthesis Q_synth*/ + Word32 SWB_tenv[], /* i/o: frequency envelope Q15*/ + const Word16 L, /* i : frame length */ + Word16 *Q_synth +); + +void time_reduce_pre_echo_fx( + const Word16 *synth, /* i : ACELP core synthesis Q_syn*/ + Word16 *error, /* i/o: SHB BWE synthesis Q0*/ + Word16 prev_td_energy, /* o : last td energy Q0*/ + const Word16 L, /* i : subframe length */ + Word16 Q_syn, + Word16 Q_synth +); + +void calc_norm_envelop_fx_32( + const Word32 SWB_signal_fx[], /* i : SWB spectrum : Q12 */ + Word32 *envelope_fx, /* o : normalized envelope : Q16 */ + const Word16 L_swb_norm, /* i : length of envelope : Q0 */ + const Word16 SWB_flength, /* i : Length of i /output : Q0 */ + const Word16 st_offset /* i : offset : Q0 */ +); + +void hq_generic_decoding_fx( + const Word16 HQ_mode, /* i : HQ mode */ + Word32 *coeff_out1_fx, /* i/o: BWE i & temporary buffer */ + const Word16 *hq_generic_fenv_fx, /* i : SWB frequency envelopes */ + Word32 *coeff_out_fx, /* o : SWB signal in MDCT domain */ + const Word16 hq_generic_offset, /* i : frequency offset for representing hq generic*/ + Word16 *prev_L_swb_norm, /* i/o: last normalize length */ + const Word16 hq_generic_exc_clas, /* i : bwe excitation class */ + const Word16 *R +); + +void save_old_syn_fx( + const Word16 L_frame, /* i : frame length */ + const Word16 syn[], /* i : ACELP synthesis */ + Word16 old_syn[], /* o : old synthesis buffer */ + Word16 old_syn_mem[], /* i/o: old synthesis buffer memory */ + const Word16 preemph_fac, /* i : preemphasis factor */ + Word16 *mem_deemph /* i/o: deemphasis filter memory */ +); + /*========================================================================================================/ lognorm_fx.c /========================================================================================================*/ @@ -2607,4 +2753,282 @@ Word32 DTFS_getEngy_band_wb_fx( Word16 hband ); +//tns_base.c +/** Init TNS configuration. + * Fills STnsConfig structure with sensible content. + * @param nSampleRate Sampling rate of the i . + * @param nFrameLength Frame length. + * @param pTnsConfig TNS configuration to be initialized. + * @return 0 on success, otherwise 1. + */ +void InitTnsConfiguration( + const Word16 bwidth, + const Word16 frameLength, + STnsConfig* pTnsConfig, + const Word16 igfStopFreq, + const Word32 total_brate, + const Word16 element_mode, + const Word16 is_mct +); + +/** Modify spectrum using TNS filter. + * Modifies spectrum unsing TNS filter defined by pTnsData. + * If fIsAnalyses is true considers spectrum to be + * an i of encoder and returns residum. + * If fIsAnalyses is false considers spectrum to be + * a residum from decoder and returns output spectrum. + * @param pTnsConfig TNS configuration. + * @param pTnsData TNS data describing filters. + * @param spectrum Input/output spectrum. + * @param fIsAnalysis Defines if TNS filter is applied + * in encoder (TRUE) or in decoder (FALSE). + * @return 0 on success, otherwise 1. + */ +void ApplyTnsFilter( + STnsConfig const * pTnsConfig, + STnsData const * pTnsData, + Word32 spectrum[], + const Word8 fIsAnalysis +); + +Word16 ITF_Detect_fx(Word32 const pSpectrum[], + const Word16 startLine, + const Word16 stopLine, + const Word16 maxOrder, + Word16* A, + Word16* Q_A, + Word16* predictionGain, + Word16* curr_order, + Word16 Q); + +void ITF_Apply_fx(Word32 spectrum[], + Word16 startLine, Word16 stopLine, const Word16* A, + Word16 Q_A, + Word16 curr_order); + +void const * GetTnsFilterCoeff(void const * p, const Word16 index, Word16 * pValue); + +void * SetTnsFilterCoeff(void * p, const Word16 index, const Word16 value); + +Word16 GetSWBTCX20TnsFilterCoeffBits(const Word16 value, const Word16 index); + +Word16 EncodeSWBTCX20TnsFilterCoeff(const Word16 value, const Word16 index); + +Word16 DecodeSWBTCX20TnsFilterCoeff(Decoder_State *st, const Word16 index, Word16 * pValue); + +Word16 GetSWBTCX10TnsFilterCoeffBits(const Word16 value, const Word16 index); + +Word16 EncodeSWBTCX10TnsFilterCoeff(const Word16 value, const Word16 index); + +Word16 DecodeSWBTCX10TnsFilterCoeff(Decoder_State *st, const Word16 index, Word16 * pValue); + +Word16 GetWBTCX20TnsFilterCoeffBits(const Word16 value, const Word16 index); + +Word16 EncodeWBTCX20TnsFilterCoeff(const Word16 value, const Word16 index); + +Word16 DecodeWBTCX20TnsFilterCoeff(Decoder_State *st, const Word16 index, Word16 * pValue); + +void const * GetTnsFilterOrder(void const * p, const Word16 index, Word16 * pValue); + +void * SetTnsFilterOrder(void * p, const Word16 index, const Word16 value); + +Word16 GetTnsFilterOrderBitsSWBTCX20(const Word16 value, const Word16 index); + +Word16 EncodeTnsFilterOrderSWBTCX20(const Word16 value, const Word16 index); + +Word16 DecodeTnsFilterOrderSWBTCX20(Decoder_State *st, const Word16 index, Word16 * pValue); + +Word16 GetTnsFilterOrderBitsSWBTCX10(const Word16 value, const Word16 index); + +Word16 EncodeTnsFilterOrderSWBTCX10(const Word16 value, const Word16 index); + +Word16 DecodeTnsFilterOrderSWBTCX10(Decoder_State *st, const Word16 index, Word16 * pValue); + +Word16 GetTnsFilterOrderBits(const Word16 value, const Word16 index); + +Word16 EncodeTnsFilterOrder(const Word16 value, const Word16 index); + +Word16 DecodeTnsFilterOrder(Decoder_State *st, const Word16 index, Word16 * pValue); + +void const * GetNumOfTnsFilters(void const * p, const Word16 index, Word16 * pValue); + +void * SetNumOfTnsFilters(void * p, const Word16 index, Word16 value); + +void const * GetTnsEnabled(void const * p, const Word16 index, Word16 * pValue); + +void * SetTnsEnabled(void * p, const Word16 index, const Word16 value); + +void const * GetTnsEnabledSingleFilter(void const * p, const Word16 index, Word16 * pValue); + +void * SetTnsEnabledSingleFilter(void * p, const Word16 index, const Word16 value); + +/*tns_base.h*/ +/** Reset TNS data. + * Resets TNS data to the initial state. + * @param pTnsData pointer to a TNS data to be reset. + */ +void ResetTnsData(STnsData * pTnsData); + +/** Clear TNS filter data. + * Resets TNS filter order and all coefficients to 0. + * @param pTnsFilter pointer to a TNS filter to be cleared. + */ +void ClearTnsFilterCoefficients(STnsFilter * pTnsFilter); + +/*========================================================================================================/ +gp_clips_fx.c +/========================================================================================================*/ + +void init_gp_clip_fx( + Word16 mem[] /* o : memory of gain of pitch clipping algorithm */ +); + +Word16 gp_clip_fx( + const Word16 element_mode, /* i : element mode */ + const Word32 core_brate, /* i : core bitrate */ + const Word16* voicing, /* i : normalized correlations (from OL pitch) */ + const Word16 i_subfr, /* i : subframe index */ + const Word16 coder_type, /* i : type of coder */ + const Word16 xn[], /* i : target vector */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + const Word16 Q_new /* i : scaling factor */ +); + +void gp_clip_test_isf_fx( + const Word16 element_mode, /* i : element mode */ + const Word32 core_brate, /* i : core bitrate */ + const Word16 isf[], /* i : isf values (in frequency domain) */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + const Word16 Opt_AMR_WB /* i : flag indicating AMR-WB IO mode */ +); + +void gp_clip_test_gain_pit_fx( + const Word16 element_mode, /* i : element mode */ + const Word32 core_brate, /* i : core bitrate */ + const Word16 gain_pit, /* i : gain of quantized pitch Q14 */ + Word16 mem[] /* i/o: memory of gain of pitch clipping algorithm 1Q14 */ +); + +Word16 Mode2_gp_clip( + const Word16 *voicing, /* i : normalized correlations (from OL pitch) */ + const Word16 i_subfr, /* i : subframe index */ + const Word16 coder_type, /* i : type of coder */ + const Word16 xn[], /* i : target vector */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + const Word16 L_subfr, + const Word16 Q_xn /* i : xn data format */ +); + +void gp_clip_test_lsf_fx( + const Word16 element_mode, /* i : element mode */ + const Word16 lsf[], /* i : lsf values (in frequency domain) 14Q1*1.28 */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + const Word16 m /* i : dimension of lsf */ +); + +/*========================================================================================================/ +nelp_enc_fx.c +/========================================================================================================*/ + +void quantize_uvg_fx( + Word16 *G, + Word16 *iG1, + Word16 *iG2, + Word16 *quantG, + Word16 bandwidth +); + +void nelp_encoder_fx( + Encoder_State *st_fx, /* i/o: encoder state */ + Word16 *in_fx, /* i : residual signal */ + Word16 *exc_fx, /* o : NELP quantized excitation signal */ + Word16 *qIn1 + , Word16 reduce_gains +); + +/*========================================================================================================/ +swb_bwe_enc_lr_fx.c +/========================================================================================================*/ + +void swb_bwe_enc_lr_fx( + Encoder_State *st_fx, /* i/o: encoder state structure */ + const Word32 L_m_core[], /* i : lowband synthesis */ + Word16 QsL, + const Word32 L_m_orig[], /* i/o: scaled orig signal (MDCT) */ + Word32 L_m[], /* o : highband synthesis with lowband zeroed */ + const Word32 L_total_brate, /* i : total bitrate for selecting subband pattern */ + Word16 BANDS_fx, /* i : Total number of Subbands in a frame */ + Word16 *band_start_fx, /* i : band start of each SB */ + Word16 *band_end_fx, /* i : band end of each SB */ + Word32 *L_band_energy, /* i : band_energy of each SB */ + Word16 Qbe, /* i : Q value of band energy */ + Word16 *p2a_flags_fx, /* i : HF tonal indicator */ + const Word16 hqswb_clas_fx, /* i : HQ_NORMAL2 or HQ_HARMONIC mode */ + Word16 lowlength_fx, /* i : lowband length */ + Word16 highlength_fx, /* i : highband length */ + Word16 *prev_frm_index_fx, /* i/o: previous frame lag index for harmonic mode */ + const Word16 har_bands_fx, /* i : Number of LF harmonic bands */ + Word16 *prev_frm_hfe2, /* i/o: */ + Word16 *prev_stab_hfe2, /* i/o: */ + const Word16 band_width_fx[], /* i : band_width information */ + const Word32 L_y2_ni[], /* i : band_width information */ + Word16 *ni_seed_fx /* i/o: random seed for search buffer NI */ +); + +/*========================================================================================================/ +isf_enc_amr_wb_fx.c +/========================================================================================================*/ + +void isf_enc_amr_wb_fx( + Encoder_State* st, /* i/o: state structure */ + Word16* isf_new, /* i/o: quantized ISF vector */ + Word16* isp_new, /* i/o: ISP vector to quantize/quantized */ + Word16* Aq /* o : quantized A(z) for 4 subframes */ +); + +/*========================================================================================================/ +detect_transient_fx.c +/========================================================================================================*/ + +Word16 detect_transient_fx( + const Word16 *in_fx, /*Q_new */ + const Word16 L, + Word16 Q_new, + Encoder_State *st_fx +); + +/*========================================================================================================/ +codec_tcx_common.c +/========================================================================================================*/ + +Word16 tcxGetNoiseFillingTilt( + const Word16 A[], + const Word16 lpcorder, + const Word16 L_frame, + const Word16 mode, + Word16* noiseTiltFactor +); + +void tcxFormantEnhancement( + Word16 xn_buf[], + const Word16 gainlpc[], + const Word16 gainlpc_e[], + Word32 spectrum[], + Word16* spectrum_e, + const Word16 L_frame, + const Word16 L_frameTCX +); + +void tcxInvertWindowGrouping( + TCX_CONFIG_HANDLE hTcxCfg, /* i : configuration of TCX */ + Word32 xn_buf[], + Word32 spectrum[], + const Word16 L_frame, + const Word8 fUseTns, + const Word16 last_core, + const Word16 index, + const Word16 frame_cnt, + const Word16 bfi +); + #endif \ No newline at end of file diff --git a/lib_com/rom_basop_util.c b/lib_com/rom_basop_util.c index b0c91f723..e6b63e54a 100644 --- a/lib_com/rom_basop_util.c +++ b/lib_com/rom_basop_util.c @@ -813,4 +813,17 @@ const PWord16* getSineWindowTable(Word16 length) assert(p != NULL); return p; -} \ No newline at end of file +} + +const Word16 InvIntTable[65] = +{ + 0x7FFF, + 0x7FFF, 0x4000, 0x2AAB, 0x2000, 0x199A, 0x1555, 0x1249, 0x1000, + 0x0E39, 0x0CCD, 0x0BA3, 0x0AAB, 0x09D9, 0x0925, 0x0889, 0x0800, + 0x0788, 0x071C, 0x06BD, 0x0666, 0x0618, 0x05D1, 0x0591, 0x0555, + 0x051F, 0x04EC, 0x04BE, 0x0492, 0x046A, 0x0444, 0x0421, 0x0400, + 0x03E1, 0x03C4, 0x03A8, 0x038E, 0x0376, 0x035E, 0x0348, 0x0333, + 0x031F, 0x030C, 0x02FA, 0x02E9, 0x02D8, 0x02C8, 0x02B9, 0x02AB, + 0x029D, 0x028F, 0x0283, 0x0276, 0x026A, 0x025F, 0x0254, 0x0249, + 0x023F, 0x0235, 0x022B, 0x0222, 0x0219, 0x0211, 0x0208, 0x0200 +}; \ No newline at end of file diff --git a/lib_com/rom_basop_util.h b/lib_com/rom_basop_util.h index 18c4bf701..188af4013 100644 --- a/lib_com/rom_basop_util.h +++ b/lib_com/rom_basop_util.h @@ -51,4 +51,6 @@ extern const PWord16 SineTable320[161]; void BASOP_getTables(const PWord16 **ptwiddle, const PWord16 **sin_twiddle, Word16 *sin_step, Word16 length); const PWord16* getSineWindowTable(Word16 length); +extern const Word16 InvIntTable[65]; + #endif diff --git a/lib_com/rom_com.c b/lib_com/rom_com.c index 75157e8f4..ff4569677 100644 --- a/lib_com/rom_com.c +++ b/lib_com/rom_com.c @@ -41,6 +41,7 @@ #include "prot.h" #include "basop_util.h" #include "wmc_auto.h" +#include "prot_fx2.h" /* clang-format off */ @@ -18683,6 +18684,8 @@ const float Mean_env_tr[5] = { 27.23f, 23.81f, 23.87f, 19.51f }; const float gain_table_SWB_BWE[NB_SWB_SUBBANDS] = {-0.4f, 0.1f, 0.6f, 1.1f}; +const Word16 gain_table_SWB_BWE_fx[NB_SWB_SUBBANDS] = { -6554/*-0.4f*/, 1638/*0.1f*/, 9830/*0.6f*/, 18022/*1.1f*/ }; /* Q14 */ + const int16_t bits_lagIndices_modeNormal[NB_SWB_SUBBANDS] = {2, 2, 1, 1}; const int16_t subband_offsets_12KBPS[NB_SWB_SUBBANDS] = {SWB_SB_OFF0_12KBPS, SWB_SB_OFF1_12KBPS, SWB_SB_OFF2_12KBPS, SWB_SB_OFF3_12KBPS}; const int16_t subband_offsets_16KBPS[NB_SWB_SUBBANDS] = {SWB_SB_OFF0_16KBPS, SWB_SB_OFF1_16KBPS, SWB_SB_OFF2_16KBPS, SWB_SB_OFF3_16KBPS}; @@ -20225,6 +20228,8 @@ const int16_t lim_neg_inv_tbl_fx[MAX_SPLITS + 1 ] = -5462, -4681, -4096, -3641, -3277 }; +const Word16 Idx2Freq_Tbl[] = { 6554/*12.8*512*/, 48 * 512, 13108/*25.6*512*/, 32 * 512, 16 * 512, 8 * 512 }; /* in Q9 */ + const int16_t fg_inv_tbl_fx [HQ_MAX_BAND_LEN/8 + 1 ] = { /* i/8 , slice of inv_tbl_fx , Q15 */ 0, @@ -23308,6 +23313,10 @@ const float SmoothingWin_NB2[16] = const float bp1_num_coef_wb[5] = {0.9329833984375,0,-1.865966796875,0,0.9329833984375}; const float bp1_den_coef_wb[5] = {1,0,-1.8614501953125,0,0.8704833984375}; +const Word16 bp1_num_coef_wb_fx[5] = { 15286, 0, -30572, 0, 15286, }; /* Q14 */ +const Word16 bp1_den_coef_wb_fx[5] = { 16384, 0, -30498, 0, 14262, }; /* Q14 */ + + const float shape1_num_coef[11] = { 0.959381103515625f, -0.074554443359375f, -0.4161376953125f, 0.1317138671875f, @@ -23315,6 +23324,13 @@ const float shape1_num_coef[11] = -0.023681640625f, 0.03192138671875f, 0.012176513671875f }; +const Word16 shape1_num_coef_fx[11] = /* Q15 */ +{ + 31437, -2443, -13636, 4316, + -10188, 48, 2639, -3575, + -776, 1046, 399 +}; + const float shape1_den_coef[11] = { 1, 0.0897216796875f, -0.373443603515625f, 0.123046875f, -0.293243408203125f, @@ -23322,6 +23338,12 @@ const float shape1_den_coef[11] = 0.026153564453125f, 0.007720947265625f }; +const Word16 shape1_den_coef_fx[11] = { 32767, /* Q15 */ + 2940, -12237, 4032, -9609, + -1998, 2335, -3900, -1595, + 857, 253 +}; + const float shape2_num_coef[11] = { 0.938720703125f, 0.000946044921875f, -0.295989990234375f, 0.2904052734375f, @@ -23329,6 +23351,13 @@ const float shape2_num_coef[11] = 0.10003662109375f, -0.001922607421875f, 0.034027099609375f }; +const Word16 shape2_num_coef_fx[11] = /* Q15 */ +{ + 30760, 31, -9699, 9516, + -5878, -7249, -10468, 442, + 3278, -63, 1115 +}; + const float shape2_den_coef[11] = { 1, 0.488861083984375f, -0.02716064453125f, 0.390594482421875f, 0.07159423828125f, @@ -23336,6 +23365,12 @@ const float shape2_den_coef[11] = -0.0455322265625f, -0.00927734375f }; +const Word16 shape2_den_coef_fx[11] = { 32767, /* Q15 */ + 16019, -890, 12799, 2346, + -6985, -13192, -5795, -949, + -1492, -304 +}; + const float shape3_num_coef[11] = { 0.936431884765625f, -0.011688232421875f, -0.303253173828125f, -0.293121337890625f, @@ -23343,6 +23378,13 @@ const float shape3_num_coef[11] = 0.098846435546875f, 0.0003662109375f, 0.0364990234375f }; +const Word16 shape3_num_coef_fx[11] = /* Q15 */ +{ + 30685, -383, -9937, -9605, + -5997, 7611, -10393, -355, + 3239, 12, 1196 +}; + const float shape3_den_coef[11] = { 1, -0.50347900390625f, -0.027801513671875f, -0.395111083984375f, 0.06976318359375f, @@ -23350,6 +23392,14 @@ const float shape3_den_coef[11] = 0.0482177734375f, -0.008331298828125f }; +const Word16 shape3_den_coef_fx[11] = { 32767, /* Q15 */ + -16498, -911, -12947, 2286, + 7430, -13385, 6066, -1182, + 1580, -273 +}; + + + const float txlpf1_num_coef[11] = { 0.016845703125, 0.024169921875, 0.062744140625, 0.0831298828125, 0.1124267578125, @@ -23357,6 +23407,13 @@ const float txlpf1_num_coef[11] = 0.016845703125 }; +const Word16 txlpf1_num_coef_fx[11] = /* Q13 */ +{ + 138, 198, 514, 681, 921, + 964, 921, 681, 514, 198, + 138, +}; + const float txlpf1_den_coef[11] = { 1, -2.3126220703125, 3.8590087890625, -3.8023681640625, 2.989990234375, @@ -23364,6 +23421,13 @@ const float txlpf1_den_coef[11] = 0.00048828125 }; +const Word16 txlpf1_den_coef_fx[11] = /* Q13 */ +{ + 8192,-18945, 31613,-31149, 24494, + -12753, 5528, -1436, 347, -25, + 4, +}; + const float txhpf1_num_coef[11] = { 0.016845703125, -0.024169921875, 0.062744140625, -0.0831298828125, 0.1124267578125, @@ -23371,25 +23435,52 @@ const float txhpf1_num_coef[11] = 0.016845703125 }; +const Word16 txhpf1_num_coef_fx[11] = /* Q13 */ +{ + 138, -198, 514, -681, 921, + -964, 921, -681, 514, -198, + 138, +}; + const float txhpf1_den_coef[11] = { 1, 2.3126220703125, 3.8590087890625, 3.8023681640625, 2.989990234375, 1.5567626953125, 0.6748046875, 0.17529296875, 0.0423583984375, 0.0030517578125, 0.00048828125 }; + +const Word16 txhpf1_den_coef_fx[11] = /* Q13 */ +{ + 8192, 18945, 31613, 31149, 24494, + 12753, 5528, 1436, 347, 25, + 4, +}; + /* NELP filter coefficients */ -const float bp1_num_coef_nb_fx_order7[8] = +const float bp1_num_coef_nb_fx_order7_flt[8] = { 0.180780569293627f, 0.821512462016641f, 1.901786162198923f, 2.798216464912205f, 2.798216464912205f, 1.901786162198923f, 0.821512462016641f, 0.180780569293627f }; -const float bp1_den_coef_nb_fx_order7[8] = +const Word16 bp1_num_coef_nb_fx_order7[8] = +{ + /* Q = BP1_COEF_NB_QF_ORDER7 = 13 */ + 1481, 6730, 15579, 22923, 22923, 15579, 6730, 1481, + +}; + +const float bp1_den_coef_nb_fx_order7_flt[8] = { 1.0f, 1.972212566911875f, 2.906981567843655f, 2.667903533650106f, 1.784691945273023f, 0.807367818229743f, 0.232764318343094f, 0.032669566591295f }; +const Word16 bp1_den_coef_nb_fx_order7[8] = +{ + /* Q = BP1_COEF_NB_QF_ORDER7 = 13 */ + 8192, 16156, 23814, 21855, 14620, 6614, 1907, 268, +}; /* order 8 LPF for nelp frames when non-native sampling freq inputs used with -max_band NB */ /* used to suppress frequencies above 4kHz present at the output of filters in pre_proc() */ @@ -26947,7 +27038,7 @@ const ParamsBitMap tnsSWBTCX20FilterCoeffBitMap = { 1, { - { 0, GetSWBTCX20TnsFilterCoeffBits, TRUE, GetTnsFilterCoeff, SetTnsFilterCoeff, EncodeSWBTCX20TnsFilterCoeff, DecodeSWBTCX20TnsFilterCoeff, NULL } /* TNS filter coefficients */ + { 0, GetSWBTCX20TnsFilterCoeffBits, TRUE, GetTnsFilterCoeff, SetTnsFilterCoeff, EncodeSWBTCX20TnsFilterCoeff, DecodeSWBTCX20TnsFilterCoeff_flt, NULL } /* TNS filter coefficients */ } }; @@ -26955,7 +27046,7 @@ const ParamsBitMap tnsSWBTCX10FilterCoeffBitMap = { 1, { - { 0, GetSWBTCX10TnsFilterCoeffBits, TRUE, GetTnsFilterCoeff, SetTnsFilterCoeff, EncodeSWBTCX10TnsFilterCoeff, DecodeSWBTCX10TnsFilterCoeff, NULL } /* TNS filter coefficients */ + { 0, GetSWBTCX10TnsFilterCoeffBits, TRUE, GetTnsFilterCoeff, SetTnsFilterCoeff, EncodeSWBTCX10TnsFilterCoeff, DecodeSWBTCX10TnsFilterCoeff_flt, NULL } /* TNS filter coefficients */ } }; @@ -26963,7 +27054,7 @@ const ParamsBitMap tnsSWBTCX20FilterBitMap = { 1, { - { 0, GetTnsFilterOrderBitsSWBTCX20, FALSE, GetTnsFilterOrder, SetTnsFilterOrder, EncodeTnsFilterOrderSWBTCX20, DecodeTnsFilterOrderSWBTCX20, &tnsSWBTCX20FilterCoeffBitMap } /* TNS filter order */ + { 0, GetTnsFilterOrderBitsSWBTCX20, FALSE, GetTnsFilterOrder, SetTnsFilterOrder, EncodeTnsFilterOrderSWBTCX20, DecodeTnsFilterOrderSWBTCX20_flt, &tnsSWBTCX20FilterCoeffBitMap } /* TNS filter order */ } }; @@ -26971,7 +27062,7 @@ const ParamsBitMap tnsSWBTCX10FilterBitMap = { 1, { - { 0, GetTnsFilterOrderBitsSWBTCX10, FALSE, GetTnsFilterOrder, SetTnsFilterOrder, EncodeTnsFilterOrderSWBTCX10, DecodeTnsFilterOrderSWBTCX10, &tnsSWBTCX10FilterCoeffBitMap } /* TNS filter order */ + { 0, GetTnsFilterOrderBitsSWBTCX10, FALSE, GetTnsFilterOrder, SetTnsFilterOrder, EncodeTnsFilterOrderSWBTCX10, DecodeTnsFilterOrderSWBTCX10_flt, &tnsSWBTCX10FilterCoeffBitMap } /* TNS filter order */ } }; @@ -26979,7 +27070,7 @@ const ParamsBitMap tnsSWBTCX20BitMap = { 1, { - { 1, NULL, FALSE, GetNumOfTnsFilters, SetNumOfTnsFilters, NULL, NULL, &tnsSWBTCX20FilterBitMap } /* Number of TNS filters */ + { 1, NULL, FALSE, GetNumOfTnsFilters_flt, SetNumOfTnsFilters_flt, NULL, NULL, &tnsSWBTCX20FilterBitMap } /* Number of TNS filters */ } }; @@ -26996,7 +27087,7 @@ const ParamsBitMap tnsSWBTCX10BitMap = { 1, { - { 1, NULL, FALSE, GetNumOfTnsFilters, SetNumOfTnsFilters, NULL, NULL, &tnsSWBTCX10FilterBitMap } /* Number of TNS filters */ + { 1, NULL, FALSE, GetNumOfTnsFilters_flt, SetNumOfTnsFilters_flt, NULL, NULL, &tnsSWBTCX10FilterBitMap } /* Number of TNS filters */ } }; @@ -27013,7 +27104,7 @@ const ParamsBitMap tnsWBTCX20FilterCoeffBitMap = { 1, { - { 0, GetWBTCX20TnsFilterCoeffBits, TRUE, GetTnsFilterCoeff, SetTnsFilterCoeff, EncodeWBTCX20TnsFilterCoeff, DecodeWBTCX20TnsFilterCoeff, NULL } /* TNS filter coefficients */ + { 0, GetWBTCX20TnsFilterCoeffBits, TRUE, GetTnsFilterCoeff, SetTnsFilterCoeff, EncodeWBTCX20TnsFilterCoeff, DecodeWBTCX20TnsFilterCoeff_flt, NULL } /* TNS filter coefficients */ } }; @@ -27022,7 +27113,7 @@ const ParamsBitMap tnsWBTCX20FilterBitMap = { 1, { - { 0, GetTnsFilterOrderBits, FALSE, GetTnsFilterOrder, SetTnsFilterOrder, EncodeTnsFilterOrder, DecodeTnsFilterOrder, &tnsWBTCX20FilterCoeffBitMap } /* TNS filter order */ + { 0, GetTnsFilterOrderBits, FALSE, GetTnsFilterOrder, SetTnsFilterOrder, EncodeTnsFilterOrder, DecodeTnsFilterOrder_flt, &tnsWBTCX20FilterCoeffBitMap } /* TNS filter order */ } }; @@ -27042,7 +27133,7 @@ const ParamsBitMap tnsOnWhiteSWBTCX20BitMap = 2, { { 1, NULL, TRUE, GetTnsOnWhite, SetTnsOnWhite, NULL, NULL, NULL }, /* TNS Enabled/Disable */ - { 1, NULL, FALSE, GetNumOfTnsFilters, SetNumOfTnsFilters, NULL, NULL, &tnsSWBTCX20FilterBitMap } + { 1, NULL, FALSE, GetNumOfTnsFilters_flt, SetNumOfTnsFilters_flt, NULL, NULL, &tnsSWBTCX20FilterBitMap } } }; @@ -27059,7 +27150,7 @@ const ParamsBitMap tnsOnWhiteSWBTCX10BitMap = 2, { { 1, NULL, TRUE, GetTnsOnWhite, SetTnsOnWhite, NULL, NULL, NULL }, /* TNS on whitened spectra */ - { 1, NULL, FALSE, GetNumOfTnsFilters, SetNumOfTnsFilters, NULL, NULL, &tnsSWBTCX10FilterBitMap } + { 1, NULL, FALSE, GetNumOfTnsFilters_flt, SetNumOfTnsFilters_flt, NULL, NULL, &tnsSWBTCX10FilterBitMap } } }; @@ -27076,7 +27167,7 @@ const ParamsBitMap tnsEnabledOnWhiteSWBTCX10BitMap = /** * 4 bit resolution TNS coefficients. */ -const float tnsCoeff4[16]= +const float tnsCoeff4_flt[16]= { -0.99573418F, /* = sin(-8*(EVS_PI/2.0)/(8 + 0.5)) */ -0.96182564F, /* = sin(-7*(EVS_PI/2.0)/(8 + 0.5)) */ @@ -27096,6 +27187,26 @@ const float tnsCoeff4[16]= 0.99452190F /* = sin(7*(EVS_PI/2.0)/(8 - 0.5)) */ }; +const Word16 tnsCoeff4[16] = +{ + -32628/*-0.99573418F Q15*/, /* = sin(-8*(PI/2.0)/(8 + 0.5)) */ + -31517/*-0.96182564F Q15*/, /* = sin(-7*(PI/2.0)/(8 + 0.5)) */ + -29333/*-0.89516329F Q15*/, + -26149/*-0.79801723F Q15*/, + -22076/*-0.67369564F Q15*/, + -17250/*-0.52643216F Q15*/, + -11837/*-0.36124167F Q15*/, + -6021/*-0.18374952F Q15*/, /* = sin(-1*(PI/2.0)/(8 + 0.5)) */ + 0/* 0.00000000F Q15*/, /* = sin(0*(PI/2.0)/(8 + 0.5)) */ + 6813/* 0.20791169F Q15*/, /* = sin(1*(PI/2.0)/(8 - 0.5)) */ + 13328/* 0.40673664F Q15*/, + 19261/* 0.58778525F Q15*/, + 24351/* 0.74314483F Q15*/, + 28378/* 0.86602540F Q15*/, + 31164/* 0.95105652F Q15*/, /* = sin(6*(PI/2.0)/(8 - 0.5)) */ + 32588/* 0.99452190F Q15*/ /* = sin(7*(PI/2.0)/(8 - 0.5)) */ +}; + /*----------------------------------------------------------------------------------* * IGF settings for each bitrate @@ -29766,5 +29877,8 @@ const Word16 cos_diff_table[512] = }; +const Word32 bwMode2fs[4] = { 8000, 16000, 32000, 48000 }; + + /* clang-format on */ diff --git a/lib_com/rom_com.h b/lib_com/rom_com.h index 08abfedda..6f0259472 100644 --- a/lib_com/rom_com.h +++ b/lib_com/rom_com.h @@ -1047,7 +1047,10 @@ extern const Word16 env_stab_tp_fx[2][2]; /*----------------------------------------------------------------------------------* * SWB BWE for LR MDCT core *----------------------------------------------------------------------------------*/ + extern const float gain_table_SWB_BWE[NB_SWB_SUBBANDS]; +extern const Word16 gain_table_SWB_BWE_fx[NB_SWB_SUBBANDS]; + /* HQ_NORMAL mode */ extern const int16_t bits_lagIndices_modeNormal[NB_SWB_SUBBANDS]; extern const int16_t subband_offsets_12KBPS[NB_SWB_SUBBANDS]; @@ -1070,19 +1073,47 @@ extern const int16_t subband_search_offsets_16p4kbps_Har[NB_SWB_SUBBANDS_HAR_SEA /* NELP filter coefficients */ extern const float bp1_num_coef_wb[5]; +extern const Word16 bp1_num_coef_wb_fx[5]; + extern const float bp1_den_coef_wb[5]; +extern const Word16 bp1_den_coef_wb_fx[5]; + extern const float shape1_num_coef[11]; +extern const Word16 shape1_num_coef_fx[11]; + extern const float shape1_den_coef[11]; +extern const Word16 shape1_den_coef_fx[11]; + extern const float shape2_num_coef[11]; +extern const Word16 shape2_num_coef_fx[11]; + extern const float shape2_den_coef[11]; +extern const Word16 shape2_den_coef_fx[11]; + extern const float shape3_num_coef[11]; +extern const Word16 shape3_num_coef_fx[11]; + extern const float shape3_den_coef[11]; +extern const Word16 shape3_den_coef_fx[11]; + extern const float txlpf1_num_coef[11]; +extern const Word16 txlpf1_num_coef_fx[11]; + extern const float txlpf1_den_coef[11]; +extern const Word16 txlpf1_den_coef_fx[11]; + extern const float txhpf1_num_coef[11]; +extern const Word16 txhpf1_num_coef_fx[11]; + extern const float txhpf1_den_coef[11]; -extern const float bp1_num_coef_nb_fx_order7[8]; -extern const float bp1_den_coef_nb_fx_order7[8]; +extern const Word16 txhpf1_den_coef_fx[11]; + +extern const float bp1_num_coef_nb_fx_order7_flt[8]; +extern const Word16 bp1_num_coef_nb_fx_order7[8]; + +extern const float bp1_den_coef_nb_fx_order7_flt[8]; +extern const Word16 bp1_den_coef_nb_fx_order7[8]; + extern const float num_nelp_lp[NELP_LP_ORDER + 1]; extern const float den_nelp_lp[NELP_LP_ORDER + 1]; @@ -1574,7 +1605,8 @@ extern const Coding codesTnsOrderTCX10[]; extern const Coding codesTnsOrder[]; extern const int16_t nTnsOrderCodes; -extern const float tnsCoeff4[16]; +extern const float tnsCoeff4_flt[16]; +extern const Word16 tnsCoeff4[16]; /*----------------------------------------------------------------------------------* * IGF settings for each bitrate @@ -1680,5 +1712,5 @@ extern const short dsDiracsTab[65]; extern const Word16 pwf_fx[17]; extern const Word32 inverse_table[]; extern const Word16 cos_diff_table[512]; - +extern const Word32 bwMode2fs[4]; #endif diff --git a/lib_com/stat_com.h b/lib_com/stat_com.h index 819d5837c..cd08c64ba 100644 --- a/lib_com/stat_com.h +++ b/lib_com/stat_com.h @@ -490,7 +490,7 @@ typedef int16_t ( *TDecodeValue )( struct Decoder_State *st, int16_t index, int1 * @param x the current input value. * @return the output of the filter. */ -typedef float ( *TLinearPredictionFilter )( const int16_t order, const float parCoeff[], float *state, float x ); +typedef float ( *TLinearPredictionFilter_flt )( const int16_t order, const float parCoeff[], float *state, float x ); /** Structure that defines mapping between a parameter and a bitstream. */ typedef struct ParamBitMap diff --git a/lib_com/tcx_utils.c b/lib_com/tcx_utils.c index eac1c1cb8..a72b23bd9 100644 --- a/lib_com/tcx_utils.c +++ b/lib_com/tcx_utils.c @@ -956,12 +956,12 @@ void InitTnsConfigs( { if ( total_brate > ACELP_32k ) { - InitTnsConfiguration( bwidth, L_frame / 2, &tnsConfig[0][0], igfStopFreq, total_brate, element_mode, MCT_flag ); + InitTnsConfiguration_flt( bwidth, L_frame / 2, &tnsConfig[0][0], igfStopFreq, total_brate, element_mode, MCT_flag ); } - InitTnsConfiguration( bwidth, L_frame, &tnsConfig[1][0], igfStopFreq, total_brate, element_mode, MCT_flag ); + InitTnsConfiguration_flt( bwidth, L_frame, &tnsConfig[1][0], igfStopFreq, total_brate, element_mode, MCT_flag ); - InitTnsConfiguration( bwidth, L_frame + L_frame / 4, &tnsConfig[1][1], igfStopFreq, total_brate, element_mode, MCT_flag ); + InitTnsConfiguration_flt( bwidth, L_frame + L_frame / 4, &tnsConfig[1][1], igfStopFreq, total_brate, element_mode, MCT_flag ); return; } diff --git a/lib_com/tns_base.c b/lib_com/tns_base.c index d38f032b6..13aea5208 100644 --- a/lib_com/tns_base.c +++ b/lib_com/tns_base.c @@ -1,54 +1,24 @@ -/****************************************************************************************************** - - (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository. All Rights Reserved. - - This software is protected by copyright law and by international treaties. - The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, - Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., - Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, - Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other - contributors to this repository retain full ownership rights in their respective contributions in - the software. This notice grants no license of any kind, including but not limited to patent - license, nor is any license granted by implication, estoppel or otherwise. - - Contributors are required to enter into the IVAS codec Public Collaboration agreement before making - contributions. - - This software is provided "AS IS", without any express or implied warranties. The software is in the - development stage. It is intended exclusively for experts who have experience with such software and - solely for the purpose of inspection. All implied warranties of non-infringement, merchantability - and fitness for a particular purpose are hereby disclaimed and excluded. - - Any dispute, controversy or claim arising under or in relation to providing this software shall be - submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in - accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and - the United Nations Convention on Contracts on the International Sales of Goods. - -*******************************************************************************************************/ - /*==================================================================================== - EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0 + EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0 ====================================================================================*/ + #include #include +#include #include "options.h" +#include "stat_com.h" #include "cnst.h" #include "rom_com.h" -#include "prot.h" -#include "stat_com.h" -#include "wmc_auto.h" - +#include "prot_fx1.h" +#include "prot_fx2.h" +#include "basop_util.h" /*---------------------------------------------------------------------------- * Local constants *---------------------------------------------------------------------------*/ -#define HLM_MIN_NRG PCM16_TO_FLT_FAC +#define HLM_MIN_NRG 32768.0f #define MAX_SUBDIVISIONS 3 @@ -56,65 +26,121 @@ * Local prototypes *---------------------------------------------------------------------------*/ +/** Linear prediction analysis/synthesis filter definition. + * @param order filter order. + * @param parCoeff filter (PARCOR) coefficients. + * @param state state of the filter. Must be at least of 'order' size. + * @param x the current input value. + * @return the output of the filter. + */ +typedef Word32 (* TLinearPredictionFilter)(Word16 order, Word16 const parCoeff[], Word32 * state, Word32 x); -static void Index2Parcor( const int16_t index[], float parCoeff[], const int16_t order ); +/** Inverse quantization for reflection coefficients. + * + * @param index input quantized values. + * @param parCoeff output reflection coefficients. + * @param order number of coefficients/values. + */ +static void Index2Parcor(Word16 const index[], Word16 parCoeff[], Word16 order); + +/** Linear prediction analysis filter. + * See TLinearPredictionFilter for details. + */ +static Word32 FIRLattice(const Word16 order, const Word16 *parCoeff, Word32 *state, Word32 x); -static float FIRLattice( const int16_t order, const float *parCoeff, float *state, float x ); +/** Linear prediction synthesis filter. + * See TLinearPredictionFilter for details. + */ +static Word32 IIRLattice(Word16 order, const Word16 *parCoeff, Word32 *state, Word32 x); -static float IIRLattice( const int16_t order, const float *parCoeff, float *state, float x ); +/** TNS analysis/synthesis filter. + * @param spectrum input spectrum values. + * @param numOfLines number of lines in the spectrum. + * @param parCoeff filter (PARCOR) coefficients. + * @param order filter order. + * @param filter function that implements filtering. + By this function it is defined whether analysis or synthesis is performed. + * @param output filtered output spectrum values. + Inplace operation is supported, so it can be equal to spectrum. + */ +static void TnsFilter(const Word32 spectrum[], const Word16 numOfLines, const Word16 parCoeff[], const Word16 order, TLinearPredictionFilter filter, Word32 * state, Word32 output[]); -static void TnsFilter( const float spectrum[], const int16_t numOfLines, const float parCoeff[], const int16_t order, TLinearPredictionFilter filter, float *state, float output[] ); +static void ITF_TnsFilter_fx( const Word32 spectrum[], const Word16 numOfLines, const Word16 A[], /* Q14 */ const Word16 Q_A, const Word16 order, Word32 output[]); +static void ITF_GetFilterParameters_fx(Word32 rxx[], const Word16 maxOrder, Word16* A, /* Q14 */Word16* Q_A, Word16* predictionGain); -/*-------------------------------------------------------------------* - * InitTnsConfiguration() - * - *-------------------------------------------------------------------*/ +/********************************/ +/* Interface functions */ +/********************************/ +/** Init TNS configuration. + * Fills STnsConfig structure with sensible content. + * @param nSampleRate Sampling rate of the input. + * @param nFrameLength Frame length. + * @param pTnsConfig TNS configuration to be initialized. + * @return 0 on success, otherwise 1. + */ void InitTnsConfiguration( - const int16_t bwidth, - const int16_t frameLength, - STnsConfig *pTnsConfig, - const int16_t igfStopFreq, - const int32_t total_brate, + const Word16 bwidth, + const Word16 frameLength, + STnsConfig * pTnsConfig, + const Word16 igfStopFreq, + const Word32 total_brate, const int16_t element_mode, - const int16_t MCT_flag ) + const int16_t is_mct +) { - int32_t nSampleRate; - int16_t iFilter; - int16_t *startLineFilter = &pTnsConfig->iFilterBorders[1]; - - nSampleRate = inner_frame_tbl[bwidth] * FRAMES_PER_SEC; + Word16 iFilter = 0; + Word16 * startLineFilter; + Word32 L_tmp; + Word32 nSampleRate; + Word16 s1; + Word16 s2; +#ifndef ADD_IVAS_TNS + (void)(element_mode); + (void)(is_mct); +#endif + nSampleRate = bwMode2fs[bwidth]; + move32(); + startLineFilter = &pTnsConfig->iFilterBorders[1]; /* Sanity checks */ - assert( ( nSampleRate > 0 ) && ( frameLength > 0 ) && ( pTnsConfig != NULL ) ); - if ( ( nSampleRate <= 0 ) || ( frameLength <= 0 ) || ( pTnsConfig == NULL ) ) + assert((nSampleRate > 0) && (frameLength > 0) && (pTnsConfig != NULL)); + if ((nSampleRate <= 0) || (frameLength <= 0) || (pTnsConfig == NULL)) { return /*TNS_FATAL_ERROR*/; } - /* WMOPS: All initializations are either for safety or static (tables) and thus not to be counted */ + /* Initialize TNS filter flag and maximum order */ - pTnsConfig->maxOrder = TNS_MAX_FILTER_ORDER; - if ( total_brate <= ACELP_32k ) - { - pTnsConfig->nMaxFilters = sizeof( tnsParametersIGF32kHz_LowBR ) / sizeof( tnsParametersIGF32kHz_LowBR[0] ); + move16(); + pTnsConfig->maxOrder = TNS_MAX_FILTER_ORDER; + IF (LE_32(total_brate, ACELP_32k)) + { + move16(); + move16(); + pTnsConfig->nMaxFilters = sizeof(tnsParametersIGF32kHz_LowBR)/sizeof(tnsParametersIGF32kHz_LowBR[0]); pTnsConfig->pTnsParameters = tnsParametersIGF32kHz_LowBR; } - else + ELSE { - if ( nSampleRate > 32000 && nSampleRate == 100 * frameLength ) + test(); + IF (GT_32(nSampleRate,32000)&&EQ_32(nSampleRate,L_mult0(100,frameLength))) { - pTnsConfig->nMaxFilters = sizeof( tnsParameters48kHz_grouped ) / sizeof( tnsParameters48kHz_grouped[0] ); + move16(); + pTnsConfig->nMaxFilters = sizeof(tnsParameters48kHz_grouped)/sizeof(tnsParameters48kHz_grouped[0]); + move16(); pTnsConfig->pTnsParameters = tnsParameters48kHz_grouped; } - else if ( nSampleRate > 16000 ) + ELSE + IF ( GT_32(nSampleRate,INT_FS_16k)) { - if ( ( element_mode > IVAS_SCE ) && ( total_brate >= ( MCT_flag ? IVAS_32k : IVAS_48k ) ) ) +#ifdef ADD_IVAS_TNS + if ((element_mode > IVAS_SCE) && (total_brate >= (is_mct ? IVAS_32k : IVAS_48k))) { - pTnsConfig->nMaxFilters = sizeof( tnsParameters32kHz_Stereo ) / sizeof( tnsParameters32kHz_Stereo[0] ); - if ( nSampleRate == 100 * frameLength ) /* sub-frame length is <= 10 ms */ + pTnsConfig->nMaxFilters = sizeof(tnsParameters32kHz_Stereo) / sizeof(tnsParameters32kHz_Stereo[0]); + if (nSampleRate == 100 * frameLength) /* sub-frame length is <= 10 ms */ { pTnsConfig->pTnsParameters = tnsParameters32kHz_grouped; } @@ -124,398 +150,693 @@ void InitTnsConfiguration( } } else +#endif { - pTnsConfig->nMaxFilters = sizeof( tnsParameters32kHz ) / sizeof( tnsParameters32kHz[0] ); - if ( nSampleRate == 100 * frameLength ) /* sub-frame length is <= 10 ms */ + + move16(); + pTnsConfig->nMaxFilters = sizeof(tnsParameters32kHz) / sizeof(tnsParameters32kHz[0]); + + move16(); + pTnsConfig->pTnsParameters = tnsParameters32kHz; + + if (EQ_32(nSampleRate, L_mult0(100, frameLength))) /* sub-frame length is <= 10 ms */ { + move16(); pTnsConfig->pTnsParameters = tnsParameters32kHz_grouped; } - else - { - pTnsConfig->pTnsParameters = tnsParameters32kHz; - } } } - else + ELSE { - if ( nSampleRate == 100 * frameLength ) /* sub-frame length is <= 10 ms */ + IF ( EQ_32(nSampleRate, L_mult0(100, frameLength))) /* sub-frame length is <= 10 ms */ { - pTnsConfig->nMaxFilters = sizeof( tnsParameters16kHz_grouped ) / sizeof( tnsParameters16kHz_grouped[0] ); + move16(); + move16(); + pTnsConfig->nMaxFilters = sizeof(tnsParameters16kHz_grouped)/sizeof(tnsParameters16kHz_grouped[0]); pTnsConfig->pTnsParameters = tnsParameters16kHz_grouped; } - else + ELSE { - pTnsConfig->nMaxFilters = sizeof( tnsParameters16kHz ) / sizeof( tnsParameters16kHz[0] ); + move16(); + move16(); + pTnsConfig->nMaxFilters = sizeof(tnsParameters16kHz)/sizeof(tnsParameters16kHz[0]); pTnsConfig->pTnsParameters = tnsParameters16kHz; } } } - assert( pTnsConfig->nMaxFilters <= TNS_MAX_NUM_OF_FILTERS ); + assert(pTnsConfig->nMaxFilters <= TNS_MAX_NUM_OF_FILTERS); /* Set starting MDCT line for each filter based on the starting frequencies from the TNS table */ - for ( iFilter = 0; iFilter < pTnsConfig->nMaxFilters; iFilter++ ) + + FOR (iFilter = 0; iFilter < pTnsConfig->nMaxFilters; iFilter++) { - assert( pTnsConfig->pTnsParameters[iFilter].startLineFrequency < 0.5f * nSampleRate ); - startLineFilter[iFilter] = (int16_t) ( ( frameLength * 2 * pTnsConfig->pTnsParameters[iFilter].startLineFrequency ) / nSampleRate ); + assert(pTnsConfig->pTnsParameters[iFilter].startLineFrequency < 0.5f*nSampleRate); + assert(nSampleRate <= 96000); + move16(); + startLineFilter[iFilter] = divide3232(L_mult0(frameLength, pTnsConfig->pTnsParameters[iFilter].startLineFrequency), L_shl(nSampleRate,14)); } - if ( igfStopFreq > 0 ) + + IF (igfStopFreq > 0) { - pTnsConfig->iFilterBorders[0] = (int16_t) ( ( frameLength * 2 * igfStopFreq ) / nSampleRate ); + L_tmp = L_mult(frameLength, igfStopFreq); + s1 = sub(norm_l(L_tmp), 1); + s2 = norm_l(nSampleRate); + + move16(); + pTnsConfig->iFilterBorders[0] = shr( div_l( L_shl(L_tmp, s1), extract_h(L_shl(nSampleRate, s2)) ) , sub(WORD16_BITS-1, sub(s2, s1))); + } - else + ELSE { + move16(); pTnsConfig->iFilterBorders[0] = frameLength; } - +#ifdef ADD_IVAS_TNS pTnsConfig->allowTnsOnWhite = 0; - - return /*TNS_NO_ERROR*/; +#endif + return; /*TNS_NO_ERROR;*/ } - /*-------------------------------------------------------------------* * ApplyTnsFilter() * *-------------------------------------------------------------------*/ void ApplyTnsFilter( - STnsConfig const *pTnsConfig, - STnsData const *pTnsData, - float spectrum[], - const int16_t fIsAnalysis ) + STnsConfig const * pTnsConfig, + STnsData const * pTnsData, + Word32 spectrum[], + const Word8 fIsAnalysis +) { TLinearPredictionFilter filter; - float state[TNS_MAX_FILTER_ORDER]; - int16_t iFilter; - int16_t stopLine, startLine; - const int16_t *pBorders; + Word32 state[TNS_MAX_FILTER_ORDER]; + Word16 iFilter; + Word16 stopLine, startLine; + Word16 const * pBorders; + - filter = fIsAnalysis ? FIRLattice : IIRLattice; - set_f( state, 0, TNS_MAX_FILTER_ORDER ); + move16(); + filter = IIRLattice; + if (fIsAnalysis) + { + move16(); + filter = FIRLattice; + } + set32_fx(state, 0, TNS_MAX_FILTER_ORDER); + move16(); pBorders = pTnsConfig->iFilterBorders; - for ( iFilter = pTnsConfig->nMaxFilters - 1; iFilter >= 0; iFilter-- ) + FOR (iFilter = pTnsConfig->nMaxFilters-1; iFilter >= 0; iFilter--) { - float parCoeff[TNS_MAX_FILTER_ORDER]; - const STnsFilter *pFilter = &pTnsData->filter[iFilter]; + Word16 parCoeff[TNS_MAX_FILTER_ORDER]; + const STnsFilter * pFilter; - set_f( parCoeff, 0, TNS_MAX_FILTER_ORDER ); + + move16(); + move16(); + move16(); + pFilter = &pTnsData->filter[iFilter]; stopLine = pBorders[iFilter]; - startLine = pBorders[iFilter + 1]; + startLine = pBorders[iFilter+1]; + + Index2Parcor(pFilter->coefIndex, parCoeff, pFilter->order); + + TnsFilter(&spectrum[startLine], stopLine-startLine, + parCoeff, pFilter->order, + filter, state, + &spectrum[startLine]); + + } + + move16(); + + return /*result*/; +} + +/*-------------------------------------------------------------------* + * ITF_Apply() + * + *-------------------------------------------------------------------*/ + +void ITF_Apply_fx( + Word32 spectrum[], + Word16 startLine, + Word16 stopLine, + const Word16* A, + Word16 Q_A, + Word16 order +) +{ + + ITF_TnsFilter_fx(&spectrum[startLine],(Word16)(stopLine-startLine), A, Q_A, (Word16)order, &spectrum[startLine]); + + return /*TNS_NO_ERROR*/; +} +/*-------------------------------------------------------------------* +* ITF_Detect() +* +* +*-------------------------------------------------------------------*/ + +Word16 ITF_Detect_fx( + const Word32 pSpectrum[], + const Word16 startLine, + const Word16 stopLine, + const Word16 maxOrder, + Word16* A, + Word16* Q_A, + Word16* predictionGain, + Word16* curr_order, + Word16 Q +) +{ + + Word16 spectrumLength; + Word16 const nSubdivisions = MAX_SUBDIVISIONS; + Word16 iSubdivisions; + Word16 iStartLine; + Word16 iEndLine; + Word16 facs[MAX_SUBDIVISIONS]; + Word16 facs_e[MAX_SUBDIVISIONS]; /* exponents of facs[][] */ + Word16 shifts[MAX_SUBDIVISIONS]; + Word16 tmp, headroom, shift; + Word32 rxx[ITF_MAX_FILTER_ORDER+1]; + Word16 lag; + Word32 L_tmp, tmp32; + Word16 tmpbuf[325]; + Word16 n, i; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + move16(); + move16(); + move16(); + + if (maxOrder <= 0) + { + return 0; + } + + /* Calculate norms for each spectrum part */ + FOR (iSubdivisions = 0; iSubdivisions < nSubdivisions; iSubdivisions++) + { + assert((nSubdivisions == 1) || (nSubdivisions == 3)); + + tmp = sub(stopLine, startLine); + iStartLine = imult1616(tmp, iSubdivisions); + iEndLine = add(iStartLine, tmp); + + if (EQ_16(nSubdivisions, 3))iStartLine=mult(iStartLine,0x2AAB); + iStartLine = add(iStartLine, startLine); + + if (EQ_16(nSubdivisions, 3))iEndLine=mult(iEndLine,0x2AAB); + iEndLine = add(iEndLine, startLine); + headroom = getScaleFactor32(pSpectrum+iStartLine-IGF_START_MN, sub(iEndLine, iStartLine)); + /* Calculate norm of spectrum band */ + L_tmp = Norm32Norm(pSpectrum+iStartLine-IGF_START_MN, headroom, sub(iEndLine, iStartLine), &shift); + + /* Check threshold HLM_MIN_NRG */ + BASOP_SATURATE_WARNING_OFF_EVS; +#ifdef BASOP_NOGLOB + tmp32 = L_sub(L_shl_o(L_tmp, sub(shift, 24-Q), &Overflow), 4194304l/*HLM_MIN_NRG Q7*/); +#else /* BASOP_NOGLOB */ + tmp32 = L_sub(L_shl(L_tmp, sub(shift, 24-Q)), 4194304l/*HLM_MIN_NRG Q7*/); +#endif + BASOP_SATURATE_WARNING_ON_EVS; + + /* get pre-shift for autocorrelation */ + tmp = sub(shift, norm_l(L_tmp)); /* exponent for normalized L_tmp */ + tmp = shr(sub(1, tmp), 1); /* pre-shift to apply before autocorrelation */ + shifts[iSubdivisions] = s_min(tmp, headroom); + move16(); + + /* calc normalization factor */ + facs[iSubdivisions] = 0; + move16(); + facs_e[iSubdivisions] = 0; + move16(); + + if (tmp32 > 0) + { + facs[iSubdivisions] = 0x7FFF; + move16(); /* normalization not needed for one subdivision */ + } + + test(); + IF ((tmp32 > 0) && (GT_16(nSubdivisions, 1))) + { + move16(); + facs_e[iSubdivisions] = shl(sub(tmp, shifts[iSubdivisions]), 1); + + tmp = sub(1, shl(tmp, 1)); /* exponent of autocorrelation */ + L_tmp = L_shl(L_tmp, sub(shift, tmp)); /* shift L_tmp to that exponent */ - Index2Parcor( pFilter->coefIndex, parCoeff, pFilter->order ); + /* calc factor (with 2 bits headroom for sum of 3 subdivisions) */ + facs[iSubdivisions] = div_s(0x2000, round_fx(L_tmp)); /* L_tmp is >= 0x2000000 */ move16(); + } - TnsFilter( &spectrum[startLine], stopLine - startLine, parCoeff, pFilter->order, filter, state, &spectrum[startLine] ); } - return /*( pTnsData->nFilters < 0 ) ? TNS_FATAL_ERROR : TNS_NO_ERROR*/; + /* Calculate normalized autocorrelation for spectrum subdivision and get filter parameters based on it */ + set32_fx(rxx, 0, ITF_MAX_FILTER_ORDER+1); + + spectrumLength = sub(stopLine, startLine); + + FOR (iSubdivisions = 0; iSubdivisions < nSubdivisions; iSubdivisions++) + { + IF ( facs[iSubdivisions] == 0 ) + { + BREAK; + } + + + assert((nSubdivisions == 1) || (nSubdivisions == 3)); + + iStartLine = imult1616(spectrumLength, iSubdivisions); + iEndLine = add(iStartLine, spectrumLength); + + if (EQ_16(nSubdivisions, 3))iStartLine=mult(iStartLine,0x2AAB); + iStartLine = add(iStartLine, startLine); + + if (EQ_16(nSubdivisions, 3))iEndLine=mult(iEndLine,0x2AAB); + iEndLine = add(iEndLine, startLine); + + + move16(); + shift = shifts[iSubdivisions]; + + n = sub(iEndLine, iStartLine); + assert(n < (Word16)(sizeof(tmpbuf)/sizeof(Word16))); + FOR (i = 0; i < n; i++) + { + tmpbuf[i] = round_fx(L_shl(pSpectrum[iStartLine+i-IGF_START_MN], shift)); + } + + FOR (lag = 0; lag <= maxOrder; lag++) + { + n = sub(sub(iEndLine,lag), iStartLine); + + { + Word64 tmp64 = 0; + FOR (i = 0; i < n; i++) + { + tmp64 = W_mac0_16_16(tmp64, tmpbuf[i], tmpbuf[i+lag]); + } + L_tmp = W_sat_l(tmp64); + } + + L_tmp = Mpy_32_16_1(L_tmp, facs[iSubdivisions]); + L_tmp = L_shl(L_tmp, facs_e[iSubdivisions]); + + rxx[lag] = L_add(rxx[lag], L_tmp); + move32(); + } + + } + + IF ( EQ_16(iSubdivisions,nSubdivisions)) /* meaning there is no subdivision with low energy */ + { + /* Limit the maximum order to spectrum length/4 */ + ITF_GetFilterParameters_fx(rxx, s_min (maxOrder, shr(spectrumLength,2)), A, Q_A, predictionGain); + + *curr_order = maxOrder; + } + + return 1; } -/*********************************************************************************************/ -/* Definitions of functions used in the mapping between TNS parameters and a bitstream. */ -/*********************************************************************************************/ +/* Helper functions for Hufmann table coding */ -/* Helper functions for hufmann table coding */ /** Get number of bits from a Huffman table. - * The table must be sorted by values. - */ -static int16_t GetBitsFromTable( int16_t value, const Coding codes[], const int16_t nSize ) + * The table must be sorted by values. + */ +static Word16 GetBitsFromTable(const Word16 value, const Coding codes[], const Word16 nSize) { - (void) nSize; - assert( ( value >= 0 ) && ( value < nSize ) && ( nSize >= 0 ) && ( nSize <= 256 ) ); - return codes[value].nBits; + (void)nSize; + assert((value >= 0) && (value < nSize) && (nSize >= 0) && (nSize <= 256)); + + move16(); + cast16(); + return (Word16)codes[value].nBits; } /** Get the code for a value from a Huffman table. - * The table must be sorted by values. - */ -static int16_t EncodeUsingTable( int16_t value, const Coding codes[], const int16_t nSize ) + * The table must be sorted by values. + */ +static Word16 EncodeUsingTable(const Word16 value, const Coding codes[], const Word16 nSize) { - (void) nSize; - assert( ( value >= 0 ) && ( value < nSize ) && ( nSize >= 0 ) && ( nSize <= 256 ) ); + (void)nSize; + assert((value >= 0) && (value < nSize) && (nSize >= 0) && (nSize <= 256)); + + move16(); return codes[value].code; } + /** Decode a value from a bitstream using a Huffman table. */ -static int16_t DecodeUsingTable( Decoder_State *st, int16_t *pValue, const Coding codes[], const int16_t nSize ) +static Word16 DecodeUsingTable(Decoder_State *st, Word16 * pValue, const Coding codes[], const Word16 nSize) { - uint16_t code = 0; - uint8_t nBits = 0; - int16_t valueIndex = nSize; + Word16 code = 0; + Word16 nBits = 0; + Word16 valueIndex; + + assert((nSize >= 0) && (nSize <= 256)); - assert( ( nSize >= 0 ) && ( nSize <= 256 ) ); - /* Variable initialization. All are required! */ - while ( valueIndex == nSize ) + + move16(); + valueIndex = nSize; + + + WHILE (valueIndex == nSize) { - code = ( code << 1 ) + get_next_indice( st, 1 ); - ++nBits; - if ( nBits > nSize || nBits > 16 ) + code = add(shl(code,1), get_next_indice_fx(st, 1)); + nBits = add(nBits,1); + if (nBits > nSize || nBits > 16) { st->BER_detect = 1; *pValue = 0; + return -1; } - for ( valueIndex = 0; valueIndex < nSize; valueIndex++ ) + + FOR (valueIndex = 0; valueIndex < nSize; valueIndex++) { - if ( codes[valueIndex].nBits == nBits ) + + IF ( s_and((Word16)EQ_16(codes[valueIndex].nBits,nBits),(Word16)EQ_16(codes[valueIndex].code,code))) { - if ( codes[valueIndex].code == code ) - { - break; - } + BREAK; } } - /* Loop condition */ - } - if ( valueIndex < nSize ) + } + if (valueIndex < nSize) { - *pValue = codes[valueIndex].value; + *pValue = (Word16)codes[valueIndex].value; } else { st->BER_detect = 1; *pValue = 0; + return -1; } return nBits; } + /* TNS filter coefficients */ -void const *GetTnsFilterCoeff( void const *p, const int16_t index, int16_t *pValue ) +void const * GetTnsFilterCoeff(void const * p, const Word16 index, Word16 * pValue) { - *pValue = ( (int16_t const *) p )[index] + INDEX_SHIFT; + *pValue = ((Word16 const *)p)[index] + INDEX_SHIFT; return NULL; } -void *SetTnsFilterCoeff( void *p, const int16_t index, const int16_t value ) +void * SetTnsFilterCoeff(void * p, const Word16 index, const Word16 value) { - ( (int16_t *) p )[index] = value - INDEX_SHIFT; + ((Word16 *)p)[index] = sub(value, INDEX_SHIFT); return NULL; } -int16_t GetSWBTCX20TnsFilterCoeffBits( const int16_t value, const int16_t index ) + +Word16 GetSWBTCX20TnsFilterCoeffBits(const Word16 value, const Word16 index) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return GetBitsFromTable( value, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return GetBitsFromTable(value, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes); } -int16_t EncodeSWBTCX20TnsFilterCoeff( const int16_t value, const int16_t index ) +Word16 EncodeSWBTCX20TnsFilterCoeff(const Word16 value, const Word16 index) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return EncodeUsingTable( value, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return EncodeUsingTable(value, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes); } -int16_t DecodeSWBTCX20TnsFilterCoeff( Decoder_State *st, const int16_t index, int16_t *pValue ) +Word16 DecodeSWBTCX20TnsFilterCoeff(Decoder_State *st, const Word16 index, Word16 * pValue) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return DecodeUsingTable( st, pValue, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return DecodeUsingTable(st, pValue, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes); } -int16_t GetSWBTCX10TnsFilterCoeffBits( const int16_t value, const int16_t index ) +Word16 GetSWBTCX10TnsFilterCoeffBits(const Word16 value, const Word16 index) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return GetBitsFromTable( value, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return GetBitsFromTable(value, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes); } -int16_t EncodeSWBTCX10TnsFilterCoeff( const int16_t value, const int16_t index ) +Word16 EncodeSWBTCX10TnsFilterCoeff(const Word16 value, const Word16 index) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return EncodeUsingTable( value, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return EncodeUsingTable(value, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes); } -int16_t DecodeSWBTCX10TnsFilterCoeff( Decoder_State *st, const int16_t index, int16_t *pValue ) +Word16 DecodeSWBTCX10TnsFilterCoeff(Decoder_State *st, const Word16 index, Word16 * pValue) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return DecodeUsingTable( st, pValue, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return DecodeUsingTable(st, pValue, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes); } -int16_t GetWBTCX20TnsFilterCoeffBits( const int16_t value, const int16_t index ) +Word16 GetWBTCX20TnsFilterCoeffBits(const Word16 value, const Word16 index) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return GetBitsFromTable( value, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return GetBitsFromTable(value, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes); } -int16_t EncodeWBTCX20TnsFilterCoeff( const int16_t value, const int16_t index ) +Word16 EncodeWBTCX20TnsFilterCoeff(const Word16 value, const Word16 index) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return EncodeUsingTable( value, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return EncodeUsingTable(value, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes); } -int16_t DecodeWBTCX20TnsFilterCoeff( Decoder_State *st, const int16_t index, int16_t *pValue ) +Word16 DecodeWBTCX20TnsFilterCoeff(Decoder_State *st, const Word16 index, Word16 * pValue) { - assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); - return DecodeUsingTable( st, pValue, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes ); + assert((index >= 0) && (index < nTnsCoeffTables)); + + return DecodeUsingTable(st, pValue, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes); } + /* TNS filter order */ -void const *GetTnsFilterOrder( void const *p, const int16_t index, int16_t *pValue ) +void const * GetTnsFilterOrder(void const * p, const Word16 index, Word16 * pValue) { - *pValue = ( (STnsFilter const *) p )[index].order; - return ( (STnsFilter const *) p )[index].coefIndex; + move16(); + *pValue = ((STnsFilter const *)p)[index].order; + + move16(); + return ((STnsFilter const *)p)[index].coefIndex; } -void *SetTnsFilterOrder( void *p, const int16_t index, const int16_t value ) +void * SetTnsFilterOrder(void * p, const Word16 index, const Word16 value) { - ( (STnsFilter *) p )[index].order = value; - return ( (STnsFilter *) p )[index].coefIndex; + move16(); + ((STnsFilter *)p)[index].order = value; + + move16(); + return ((STnsFilter *)p)[index].coefIndex; } -int16_t GetTnsFilterOrderBitsSWBTCX20( const int16_t value, const int16_t index ) +Word16 GetTnsFilterOrderBitsSWBTCX20(const Word16 value, const Word16 index) { - (void) index; - return GetBitsFromTable( value - 1, codesTnsOrderTCX20, nTnsOrderCodes ); + (void)index; + + return GetBitsFromTable(value-1, codesTnsOrderTCX20, nTnsOrderCodes); } -int16_t EncodeTnsFilterOrderSWBTCX20( const int16_t value, const int16_t index ) +Word16 EncodeTnsFilterOrderSWBTCX20(const Word16 value, const Word16 index) { - (void) index; - return EncodeUsingTable( value - 1, codesTnsOrderTCX20, nTnsOrderCodes ); + (void)index; + + return EncodeUsingTable(value-1, codesTnsOrderTCX20, nTnsOrderCodes); } -int16_t DecodeTnsFilterOrderSWBTCX20( Decoder_State *st, const int16_t index, int16_t *pValue ) +Word16 DecodeTnsFilterOrderSWBTCX20(Decoder_State *st, const Word16 index, Word16 * pValue) { - (void) index; - return DecodeUsingTable( st, pValue, codesTnsOrderTCX20, nTnsOrderCodes ); + (void)index; + + return DecodeUsingTable(st, pValue, codesTnsOrderTCX20, nTnsOrderCodes); } -int16_t GetTnsFilterOrderBitsSWBTCX10( const int16_t value, const int16_t index ) +Word16 GetTnsFilterOrderBitsSWBTCX10(const Word16 value, const Word16 index) { - (void) index; - return GetBitsFromTable( value - 1, codesTnsOrderTCX10, nTnsOrderCodes ); + (void)index; + + return GetBitsFromTable(value-1, codesTnsOrderTCX10, nTnsOrderCodes); } -int16_t EncodeTnsFilterOrderSWBTCX10( const int16_t value, const int16_t index ) +Word16 EncodeTnsFilterOrderSWBTCX10(const Word16 value, const Word16 index) { - (void) index; - return EncodeUsingTable( value - 1, codesTnsOrderTCX10, nTnsOrderCodes ); + (void)index; + + return EncodeUsingTable(value-1, codesTnsOrderTCX10, nTnsOrderCodes); } -int16_t DecodeTnsFilterOrderSWBTCX10( Decoder_State *st, const int16_t index, int16_t *pValue ) +Word16 DecodeTnsFilterOrderSWBTCX10(Decoder_State *st, const Word16 index, Word16 * pValue) { - (void) index; - return DecodeUsingTable( st, pValue, codesTnsOrderTCX10, nTnsOrderCodes ); + (void)index; + + return DecodeUsingTable(st, pValue, codesTnsOrderTCX10, nTnsOrderCodes); } -int16_t GetTnsFilterOrderBits( const int16_t value, const int16_t index ) +Word16 GetTnsFilterOrderBits(const Word16 value, const Word16 index) { - (void) index; - return GetBitsFromTable( value - 1, codesTnsOrder, nTnsOrderCodes ); + (void)index; + + return GetBitsFromTable(value-1, codesTnsOrder, nTnsOrderCodes); } -int16_t EncodeTnsFilterOrder( const int16_t value, const int16_t index ) +Word16 EncodeTnsFilterOrder(const Word16 value, const Word16 index) { - (void) index; - return EncodeUsingTable( value - 1, codesTnsOrder, nTnsOrderCodes ); + (void)index; + + return EncodeUsingTable(value-1, codesTnsOrder, nTnsOrderCodes); } -int16_t DecodeTnsFilterOrder( Decoder_State *st, const int16_t index, int16_t *pValue ) +Word16 DecodeTnsFilterOrder(Decoder_State *st, const Word16 index, Word16 * pValue) { - (void) index; - return DecodeUsingTable( st, pValue, codesTnsOrder, nTnsOrderCodes ); + (void)index; + + return DecodeUsingTable(st, pValue, codesTnsOrder, nTnsOrderCodes); } /* Number of TNS filters */ -void const *GetNumOfTnsFilters( void const *p, const int16_t index, int16_t *pValue ) +void const * GetNumOfTnsFilters(void const * p, const Word16 index, Word16 * pValue) { - *pValue = (int16_t) abs( ( (STnsData const *) p )[index].nFilters ); - return ( (STnsData const *) p )[index].filter; + *pValue = ((STnsData const *)p)[index].nFilters; + + return ((STnsData const *)p)[index].filter; } -void *SetNumOfTnsFilters( void *p, const int16_t index, const int16_t value ) +void * SetNumOfTnsFilters(void * p, const Word16 index, Word16 value) { - ( (STnsData *) p )[index].nFilters = (int16_t) abs( value ); - return ( (STnsData *) p )[index].filter; + ((STnsData *)p)[index].nFilters = value; + + return ((STnsData *)p)[index].filter; } /* TNS enabled/disabled flag */ -void const *GetTnsEnabled( void const *p, const int16_t index, int16_t *pValue ) +void const * GetTnsEnabled(void const * p, const Word16 index, Word16 * pValue) { - *pValue = ( (STnsData const *) p )[index].nFilters != 0 ? 1 : 0; + move16(); + *pValue = 0; + if (((STnsData const *)p)[index].nFilters != 0) + { + move16(); + *pValue = 1; + } return NULL; } -void *SetTnsEnabled( void *p, const int16_t index, const int16_t value ) +void * SetTnsEnabled(void * p, const Word16 index, const Word16 value) { - (void) p, (void) index, (void) value; + (void)p,(void)index,(void)value; return NULL; } - +#ifdef ADD_IVAS_TNS /* TNS on whitened spectra flag */ -void const *GetTnsOnWhite( void const *p, const int16_t index, int16_t *pValue ) +void const* GetTnsOnWhite(void const* p, const int16_t index, int16_t* pValue) { - *pValue = ( (STnsData const *) p )[index].tnsOnWhitenedSpectra > 0 ? 1 : 0; + *pValue = ((STnsData const*)p)[index].tnsOnWhitenedSpectra > 0 ? 1 : 0; return NULL; } -void *SetTnsOnWhite( void *p, const int16_t index, const int16_t value ) +void* SetTnsOnWhite(void* p, const int16_t index, const int16_t value) { - ( (STnsData *) p )[index].tnsOnWhitenedSpectra = value; + ((STnsData*)p)[index].tnsOnWhitenedSpectra = value; return NULL; } -void const *GetTnsEnabledSingleFilter( void const *p, const int16_t index, int16_t *pValue ) +void const* GetTnsEnabledSingleFilter(void const* p, const int16_t index, int16_t* pValue) { - *pValue = ( (STnsData const *) p )[index].nFilters != 0 ? 1 : 0; - return ( (STnsData const *) p )[index].filter; + *pValue = ((STnsData const*)p)[index].nFilters != 0 ? 1 : 0; + return ((STnsData const*)p)[index].filter; } +#endif -void *SetTnsEnabledSingleFilter( void *p, const int16_t index, const int16_t value ) +void const * GetTnsEnabledSingleFilter(void const * p, const Word16 index, Word16 * pValue) { - ( (STnsData *) p )[index].nFilters = value; - return ( (STnsData *) p )[index].filter; + move16(); + *pValue = 0; + if (((STnsData const *)p)[index].nFilters > 0) + { + move16(); + *pValue = 1; + } + return ((STnsData const *)p)[index].filter; } +void * SetTnsEnabledSingleFilter(void * p, const Word16 index, const Word16 value) +{ + ((STnsData *)p)[index].nFilters = value; + return ((STnsData *)p)[index].filter; +} /*-------------------------------------------------------------------* * ResetTnsData() * *-------------------------------------------------------------------*/ -void ResetTnsData( - STnsData *pTnsData ) +void ResetTnsData(STnsData * pTnsData) { - uint16_t iFilter; + Word16 iFilter; + pTnsData->nFilters = 0; +#ifdef ADD_IVAS_TNS pTnsData->tnsOnWhitenedSpectra = 0; - - for ( iFilter = 0; iFilter < sizeof( pTnsData->filter ) / sizeof( pTnsData->filter[0] ); iFilter++ ) +#endif + FOR (iFilter = 0; iFilter < (Word16) (sizeof(pTnsData->filter)/sizeof(pTnsData->filter[0])); iFilter++) { - STnsFilter *const pTnsFilter = &pTnsData->filter[iFilter]; + STnsFilter * const pTnsFilter = &pTnsData->filter[iFilter]; pTnsFilter->spectrumLength = 0; - pTnsFilter->predictionGain_flt = 1.0f; - pTnsFilter->avgSqrCoef_flt = 0; + pTnsFilter->predictionGain = 128/*1.0f Q7*/; + pTnsFilter->avgSqrCoef = 0; +#ifdef ADD_IVAS_TNS pTnsFilter->filterType = TNS_FILTER_OFF; - ClearTnsFilterCoefficients( pTnsFilter ); +#endif + ClearTnsFilterCoefficients(pTnsFilter); } - return; } - - /*-------------------------------------------------------------------* * ClearTnsFilterCoefficients() * *-------------------------------------------------------------------*/ void ClearTnsFilterCoefficients( - STnsFilter *pTnsFilter ) + STnsFilter * pTnsFilter +) { + move16(); pTnsFilter->order = 0; - set_s( pTnsFilter->coefIndex, 0, TNS_MAX_FILTER_ORDER ); - - return; + assert(TNS_MAX_FILTER_ORDER == 8); + move16();move16();move16();move16(); + move16();move16();move16();move16(); + pTnsFilter->coefIndex[0] = 0; + pTnsFilter->coefIndex[1] = 0; + pTnsFilter->coefIndex[2] = 0; + pTnsFilter->coefIndex[3] = 0; + pTnsFilter->coefIndex[4] = 0; + pTnsFilter->coefIndex[5] = 0; + pTnsFilter->coefIndex[6] = 0; + pTnsFilter->coefIndex[7] = 0; } /** Inverse quantization for reflection coefficients. @@ -524,71 +845,74 @@ void ClearTnsFilterCoefficients( * @param parCoeff output reflection coefficients. * @param order number of coefficients/values. */ -static void Index2Parcor( - const int16_t index[], - float parCoeff[], - const int16_t order ) +static void Index2Parcor(const Word16 index[], Word16 parCoeff[], Word16 order) { - const float *values = tnsCoeff4; - int16_t i; + const Word16 * values; + Word16 i; + + move16(); + values = tnsCoeff4; - for ( i = 0; i < order; i++ ) + FOR (i = 0; i < order; i++) { - parCoeff[i] = values[index[i] + INDEX_SHIFT]; + move16(); + parCoeff[i] = values[add(index[i], INDEX_SHIFT)]; } - return; } + /* Linear prediction analysis filter. */ -static float FIRLattice( - const int16_t order, - const float *parCoeff, - float *state, - float x ) +static Word32 FIRLattice( + const Word16 order, + const Word16 *parCoeff /*Q15*/, + Word32 *state, + Word32 x /* Q0 */ +) { - int16_t i; - float tmpSave; + Word16 i; + Word32 tmpSave, tmp; + tmpSave = x; - for ( i = 0; i < order - 1; i++ ) + move32(); + FOR (i = 0; i < order-1; i++) { - const float tmp = parCoeff[i] * x + state[i]; - /* Variable initialization */ - x += parCoeff[i] * state[i]; + tmp = L_add(state[i], Mpy_32_16_1(x, parCoeff[i])); + x = L_add(x, Mpy_32_16_1(state[i], parCoeff[i])); /* exponent: 31+0 */ state[i] = tmpSave; + move32(); tmpSave = tmp; + move32(); } /* last stage: only need half operations */ - x += parCoeff[order - 1] * state[order - 1]; - state[order - 1] = tmpSave; + x = L_add(x, Mpy_32_16_1(state[order-1], parCoeff[order-1])); + state[order-1] = tmpSave; + move32(); return x; } -/* Linear prediction synthesis filter. */ -static float IIRLattice( - const int16_t order, - const float *parCoeff, - float *state, - float x ) +static Word32 IIRLattice(Word16 order, const Word16 *parCoeff, Word32 *state, Word32 x) { - int16_t i; + Word16 i; + /* first stage: no need to calculate state[order-1] */ - x -= parCoeff[order - 1] * state[order - 1]; - for ( i = order - 2; i >= 0; i-- ) + x = L_sub(x, Mpy_32_16_1(state[order-1], parCoeff[order-1])); + + FOR (i = order-2; i >= 0; i--) { - x -= parCoeff[i] * state[i]; - state[i + 1] = parCoeff[i] * x + state[i]; + x = L_sub(x, Mpy_32_16_1(state[i], parCoeff[i])); + state[i+1] = L_add(state[i], Mpy_32_16_1(x, parCoeff[i])); + move32(); } + move32(); state[0] = x; - return x; } - /** TNS analysis/synthesis filter. * @param spectrum input spectrum values. * @param numOfLines number of lines in the spectrum. @@ -600,250 +924,154 @@ static float IIRLattice( Inplace operation is supported, so it can be equal to spectrum. */ static void TnsFilter( - const float spectrum[], - const int16_t numOfLines, - const float parCoeff[], - const int16_t order, - TLinearPredictionFilter filter, - float *state, - float output[] ) + const Word32 spectrum[], + const Word16 numOfLines, + const Word16 parCoeff[], + const Word16 order, + TLinearPredictionFilter filter, + Word32 * state, + Word32 output[] +) { - int16_t j; + Word16 j; + - assert( ( order >= 0 ) && ( order <= TNS_MAX_FILTER_ORDER ) ); - assert( ( numOfLines > 0 ) || ( ( numOfLines == 0 ) && ( order == 0 ) ) ); + assert((order >= 0) && (order <= TNS_MAX_FILTER_ORDER)); + assert((numOfLines > 0) || ((numOfLines == 0) && (order == 0))); - if ( order == 0 ) + IF (order == 0) { - if ( ( spectrum != output ) && ( numOfLines > 0 ) ) + + test(); + IF ( s_and((spectrum != output), numOfLines > 0) ) { - mvr2r( spectrum, output, numOfLines ); + Copy32(spectrum, output, numOfLines); } } - else + ELSE { - for ( j = 0; j < numOfLines; j++ ) { - output[j] = filter( order, parCoeff, state, spectrum[j] ); + + FOR (j = 0; j < numOfLines; j++) + { + move32(); + output[j] = filter(order, parCoeff, state, spectrum[j]); + } } } - return; } - -static void ITF_TnsFilter( - const float spectrum[], - const int16_t numOfLines, - const float A[], - const int16_t order, - float output[] ) +static void ITF_TnsFilter_fx( + const Word32 spectrum[], + const Word16 numOfLines, + const Word16 A[], /* ifdef FIX_ITF_OVERFLOW Q_A else Q14 */ + const Word16 Q_A, + const Word16 order, + Word32 output[] +) { - int16_t i, j; - float *p, buf[ITF_MAX_FILTER_ORDER + N_MAX]; - - assert( ( order >= 0 ) && ( order <= ITF_MAX_FILTER_ORDER ) ); - assert( ( numOfLines > 0 ) || ( ( numOfLines == 0 ) && ( order == 0 ) ) ); - - if ( order == 0 ) + Word16 i, j; + Word32 buf[ITF_MAX_FILTER_ORDER + N_MAX]; + Word32* p; + Word16 shift; + assert((order >= 0) && (order <= ITF_MAX_FILTER_ORDER)); + assert((numOfLines > 0) || ((numOfLines == 0) && (order == 0))); + + IF (order == 0) { - if ( ( spectrum != output ) && ( numOfLines > 0 ) ) + + test(); + IF ( s_and((spectrum != output), numOfLines > 0) ) { - mvr2r( spectrum, output, numOfLines ); + Copy32(spectrum, output, numOfLines); } } - else + ELSE { - p = buf + ITF_MAX_FILTER_ORDER; + shift = sub(15, Q_A); - set_f( buf, 0, ITF_MAX_FILTER_ORDER ); - mvr2r( spectrum, p, numOfLines ); - - for ( j = 0; j < numOfLines; j++, p++ ) + p = buf + ITF_MAX_FILTER_ORDER; + set32_fx(buf, 0, ITF_MAX_FILTER_ORDER); + Copy32(spectrum, p, numOfLines); + FOR (j = 0; j < numOfLines; j++) { - output[j] = p[0]; - for ( i = 1; i < order; i++ ) + Word32 L_tmp; + + L_tmp = L_add(p[0], 0); + FOR (i = 1; i < order; i++) { - output[j] += A[i] * p[-i]; + L_tmp = L_add(L_tmp, L_shl(Mpy_32_16_1(p[-i], A[i]), shift)); } + output[j] = L_tmp; + move32(); + ++p; } } - return; } +static void ITF_GetFilterParameters_fx( + Word32 rxx[], + const Word16 maxOrder, + Word16* A, /* ifdef FIX_ITF_OVERFLOW Q_A else Q14 */ + Word16* Q_A, + Word16* predictionGain +) +{ + Word16 i, j, i_2, tmp; + Word16 parCoeff[ITF_MAX_FILTER_ORDER]; + Word32 epsP[ITF_MAX_FILTER_ORDER+1], L_tmp; -/*********************************************************************************************/ -/* Definitions of functions used in the mapping between TNS parameters and a bitstream. */ -/*********************************************************************************************/ - -/* Helper functions for hufmann table coding */ - -/********************************/ -/* Private functions */ -/********************************/ + /* compute filter in ParCor form with LeRoux-Gueguen algorithm */ + L_tmp = E_LPC_schur(rxx, parCoeff, epsP, maxOrder); + BASOP_SATURATE_WARNING_OFF_EVS /* Allow saturation, this value is compared against a threshold. */ + *predictionGain = divide3232(L_shr(epsP[0], PRED_GAIN_E), L_tmp); + BASOP_SATURATE_WARNING_ON_EVS -/** Autocorrelation to parcor coefficients. - * Conversion of autocorrelation to parcor/reflection coefficients. - * @param input Autocorrelation function/coefficients. - * @param parCoeff output filter (PARCOR) coefficients. - * @param order filter order. - * @return prediction gain. - */ -static float ITF_AutoToLPcoef( - const float input[], - float a[], - const int16_t order ) -{ - int16_t i, j; - float tmp, tmp2; - float workBuffer[2 * ITF_MAX_FILTER_ORDER]; - float parCoeff[ITF_MAX_FILTER_ORDER]; - float *const pWorkBuffer = &workBuffer[order]; /* temp pointer */ - - for ( i = 0; i < order; i++ ) { - workBuffer[i] = input[i]; - pWorkBuffer[i] = input[i + 1]; - } + Word32 A32[ITF_MAX_FILTER_ORDER]; + Word16 tmp1_l, tmp1_h, tmp2_l, tmp2_h; - for ( i = 0; i < order; i++ ) - { - if ( workBuffer[0] < 1.0f / 65536.0f ) - { - tmp = 0; - } - else + /* Convert ParCor / reflection coefficients to LPC */ + A32[0] = 134217728l/*1.0 Q27*/; + move16(); /* Q11+16 */ + A32[1] = L_shr(L_deposit_h(parCoeff[0]), 4); /* Q11+16 */ + + FOR (i=1; i Q14 */ + FOR (i=0; i HLM_MIN_NRG ); iSubdivisions++ ) - { - fac = 1.0f / norms[iSubdivisions]; - iStartLine = startLine + spectrumLength * iSubdivisions / nSubdivisions; - iEndLine = startLine + spectrumLength * ( iSubdivisions + 1 ) / nSubdivisions; - pWindow = tnsAcfWindow; - - /* For additional loop condition */ - /* Variable initialization */ - for ( lag = 1; lag <= maxOrder; lag++ ) - { - rxx[lag] += fac * ( *pWindow ) * dotp( pSpectrum + iStartLine - IGF_START_MN, pSpectrum + iStartLine - IGF_START_MN + lag, iEndLine - iStartLine - lag ); - pWindow++; - } - } - - *predictionGain = 0; - if ( iSubdivisions == nSubdivisions ) /* meaning there is no subdivision with low energy */ - { - rxx[0] = (float) nSubdivisions; - - /* Limit the maximum order to spectrum length/4 */ - *predictionGain = ITF_AutoToLPcoef( rxx, A, min( maxOrder, spectrumLength / 4 ) ); - - *curr_order = maxOrder; - } - - return 1; -} diff --git a/lib_com/tns_base_flt.c b/lib_com/tns_base_flt.c new file mode 100644 index 000000000..c0cffa830 --- /dev/null +++ b/lib_com/tns_base_flt.c @@ -0,0 +1,849 @@ +/****************************************************************************************************** + + (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/*==================================================================================== + EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0 + ====================================================================================*/ + +#include +#include +#include "options.h" +#include "cnst.h" +#include "rom_com.h" +#include "prot.h" +#include "stat_com.h" +#include "wmc_auto.h" + + +/*---------------------------------------------------------------------------- + * Local constants + *---------------------------------------------------------------------------*/ + +#define HLM_MIN_NRG PCM16_TO_FLT_FAC +#define MAX_SUBDIVISIONS 3 + + +/*---------------------------------------------------------------------------- + * Local prototypes + *---------------------------------------------------------------------------*/ + + +static void Index2Parcor( const int16_t index[], float parCoeff[], const int16_t order ); + +static float FIRLattice( const int16_t order, const float *parCoeff, float *state, float x ); + +static float IIRLattice( const int16_t order, const float *parCoeff, float *state, float x ); + +static void TnsFilter( const float spectrum[], const int16_t numOfLines, const float parCoeff[], const int16_t order, TLinearPredictionFilter_flt filter, float *state, float output[] ); + + +/*-------------------------------------------------------------------* + * InitTnsConfiguration() + * + *-------------------------------------------------------------------*/ + +void InitTnsConfiguration_flt( + const int16_t bwidth, + const int16_t frameLength, + STnsConfig *pTnsConfig, + const int16_t igfStopFreq, + const int32_t total_brate, + const int16_t element_mode, + const int16_t MCT_flag ) +{ + int32_t nSampleRate; + int16_t iFilter; + int16_t *startLineFilter = &pTnsConfig->iFilterBorders[1]; + + nSampleRate = inner_frame_tbl[bwidth] * FRAMES_PER_SEC; + + /* Sanity checks */ + assert( ( nSampleRate > 0 ) && ( frameLength > 0 ) && ( pTnsConfig != NULL ) ); + if ( ( nSampleRate <= 0 ) || ( frameLength <= 0 ) || ( pTnsConfig == NULL ) ) + { + return /*TNS_FATAL_ERROR*/; + } + + /* WMOPS: All initializations are either for safety or static (tables) and thus not to be counted */ + /* Initialize TNS filter flag and maximum order */ + pTnsConfig->maxOrder = TNS_MAX_FILTER_ORDER; + if ( total_brate <= ACELP_32k ) + { + pTnsConfig->nMaxFilters = sizeof( tnsParametersIGF32kHz_LowBR ) / sizeof( tnsParametersIGF32kHz_LowBR[0] ); + + pTnsConfig->pTnsParameters = tnsParametersIGF32kHz_LowBR; + } + else + { + if ( nSampleRate > 32000 && nSampleRate == 100 * frameLength ) + { + pTnsConfig->nMaxFilters = sizeof( tnsParameters48kHz_grouped ) / sizeof( tnsParameters48kHz_grouped[0] ); + pTnsConfig->pTnsParameters = tnsParameters48kHz_grouped; + } + else if ( nSampleRate > 16000 ) + { + if ( ( element_mode > IVAS_SCE ) && ( total_brate >= ( MCT_flag ? IVAS_32k : IVAS_48k ) ) ) + { + pTnsConfig->nMaxFilters = sizeof( tnsParameters32kHz_Stereo ) / sizeof( tnsParameters32kHz_Stereo[0] ); + if ( nSampleRate == 100 * frameLength ) /* sub-frame length is <= 10 ms */ + { + pTnsConfig->pTnsParameters = tnsParameters32kHz_grouped; + } + else + { + pTnsConfig->pTnsParameters = tnsParameters32kHz_Stereo; + } + } + else + { + pTnsConfig->nMaxFilters = sizeof( tnsParameters32kHz ) / sizeof( tnsParameters32kHz[0] ); + if ( nSampleRate == 100 * frameLength ) /* sub-frame length is <= 10 ms */ + { + pTnsConfig->pTnsParameters = tnsParameters32kHz_grouped; + } + else + { + pTnsConfig->pTnsParameters = tnsParameters32kHz; + } + } + } + else + { + if ( nSampleRate == 100 * frameLength ) /* sub-frame length is <= 10 ms */ + { + pTnsConfig->nMaxFilters = sizeof( tnsParameters16kHz_grouped ) / sizeof( tnsParameters16kHz_grouped[0] ); + pTnsConfig->pTnsParameters = tnsParameters16kHz_grouped; + } + else + { + pTnsConfig->nMaxFilters = sizeof( tnsParameters16kHz ) / sizeof( tnsParameters16kHz[0] ); + pTnsConfig->pTnsParameters = tnsParameters16kHz; + } + } + } + + assert( pTnsConfig->nMaxFilters <= TNS_MAX_NUM_OF_FILTERS ); + + /* Set starting MDCT line for each filter based on the starting frequencies from the TNS table */ + for ( iFilter = 0; iFilter < pTnsConfig->nMaxFilters; iFilter++ ) + { + assert( pTnsConfig->pTnsParameters[iFilter].startLineFrequency < 0.5f * nSampleRate ); + startLineFilter[iFilter] = (int16_t) ( ( frameLength * 2 * pTnsConfig->pTnsParameters[iFilter].startLineFrequency ) / nSampleRate ); + } + if ( igfStopFreq > 0 ) + { + pTnsConfig->iFilterBorders[0] = (int16_t) ( ( frameLength * 2 * igfStopFreq ) / nSampleRate ); + } + else + { + pTnsConfig->iFilterBorders[0] = frameLength; + } + + pTnsConfig->allowTnsOnWhite = 0; + + return /*TNS_NO_ERROR*/; +} + + +/*-------------------------------------------------------------------* + * ApplyTnsFilter() + * + *-------------------------------------------------------------------*/ + +void ApplyTnsFilter_flt( + STnsConfig const *pTnsConfig, + STnsData const *pTnsData, + float spectrum[], + const int16_t fIsAnalysis ) +{ + TLinearPredictionFilter_flt filter; + float state[TNS_MAX_FILTER_ORDER]; + int16_t iFilter; + int16_t stopLine, startLine; + const int16_t *pBorders; + + filter = fIsAnalysis ? FIRLattice : IIRLattice; + set_f( state, 0, TNS_MAX_FILTER_ORDER ); + pBorders = pTnsConfig->iFilterBorders; + + for ( iFilter = pTnsConfig->nMaxFilters - 1; iFilter >= 0; iFilter-- ) + { + float parCoeff[TNS_MAX_FILTER_ORDER]; + const STnsFilter *pFilter = &pTnsData->filter[iFilter]; + + set_f( parCoeff, 0, TNS_MAX_FILTER_ORDER ); + stopLine = pBorders[iFilter]; + startLine = pBorders[iFilter + 1]; + + Index2Parcor( pFilter->coefIndex, parCoeff, pFilter->order ); + + TnsFilter( &spectrum[startLine], stopLine - startLine, parCoeff, pFilter->order, filter, state, &spectrum[startLine] ); + } + + return /*( pTnsData->nFilters < 0 ) ? TNS_FATAL_ERROR : TNS_NO_ERROR*/; +} + + +/*********************************************************************************************/ +/* Definitions of functions used in the mapping between TNS parameters and a bitstream. */ +/*********************************************************************************************/ + +/* Helper functions for hufmann table coding */ + +/** Get number of bits from a Huffman table. + * The table must be sorted by values. + */ +static int16_t GetBitsFromTable( int16_t value, const Coding codes[], const int16_t nSize ) +{ + (void) nSize; + assert( ( value >= 0 ) && ( value < nSize ) && ( nSize >= 0 ) && ( nSize <= 256 ) ); + return codes[value].nBits; +} + +/** Get the code for a value from a Huffman table. + * The table must be sorted by values. + */ +static int16_t EncodeUsingTable( int16_t value, const Coding codes[], const int16_t nSize ) +{ + (void) nSize; + assert( ( value >= 0 ) && ( value < nSize ) && ( nSize >= 0 ) && ( nSize <= 256 ) ); + return codes[value].code; +} + +/** Decode a value from a bitstream using a Huffman table. */ +static int16_t DecodeUsingTable( Decoder_State *st, int16_t *pValue, const Coding codes[], const int16_t nSize ) +{ + uint16_t code = 0; + uint8_t nBits = 0; + int16_t valueIndex = nSize; + + assert( ( nSize >= 0 ) && ( nSize <= 256 ) ); + /* Variable initialization. All are required! */ + while ( valueIndex == nSize ) + { + code = ( code << 1 ) + get_next_indice( st, 1 ); + ++nBits; + if ( nBits > nSize || nBits > 16 ) + { + st->BER_detect = 1; + *pValue = 0; + return -1; + } + for ( valueIndex = 0; valueIndex < nSize; valueIndex++ ) + { + if ( codes[valueIndex].nBits == nBits ) + { + if ( codes[valueIndex].code == code ) + { + break; + } + } + } + /* Loop condition */ + } + + if ( valueIndex < nSize ) + { + *pValue = codes[valueIndex].value; + } + else + { + st->BER_detect = 1; + *pValue = 0; + return -1; + } + + return nBits; +} + +/* TNS filter coefficients */ + +//void const *GetTnsFilterCoeff_flt( void const *p, const int16_t index, int16_t *pValue ) +//{ +// *pValue = ( (int16_t const *) p )[index] + INDEX_SHIFT; +// return NULL; +//} + +//void *SetTnsFilterCoeff_flt( void *p, const int16_t index, const int16_t value ) +//{ +// ( (int16_t *) p )[index] = value - INDEX_SHIFT; +// return NULL; +//} + +//int16_t GetSWBTCX20TnsFilterCoeffBits_flt( const int16_t value, const int16_t index ) +//{ +// assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); +// return GetBitsFromTable( value, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes ); +//} + +//int16_t EncodeSWBTCX20TnsFilterCoeff_flt( const int16_t value, const int16_t index ) +//{ +// assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); +// return EncodeUsingTable( value, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes ); +//} + +int16_t DecodeSWBTCX20TnsFilterCoeff_flt( Decoder_State *st, const int16_t index, int16_t *pValue ) +{ + assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); + return DecodeUsingTable( st, pValue, codesTnsCoeffSWBTCX20[index], nTnsCoeffCodes ); +} + +//int16_t GetSWBTCX10TnsFilterCoeffBits_flt( const int16_t value, const int16_t index ) +//{ +// assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); +// return GetBitsFromTable( value, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes ); +//} + +//int16_t EncodeSWBTCX10TnsFilterCoeff_flt( const int16_t value, const int16_t index ) +//{ +// assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); +// return EncodeUsingTable( value, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes ); +//} + +int16_t DecodeSWBTCX10TnsFilterCoeff_flt( Decoder_State *st, const int16_t index, int16_t *pValue ) +{ + assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); + return DecodeUsingTable( st, pValue, codesTnsCoeffSWBTCX10[index], nTnsCoeffCodes ); +} + +//int16_t GetWBTCX20TnsFilterCoeffBits_flt( const int16_t value, const int16_t index ) +//{ +// assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); +// return GetBitsFromTable( value, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes ); +//} + +//int16_t EncodeWBTCX20TnsFilterCoeff_flt( const int16_t value, const int16_t index ) +//{ +// assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); +// return EncodeUsingTable( value, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes ); +//} + +int16_t DecodeWBTCX20TnsFilterCoeff_flt( Decoder_State *st, const int16_t index, int16_t *pValue ) +{ + assert( ( index >= 0 ) && ( index < nTnsCoeffTables ) ); + return DecodeUsingTable( st, pValue, codesTnsCoeffWBTCX20[index], nTnsCoeffCodes ); +} + + +/* TNS filter order */ + +//void const *GetTnsFilterOrder_flt( void const *p, const int16_t index, int16_t *pValue ) +//{ +// *pValue = ( (STnsFilter const *) p )[index].order; +// return ( (STnsFilter const *) p )[index].coefIndex; +//} + +//void *SetTnsFilterOrder_flt( void *p, const int16_t index, const int16_t value ) +//{ +// ( (STnsFilter *) p )[index].order = value; +// return ( (STnsFilter *) p )[index].coefIndex; +//} + +//int16_t GetTnsFilterOrderBitsSWBTCX20_flt( const int16_t value, const int16_t index ) +//{ +// (void) index; +// return GetBitsFromTable( value - 1, codesTnsOrderTCX20, nTnsOrderCodes ); +//} + +//int16_t EncodeTnsFilterOrderSWBTCX20_flt( const int16_t value, const int16_t index ) +//{ +// (void) index; +// return EncodeUsingTable( value - 1, codesTnsOrderTCX20, nTnsOrderCodes ); +//} + +int16_t DecodeTnsFilterOrderSWBTCX20_flt( Decoder_State *st, const int16_t index, int16_t *pValue ) +{ + (void) index; + return DecodeUsingTable( st, pValue, codesTnsOrderTCX20, nTnsOrderCodes ); +} + +int16_t GetTnsFilterOrderBitsSWBTCX10_flt( const int16_t value, const int16_t index ) +{ + (void) index; + return GetBitsFromTable( value - 1, codesTnsOrderTCX10, nTnsOrderCodes ); +} + +int16_t EncodeTnsFilterOrderSWBTCX10_flt( const int16_t value, const int16_t index ) +{ + (void) index; + return EncodeUsingTable( value - 1, codesTnsOrderTCX10, nTnsOrderCodes ); +} + +int16_t DecodeTnsFilterOrderSWBTCX10_flt( Decoder_State *st, const int16_t index, int16_t *pValue ) +{ + (void) index; + return DecodeUsingTable( st, pValue, codesTnsOrderTCX10, nTnsOrderCodes ); +} + +//int16_t GetTnsFilterOrderBits_flt( const int16_t value, const int16_t index ) +//{ +// (void) index; +// return GetBitsFromTable( value - 1, codesTnsOrder, nTnsOrderCodes ); +//} + +//int16_t EncodeTnsFilterOrder_flt( const int16_t value, const int16_t index ) +//{ +// (void) index; +// return EncodeUsingTable( value - 1, codesTnsOrder, nTnsOrderCodes ); +//} + +int16_t DecodeTnsFilterOrder_flt( Decoder_State *st, const int16_t index, int16_t *pValue ) +{ + (void) index; + return DecodeUsingTable( st, pValue, codesTnsOrder, nTnsOrderCodes ); +} + +/* Number of TNS filters */ + +void const *GetNumOfTnsFilters_flt( void const *p, const int16_t index, int16_t *pValue ) +{ + *pValue = (int16_t) abs( ( (STnsData const *) p )[index].nFilters ); + return ( (STnsData const *) p )[index].filter; +} + +void *SetNumOfTnsFilters_flt( void *p, const int16_t index, const int16_t value ) +{ + ( (STnsData *) p )[index].nFilters = (int16_t) abs( value ); + return ( (STnsData *) p )[index].filter; +} + +/* TNS enabled/disabled flag */ + +//void const *GetTnsEnabled_flt( void const *p, const int16_t index, int16_t *pValue ) +//{ +// *pValue = ( (STnsData const *) p )[index].nFilters != 0 ? 1 : 0; +// return NULL; +//} + +//void *SetTnsEnabled_flt( void *p, const int16_t index, const int16_t value ) +//{ +// (void) p, (void) index, (void) value; +// return NULL; +//} + +/* TNS on whitened spectra flag */ + +void const *GetTnsOnWhite( void const *p, const int16_t index, int16_t *pValue ) +{ + *pValue = ( (STnsData const *) p )[index].tnsOnWhitenedSpectra > 0 ? 1 : 0; + return NULL; +} + +void *SetTnsOnWhite( void *p, const int16_t index, const int16_t value ) +{ + ( (STnsData *) p )[index].tnsOnWhitenedSpectra = value; + return NULL; +} + +//void const *GetTnsEnabledSingleFilter_flt( void const *p, const int16_t index, int16_t *pValue ) +//{ +// *pValue = ( (STnsData const *) p )[index].nFilters != 0 ? 1 : 0; +// return ( (STnsData const *) p )[index].filter; +//} + +//void *SetTnsEnabledSingleFilter_flt( void *p, const int16_t index, const int16_t value ) +//{ +// ( (STnsData *) p )[index].nFilters = value; +// return ( (STnsData *) p )[index].filter; +//} + + +/*-------------------------------------------------------------------* + * ResetTnsData() + * + *-------------------------------------------------------------------*/ + +void ResetTnsData_flt( + STnsData *pTnsData ) +{ + uint16_t iFilter; + + pTnsData->nFilters = 0; + pTnsData->tnsOnWhitenedSpectra = 0; + + for ( iFilter = 0; iFilter < sizeof( pTnsData->filter ) / sizeof( pTnsData->filter[0] ); iFilter++ ) + { + STnsFilter *const pTnsFilter = &pTnsData->filter[iFilter]; + pTnsFilter->spectrumLength = 0; + pTnsFilter->predictionGain_flt = 1.0f; + pTnsFilter->avgSqrCoef_flt = 0; + pTnsFilter->filterType = TNS_FILTER_OFF; + ClearTnsFilterCoefficients_flt( pTnsFilter ); + } + + return; +} + + +/*-------------------------------------------------------------------* + * ClearTnsFilterCoefficients_flt() + * + *-------------------------------------------------------------------*/ + +void ClearTnsFilterCoefficients_flt( + STnsFilter *pTnsFilter ) +{ + pTnsFilter->order = 0; + set_s( pTnsFilter->coefIndex, 0, TNS_MAX_FILTER_ORDER ); + + return; +} + +/** Inverse quantization for reflection coefficients. + * + * @param index input quantized values. + * @param parCoeff output reflection coefficients. + * @param order number of coefficients/values. + */ +static void Index2Parcor( + const int16_t index[], + float parCoeff[], + const int16_t order ) +{ + const float *values = tnsCoeff4_flt; + int16_t i; + + for ( i = 0; i < order; i++ ) + { + parCoeff[i] = values[index[i] + INDEX_SHIFT]; + } + + return; +} + +/* Linear prediction analysis filter. */ +static float FIRLattice( + const int16_t order, + const float *parCoeff, + float *state, + float x ) +{ + int16_t i; + float tmpSave; + + tmpSave = x; + for ( i = 0; i < order - 1; i++ ) + { + const float tmp = parCoeff[i] * x + state[i]; + /* Variable initialization */ + x += parCoeff[i] * state[i]; + state[i] = tmpSave; + tmpSave = tmp; + } + + /* last stage: only need half operations */ + x += parCoeff[order - 1] * state[order - 1]; + state[order - 1] = tmpSave; + + return x; +} + +/* Linear prediction synthesis filter. */ +static float IIRLattice( + const int16_t order, + const float *parCoeff, + float *state, + float x ) +{ + int16_t i; + + /* first stage: no need to calculate state[order-1] */ + x -= parCoeff[order - 1] * state[order - 1]; + for ( i = order - 2; i >= 0; i-- ) + { + x -= parCoeff[i] * state[i]; + state[i + 1] = parCoeff[i] * x + state[i]; + } + + state[0] = x; + + return x; +} + +/** TNS analysis/synthesis filter. + * @param spectrum input spectrum values. + * @param numOfLines number of lines in the spectrum. + * @param parCoeff filter (PARCOR) coefficients. + * @param order filter order. + * @param filter function that implements filtering. + By this function it is defined whether analysis or synthesis is performed. + * @param output filtered output spectrum values. + Inplace operation is supported, so it can be equal to spectrum. + */ +static void TnsFilter( + const float spectrum[], + const int16_t numOfLines, + const float parCoeff[], + const int16_t order, + TLinearPredictionFilter_flt filter, + float *state, + float output[] ) +{ + int16_t j; + + assert( ( order >= 0 ) && ( order <= TNS_MAX_FILTER_ORDER ) ); + assert( ( numOfLines > 0 ) || ( ( numOfLines == 0 ) && ( order == 0 ) ) ); + + if ( order == 0 ) + { + if ( ( spectrum != output ) && ( numOfLines > 0 ) ) + { + mvr2r( spectrum, output, numOfLines ); + } + } + else + { + for ( j = 0; j < numOfLines; j++ ) + { + output[j] = filter( order, parCoeff, state, spectrum[j] ); + } + } + + return; +} + + +static void ITF_TnsFilter( + const float spectrum[], + const int16_t numOfLines, + const float A[], + const int16_t order, + float output[] ) +{ + int16_t i, j; + float *p, buf[ITF_MAX_FILTER_ORDER + N_MAX]; + + assert( ( order >= 0 ) && ( order <= ITF_MAX_FILTER_ORDER ) ); + assert( ( numOfLines > 0 ) || ( ( numOfLines == 0 ) && ( order == 0 ) ) ); + + if ( order == 0 ) + { + if ( ( spectrum != output ) && ( numOfLines > 0 ) ) + { + mvr2r( spectrum, output, numOfLines ); + } + } + else + { + p = buf + ITF_MAX_FILTER_ORDER; + + set_f( buf, 0, ITF_MAX_FILTER_ORDER ); + mvr2r( spectrum, p, numOfLines ); + + for ( j = 0; j < numOfLines; j++, p++ ) + { + output[j] = p[0]; + for ( i = 1; i < order; i++ ) + { + output[j] += A[i] * p[-i]; + } + } + } + + return; +} + + +/*********************************************************************************************/ +/* Definitions of functions used in the mapping between TNS parameters and a bitstream. */ +/*********************************************************************************************/ + +/* Helper functions for hufmann table coding */ + +/********************************/ +/* Private functions */ +/********************************/ + +/** Autocorrelation to parcor coefficients. + * Conversion of autocorrelation to parcor/reflection coefficients. + * @param input Autocorrelation function/coefficients. + * @param parCoeff output filter (PARCOR) coefficients. + * @param order filter order. + * @return prediction gain. + */ +static float ITF_AutoToLPcoef( + const float input[], + float a[], + const int16_t order ) +{ + int16_t i, j; + float tmp, tmp2; + float workBuffer[2 * ITF_MAX_FILTER_ORDER]; + float parCoeff[ITF_MAX_FILTER_ORDER]; + float *const pWorkBuffer = &workBuffer[order]; /* temp pointer */ + + for ( i = 0; i < order; i++ ) + { + workBuffer[i] = input[i]; + pWorkBuffer[i] = input[i + 1]; + } + + for ( i = 0; i < order; i++ ) + { + if ( workBuffer[0] < 1.0f / 65536.0f ) + { + tmp = 0; + } + else + { + tmp = -pWorkBuffer[i] / workBuffer[0]; + } + + /* compensate for calculation inaccuracies limit reflection coefs to ]-1,1[ */ + tmp = min( 0.999f, max( -0.999f, tmp ) ); + + parCoeff[i] = tmp; + for ( j = i; j < order; j++ ) + { + tmp2 = pWorkBuffer[j] + tmp * workBuffer[j - i]; + workBuffer[j - i] += tmp * pWorkBuffer[j]; + pWorkBuffer[j] = tmp2; + } + } + + /* Convert ParCor / reflection coefficients to LPC */ + a[0] = 1.0f; + a[1] = parCoeff[0]; + + for ( i = 1; i < order; i++ ) + { + for ( j = 0; j < i / 2; j++ ) + { + tmp = a[j + 1]; + a[j + 1] += parCoeff[i] * a[i - 1 - j + 1]; + a[i - 1 - j + 1] += parCoeff[i] * tmp; + } + if ( i & 1 ) + { + a[j + 1] += parCoeff[i] * a[j + 1]; + } + + a[i + 1] = parCoeff[i]; + } + + return ( ( input[0] + 1e-30f ) / ( workBuffer[0] + 1e-30f ) ); +} + + +/*-------------------------------------------------------------------* + * ITF_Apply() + * + *-------------------------------------------------------------------*/ + +void ITF_Apply( + float spectrum[], + const int16_t startLine, + const int16_t stopLine, + const float *A, + const int16_t order ) +{ + ITF_TnsFilter( &spectrum[startLine], stopLine - startLine, A, order, &spectrum[startLine] ); + + return; +} + + +/*-------------------------------------------------------------------* + * ITF_Detect() + * + * + *-------------------------------------------------------------------*/ + +int16_t ITF_Detect( + const float pSpectrum[], + const int16_t startLine, + const int16_t stopLine, + const int16_t maxOrder, + float *A, + float *predictionGain, + int16_t *curr_order ) +{ + float norms[MAX_SUBDIVISIONS]; + int16_t nSubdivisions; + int16_t iStartLine, iEndLine, spectrumLength; + float rxx[ITF_MAX_FILTER_ORDER + 1]; + float fac; + const float *pWindow; + int16_t iSubdivisions, lag; + + nSubdivisions = MAX_SUBDIVISIONS; + set_f( norms, 0.f, MAX_SUBDIVISIONS ); + set_f( rxx, 0.f, ITF_MAX_FILTER_ORDER + 1 ); /* This initialization is required */ + + if ( maxOrder <= 0 ) + { + return 0; + } + + /* Calculate norms for each spectrum part */ + for ( iSubdivisions = 0; iSubdivisions < nSubdivisions; iSubdivisions++ ) + { + iStartLine = startLine + ( stopLine - startLine ) * iSubdivisions / nSubdivisions; + iEndLine = startLine + ( stopLine - startLine ) * ( iSubdivisions + 1 ) / nSubdivisions; + + /* Variable initialization */ + norms[iSubdivisions] = sum2_f( pSpectrum + iStartLine - IGF_START_MN, iEndLine - iStartLine ); + } + + /* Calculate normalized autocorrelation for spectrum subdivision and get TNS filter parameters based on it */ + spectrumLength = stopLine - startLine; + + /* Variable initialization */ + for ( iSubdivisions = 0; ( iSubdivisions < nSubdivisions ) && ( norms[iSubdivisions] > HLM_MIN_NRG ); iSubdivisions++ ) + { + fac = 1.0f / norms[iSubdivisions]; + iStartLine = startLine + spectrumLength * iSubdivisions / nSubdivisions; + iEndLine = startLine + spectrumLength * ( iSubdivisions + 1 ) / nSubdivisions; + pWindow = tnsAcfWindow; + + /* For additional loop condition */ + /* Variable initialization */ + for ( lag = 1; lag <= maxOrder; lag++ ) + { + rxx[lag] += fac * ( *pWindow ) * dotp( pSpectrum + iStartLine - IGF_START_MN, pSpectrum + iStartLine - IGF_START_MN + lag, iEndLine - iStartLine - lag ); + pWindow++; + } + } + + *predictionGain = 0; + if ( iSubdivisions == nSubdivisions ) /* meaning there is no subdivision with low energy */ + { + rxx[0] = (float) nSubdivisions; + + /* Limit the maximum order to spectrum length/4 */ + *predictionGain = ITF_AutoToLPcoef( rxx, A, min( maxOrder, spectrumLength / 4 ) ); + + *curr_order = maxOrder; + } + + return 1; +} diff --git a/lib_dec/dec_tcx.c b/lib_dec/dec_tcx.c index 320519d49..1920b6f3c 100644 --- a/lib_dec/dec_tcx.c +++ b/lib_dec/dec_tcx.c @@ -1043,7 +1043,7 @@ void decoder_tcx_invQ( { assert( !"Not adapted to warped scale" ); } - tcxFormantEnhancement( xn_buf, gainlpc2, x, L_frame ); + tcxFormantEnhancement_flt( xn_buf, gainlpc2, x, L_frame ); } } @@ -1126,7 +1126,7 @@ void decoder_tcx_noisefilling( if ( !bfi && ( fac_ns > 0.0f ) ) { - firstLine = tcxGetNoiseFillingTilt( A, L_frame, ( total_brate >= ACELP_13k20 && !st->rf_flag ), &noiseTiltFactor ); + firstLine = tcxGetNoiseFillingTilt_flt( A, L_frame, ( total_brate >= ACELP_13k20 && !st->rf_flag ), &noiseTiltFactor ); if ( st->tcxonly ) { @@ -1298,7 +1298,7 @@ void decoder_tcx_noisefilling( } noiseTiltFactor = 1.0f; - tcxGetNoiseFillingTilt( A, L_frame, ( total_brate >= ACELP_13k20 && !st->rf_flag ), &noiseTiltFactor ); + tcxGetNoiseFillingTilt_flt( A, L_frame, ( total_brate >= ACELP_13k20 && !st->rf_flag ), &noiseTiltFactor ); if ( st->element_mode == IVAS_CPE_MDCT && !MCT_flag ) { @@ -1528,7 +1528,7 @@ void decoder_tcx_tns( tcx5TnsGrouping( L >> 1, hTcxCfg->tnsConfig[0][0].iFilterBorders[0] >> 1, x ); } - ApplyTnsFilter( hTcxCfg->pCurrentTnsConfig, tnsData, x, 0 ); + ApplyTnsFilter_flt( hTcxCfg->pCurrentTnsConfig, tnsData, x, 0 ); if ( ( L_frame == st->L_frame >> 1 ) && st->tcxonly && isTCX5 ) { diff --git a/lib_dec/nelp_dec.c b/lib_dec/nelp_dec.c index 77b3703d1..5ca7cf254 100644 --- a/lib_dec/nelp_dec.c +++ b/lib_dec/nelp_dec.c @@ -155,7 +155,7 @@ void nelp_decoder( if ( coder_type == UNVOICED && st->bwidth == NB ) { - polezero_filter( ptr, ptr_tmp, L_FRAME, bp1_num_coef_nb_fx_order7, bp1_den_coef_nb_fx_order7, 7, hSC_VBR->bp1_filt_mem_nb_dec ); + polezero_filter( ptr, ptr_tmp, L_FRAME, bp1_num_coef_nb_fx_order7_flt, bp1_den_coef_nb_fx_order7_flt, 7, hSC_VBR->bp1_filt_mem_nb_dec ); mvr2r( ptr_tmp, ptr, L_FRAME ); } diff --git a/lib_dec/tns_base_dec.c b/lib_dec/tns_base_dec.c index 444c46504..baa4c0dbe 100644 --- a/lib_dec/tns_base_dec.c +++ b/lib_dec/tns_base_dec.c @@ -107,7 +107,7 @@ int16_t DecodeTnsData( int16_t *pnSize, STnsData *pTnsData ) { - ResetTnsData( pTnsData ); + ResetTnsData_flt( pTnsData ); if ( pTnsConfig->nMaxFilters > 1 ) { diff --git a/lib_enc/SNR_calc_fx.c b/lib_enc/SNR_calc_fx.c new file mode 100644 index 000000000..360cc589b --- /dev/null +++ b/lib_enc/SNR_calc_fx.c @@ -0,0 +1,543 @@ +/*==================================================================================== + EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0 + ====================================================================================*/ + +#include +#include "options.h" +#include "options.h" +#include "basop_util.h" +#include "vad_basop.h" +#include "prot_fx2.h" +#include "rom_enc.h" + + + /*-------------------------------------------------------------------* + * calc_lf_snr() + * + * + *-------------------------------------------------------------------*/ + +void calc_lf_snr( + Word32 *lf_snr_smooth, /* o : smoothed lf_snr*/ + Word32 *lf_snr, /* o : long time frequency domain + SNR calculated by l_speech_snr and l_silence_snr*/ + const Word32 l_speech_snr, /* i : sum of active frames snr */ + const Word32 l_speech_snr_count, /* i : amount of the active frame */ + const Word32 l_silence_snr, /* i : sum of the nonactive frames snr*/ + const Word32 l_silence_snr_count,/* i : amount of the nonactive frame */ + const Word16 fg_energy_count, /* i : amount of the foreground energy frame */ + const Word16 bg_energy_count, /* i : amount of the background energy frame */ + const Word16 bw_index /* i : band width index*/ +) +{ + + Word32 l_snr, div1, div2, tmp; + Word16 q_divout, q_divout1; + + + div1 = VAD_L_div(l_speech_snr, l_speech_snr_count, 16, 0, &q_divout); + div2 = VAD_L_div(l_silence_snr, l_silence_snr_count, 16, 0, &q_divout1); + l_snr = VAD_L_ADD(div1, q_divout, L_negate(div2), q_divout1, &q_divout); + + *lf_snr_smooth = MUL_F(*lf_snr_smooth, 29490/* 0.9 Q15 */); + move32(); + tmp = MUL_F(l_snr, 26214); + *lf_snr_smooth = VAD_L_ADD(*lf_snr_smooth, 25, tmp, add(3, q_divout), &q_divout1); + move32(); + *lf_snr_smooth = L_shr(*lf_snr_smooth, sub(q_divout1, 25)); + move32(); + l_snr = L_shr(l_snr, sub(q_divout, 25)); + + test(); + if ((LT_16(bg_energy_count, 56)) || (LT_16(fg_energy_count, 56))) + { + l_snr = 161061275/* 4.8 Q25 */; + move32(); + } + + l_snr = MUL_F(l_snr, 3932/* 0.12 Q15 */); + l_snr = L_sub(l_snr, 12079595/* 0.36 Q25 */); + + l_snr = L_max(0, l_snr); + l_snr = L_min(l_snr, MAX_LF_SNR_TAB[bw_index]); + + *lf_snr = l_snr; + move32(); + return; +} +/*-------------------------------------------------------------------* + * calc_lt_snr() + * + * + *-------------------------------------------------------------------*/ +void calc_lt_snr( + VAD_CLDFB_HANDLE hVAD_CLDFB, /* i/o: CLDFB VAD state */ + Word32 *lt_snr_org_fp, /* o : original long time SNR*/ + Word32 *lt_snr_fp, /* o : long time SNR calculated by fg_energy and bg_energy*/ + Word32 fg_energy, /* i : foreground energy sum */ + Word16 fg_energy_count, /* i : amount of the foreground energy frame */ + Word32 bg_energy, /* i : background energy sum */ + Word16 bg_energy_count, /* i : amount of the background energy frame */ + Word16 bw_index, /* i : band width index*/ + Word16 lt_noise_sp_center0 /* i : long time noise spectral center by 0*/ +) +{ + Word16 tmp_lt_noise_sp_center; + Word16 q_div1, q_div2, q_divout, q_divout1; + Word32 lt_snr_org; + Word32 lt_snr, div1, div2, tmp; + + + tmp_lt_noise_sp_center = sub(lt_noise_sp_center0, 1432/* 1.4 Q10 */); + if (GT_16(tmp_lt_noise_sp_center, 818/* 0.8 Q10 */)) + { + tmp_lt_noise_sp_center = 818/* 0.8 Q10 */; + move16(); + } + + if (tmp_lt_noise_sp_center < 0) + { + tmp_lt_noise_sp_center = 0; + move16(); + } + + div1 = MUL_F(fg_energy, bg_energy_count); + div1 = VAD_L_ADD(div1, hVAD_CLDFB->fg_energy_scale, 1, 126, &q_div1); + div2 = MUL_F(bg_energy, fg_energy_count); + div2 = VAD_L_ADD(div2, hVAD_CLDFB->bg_energy_scale, 1, 126, &q_div2); + if (div2 == 0) + { + div2 = 1; + move32(); /* div2==0 , may occur for >30000 frames all zero input */ + if (div1 != 0) + { + hVAD_CLDFB->bg_energy_scale = add(hVAD_CLDFB->fg_energy_scale, 50); + } + } + div2 = VAD_L_div(div1, div2, q_div1, q_div2, &q_divout); + lt_snr_org = VAD_Log2(div2, q_divout); + lt_snr_org = MUL_F(lt_snr_org, 9864); + lt_snr = lt_snr_org; move32(); + *lt_snr_org_fp = lt_snr; + move32(); + + test(); + IF(LT_16(bg_energy_count, 56) || LT_16(fg_energy_count, 56)) + { + lt_snr = 70464302/* 2.1 Q25 */; + move32(); + } + + IF(EQ_16(bw_index, CLDFBVAD_NB_ID)) + { + lt_snr = L_sub(L_shr(lt_snr, 1), 25165823/* 0.75 Q25 */); + } + ELSE IF(EQ_16(bw_index, CLDFBVAD_WB_ID)) + { + lt_snr = L_sub(L_shr(lt_snr, 1), 25165823/* 0.75 Q25 */); + } + ELSE + { + lt_snr = MUL_F(lt_snr, 15073/* 0.46 Q15 */); + lt_snr = L_sub(lt_snr, 23152557/* 0.69 Q25 */); + } + + tmp = MUL_F(lt_snr, 13107/* 0.4 Q15 */); + + tmp = L_add(L_shr(tmp, 1), -26214); + + tmp = MUL_F(tmp, 13107/* 0.4 Q15 */); + tmp = MUL_F(tmp, tmp_lt_noise_sp_center); + lt_snr = VAD_L_ADD(lt_snr, 25, tmp, 19, &q_divout1); + lt_snr = L_shr(lt_snr, sub(q_divout1, 25)); + + lt_snr = L_max(0, lt_snr); + + if (GT_32(lt_snr, 67108862/* 2.0 Q25 */)) + { + lt_snr = 67108862/* 2.0 Q25 */; + move32(); + } + + *lt_snr_fp = lt_snr; + move32(); + return; +} + +/*-------------------------------------------------------------------* + * calc_snr_flux() + * + * + *-------------------------------------------------------------------*/ +void calc_snr_flux( + Word32 tsnr, /* i : time-domain SNR*/ + Word32 *pre_snr, /* i/o: time-domain SNR storage*/ + Word32 *snr_flux_fp /* o : average tsnr*/ +) +{ + Word32 i; + Word32 tmp, snr_flux; + Word16 s16MaxCoefNorm; + /*save a new time-domain SNR to pre_snr[0]*/ + + + test(); + IF((LT_32(L_shr(tsnr, 1), 43620759/* 2.6f/2.0f Q25 */)) && tsnr > 0) + { + pre_snr[0] = tsnr; + move32(); + } + ELSE IF(tsnr <= 0) + { + pre_snr[0] = 0; + move32(); + } + ELSE + { + pre_snr[0] = 87241517/* 2.6 Q25 */; + move32(); + } + + /*calculate snr_flux*/ + snr_flux = 0; + move32(); + s16MaxCoefNorm = sub(ffr_getSfWord32(pre_snr, 32), 5); + FOR(i = 0; i < 32; i++) + { + tmp = L_shl(pre_snr[i], s16MaxCoefNorm); + snr_flux = L_add(snr_flux, tmp); + } + snr_flux = L_shr(snr_flux, add(s16MaxCoefNorm, 5)); + *snr_flux_fp = snr_flux; + move32(); + + /*update the tsnr storage pre_snr*/ + FOR(i = PRE_SNR_NUM - 1; i > 0; i--) + { + pre_snr[i] = pre_snr[i - 1]; + move32(); + } + return; + +} + + +/*-------------------------------------------------------------------* + * SNR_calc() + * + * + *-------------------------------------------------------------------*/ +void snr_calc( + VAD_CLDFB_HANDLE hVAD_CLDFB, /* i/o: CLDFB VAD state */ + const Word16 sacle_sbpower, /* i : the Scaling of sbpower*/ + Word32 *snr, /* o : frequency domain SNR */ + Word32* tsnr, /* o : time domain SNR */ + const Word32 frame_energy, /* i : current frame energy */ + const Word32 bwidth /* i : audio band width*/ +) +{ + Word32 i; + Word32 tmpframe_eg, tmpsb_eg, constff, div1, div2; + Word32 snr_tmp, tmp; + + Word32 SNR_sb_num; + Word32 *sb_bg_energy; + Word32 *frame_sb_energy; + Word32 t_bg_energy; + Word16 tmp_addQ1, tmp_addQ2, minscale, minscale1, minscale2, s16MaxCoefNorm, q_divout; + Word32 tmpspec_amp; + Word32 const CONSTfix = 1759218560; + Word32 snr_tmpidx[12] = { 0 }; + + + SNR_sb_num = SNR_SUB_BAND_NUM[bwidth - CLDFBVAD_NB_ID]; + move16(); + sb_bg_energy = hVAD_CLDFB->sb_bg_energy; + frame_sb_energy = hVAD_CLDFB->frame_sb_energy; + t_bg_energy = hVAD_CLDFB->t_bg_energy; + move32(); + + snr_tmp = 0; + move32(); + FOR(i = 0; i < SNR_sb_num; i++) + { + div1 = VAD_L_ADD(frame_sb_energy[i], hVAD_CLDFB->frame_sb_energy_scale, CONSTfix, 44, &tmp_addQ1); + div2 = VAD_L_ADD(sb_bg_energy[i], hVAD_CLDFB->sb_bg_energy_scale, CONSTfix, 44, &tmp_addQ2); + tmp = VAD_L_div(div1, div2, tmp_addQ1, tmp_addQ2, &q_divout); + tmp = VAD_Log2(tmp, q_divout); + + if (GT_32(tmp, -3355443/* -0.10 Q25 */)) + { + snr_tmpidx[i] = tmp; + move32(); + } + } + + s16MaxCoefNorm = sub(ffr_getSfWord32(snr_tmpidx, (Word16)SNR_sb_num), 4); + FOR(i = 0; i < SNR_sb_num; i++) + { + tmpspec_amp = L_shl(snr_tmpidx[i], s16MaxCoefNorm); + snr_tmp = L_add(snr_tmp, tmpspec_amp); + } + snr_tmp = L_max(0, snr_tmp); + snr_tmp = MUL_F(snr_tmp, BAND_MUL[bwidth - CLDFBVAD_NB_ID]); + *snr = L_shr(snr_tmp, s16MaxCoefNorm); + move32(); + + IF(bwidth == CLDFBVAD_SWB_ID) + { + IF(t_bg_energy) + { + minscale = norm_l(t_bg_energy); + minscale2 = sub(s_min(add(minscale, hVAD_CLDFB->scale_t_bg_energy), 31), 1); + tmpsb_eg = L_shr(t_bg_energy, sub(hVAD_CLDFB->scale_t_bg_energy, minscale2)); + constff = L_shr(1, sub(31, minscale2)); + } + ELSE + { + tmpsb_eg = 0; move32(); + constff = 1; move32(); + minscale2 = 31; + move16(); + } + div2 = L_add(tmpsb_eg, constff); + tmp = VAD_L_div(frame_energy, div2, sacle_sbpower, minscale2, &q_divout); + IF(tmp) + { + minscale = norm_l(tmp); + minscale2 = sub(s_min(add(minscale, q_divout), 31), 1); + tmpsb_eg = L_shr(tmp, limitScale32(sub(q_divout, minscale2))); + constff = L_shr(1, sub(31, minscale2)); + tmp = L_add(tmpsb_eg, constff); + } + ELSE + { + tmp = 1; move32(); + minscale2 = 31; + move16(); + } + *tsnr = VAD_Log2(tmp, minscale2); + move32(); + *tsnr = L_add(*tsnr, MUL_F(*tsnr, 6226)); /* *tsnr *= 1.2; */ + move32(); + } + ELSE + { + IF(frame_energy) + { + minscale = norm_l(frame_energy); + minscale1 = sub(s_min(add(minscale,sacle_sbpower),44),1); + tmpframe_eg = L_shr(frame_energy,sub(sacle_sbpower,minscale1)); + constff = L_shr(CONSTfix,sub(44,minscale1)); + } + ELSE + { + tmpframe_eg = 0; move32(); + constff = CONSTfix; move32(); + minscale1 = 44; + move16(); + } + div1 = L_add(tmpframe_eg, constff); + IF(t_bg_energy) + { + minscale = norm_l(t_bg_energy); + minscale2 = sub(s_min(add(minscale,hVAD_CLDFB->scale_t_bg_energy),44),1); + tmpsb_eg = L_shr(t_bg_energy,sub(hVAD_CLDFB->scale_t_bg_energy,minscale2)); + constff = L_shr(CONSTfix,sub(44,minscale2)); + } + ELSE + { + tmpsb_eg = 0; move32(); + constff = CONSTfix; move32(); + minscale2 = 44; + move16(); + } + div2 = L_add(tmpsb_eg, constff); + tmp = VAD_L_div(div1, div2, minscale1, minscale2, &q_divout); + *tsnr = VAD_Log2(tmp,q_divout); + move32(); + } + return; +} + +Word32 construct_snr_thresh( + Word16 sp_center[], /* i : spectral center*/ + Word32 snr_flux, /* i : snr flux*/ + Word32 lt_snr, /* i : long time time domain snr*/ + Word32 l_snr, /* i : long time frequency domain snr*/ + Word32 continuous_speech_num, /* i : amount of continuous speech frames*/ + Word16 continuous_noise_num, /* i : amount of continuous noise frames*/ + Word32 fg_energy_est_start, /* i : whether if estimated energy*/ + Word16 bw_index /* i : band width index*/ +) +{ + + Word32 bw_snr, tmp_snr, snr_delta, test_l_snr, tmp, div1, div2; + + + + + snr_delta = COMVAD_INIT_SNR_DELTA[bw_index]; + move32(); + bw_snr = lt_snr; + move32(); + + + + test_l_snr = lt_snr; move32(); + IF(EQ_16(bw_index, CLDFBVAD_SWB_ID)) + { + + IF(GT_16(sp_center[3], 2864/* 2.80 Q10 */)) + { + snr_delta = snr_delta; + move32(); + } + ELSE IF(GT_16(sp_center[2], 2660/* 2.6 Q10 */)) + { + snr_delta = L_add(snr_delta, 1006633/* 0.03 Q25 */); + } + ELSE IF(GT_16(sp_center[2], 1637/* 1.6 Q10 */)) + { + snr_delta = L_add(snr_delta, 1677722/* 0.05 Q25 */); + } + ELSE IF(GT_16(sp_center[3], 1432/* 1.4 Q10 */)) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE + { + snr_delta = L_add(snr_delta , 13421773/* 0.40 Q25 */); + } + + tmp = MUL_F(l_snr, 3277/* 0.1 Q15 */); + tmp = L_add(tmp, 20132659/* 0.6 Q25 */); + + test(); + test(); + IF(GT_32(continuous_speech_num, 8) && EQ_32(fg_energy_est_start, 1)) + { + snr_delta = L_sub(snr_delta, 6710886/* 0.2 Q25 */); + } + ELSE IF(GT_16(continuous_noise_num, 12) && (GT_32(snr_flux, tmp))) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE IF(GT_16(continuous_noise_num, 24)) + { + snr_delta = L_add(snr_delta, 6710886/* 0.2 Q25 */); + } + ELSE IF((GT_16(continuous_noise_num, 4))) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + } + ELSE IF(EQ_16(bw_index, CLDFBVAD_WB_ID)) + { + + IF(GT_16(sp_center[3], 2864/* 2.80 Q10 */)) + { + snr_delta = snr_delta; + move32(); + } + ELSE IF(GT_16(sp_center[2], 2660/* 2.6 Q10 */)) + { + snr_delta = L_add(snr_delta, 1006633/* 0.03 Q25 */); + } + ELSE IF(GT_16(sp_center[2], 1637/* 1.6 Q10 */)) + { + snr_delta = L_add(snr_delta, 1677722/* 0.05 Q25 */); + } + ELSE IF(GT_16(sp_center[3], 1432/* 1.4 Q10 */)) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE + { + snr_delta = L_add(snr_delta, 10066330/* 0.30 Q25 */); + } + + tmp = MUL_F(bw_snr, 3277/* 0.1 Q15 */); + tmp = L_add(tmp, 20132659/* 0.6 Q25 */); + + test(); + test(); + IF(GT_32(continuous_speech_num, 8) && EQ_32(fg_energy_est_start, 1)) + { + snr_delta = L_sub(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE IF(GT_16(continuous_noise_num, 12) && (GT_32(snr_flux, tmp))) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE IF(GT_16(continuous_noise_num, 24)) + { + snr_delta = L_add(snr_delta, 6710886/* 0.20 Q25 */); + } + ELSE IF((GT_16(continuous_noise_num, 4))) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + } + ELSE IF(EQ_16(bw_index, CLDFBVAD_NB_ID)) + { + + IF(GT_16(sp_center[3], 3069/* 3.0 Q10 */)) + { + snr_delta = snr_delta; + move32(); + } + ELSE IF(GT_16(sp_center[2], 2660/* 2.6 Q10 */)) + { + snr_delta = L_add(snr_delta, 671089/* 0.02 Q25 */); + } + ELSE IF(GT_16(sp_center[2], 1637/* 1.6 Q10 */)) + { + snr_delta = L_add(snr_delta, 1342177/* 0.04 Q25 */); + } + ELSE IF(GT_16(sp_center[2], 1494/* 1.46 Q10 */)) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE + { + snr_delta = L_add(snr_delta , 6039798/* 0.18 Q25 */); + } + + tmp = MUL_F(l_snr, 3277/* 0.1 Q15 */); + div1 = L_add(tmp, 6710886/* 0.2 Q25 */); + div2 = L_add(tmp, 20132659/* 0.6 Q25 */); + + test(); + test(); + test(); + test(); + test(); + IF(GT_32(continuous_speech_num, 80) && EQ_32(fg_energy_est_start, 1) && (GT_16(sp_center[0], 1432/* 1.4 Q10 */))) + { + snr_delta = L_sub(snr_delta, 10737418/* 0.32 Q25 */); + } + ELSE IF(GT_32(continuous_speech_num, 8) && EQ_32(fg_energy_est_start, 1) && (GT_32(snr_flux, div1))) + { + snr_delta = L_sub(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE IF(GT_16(continuous_noise_num, 12) && (GT_32(snr_flux, div2))) + { + snr_delta = L_add(snr_delta, 3355443/* 0.10 Q25 */); + } + ELSE IF(GT_16(continuous_noise_num, 24)) + { + snr_delta = L_add(snr_delta, 6710886/* 0.2 Q25 */); + } + } + ELSE + { + snr_delta = 33554431/* 1.0 Q25 */; + move32(); + } + tmp_snr = L_add(snr_delta, test_l_snr); + + + return tmp_snr; +} + diff --git a/lib_enc/cod_tcx.c b/lib_enc/cod_tcx.c index ffb45d9e9..d8fd90f9f 100644 --- a/lib_enc/cod_tcx.c +++ b/lib_enc/cod_tcx.c @@ -165,7 +165,7 @@ void TNSAnalysisStereo( } /* WMOPS: All initializations are either for safety or static (tables) and thus not to be counted */ - ResetTnsData( &hTcxEnc->tnsData[k] ); + ResetTnsData_flt( &hTcxEnc->tnsData[k] ); if ( st->hTcxCfg->pCurrentTnsConfig->maxOrder <= 0 ) { break; @@ -356,8 +356,8 @@ void TNSAnalysisStereo( sts[1]->hTcxEnc->fUseTns[k] = 0; for ( iFilter = sts[0]->hTcxCfg->pCurrentTnsConfig->nMaxFilters - 1; iFilter >= 0; iFilter-- ) { - ClearTnsFilterCoefficients( sts[0]->hTcxEnc->tnsData[k].filter + iFilter ); - ClearTnsFilterCoefficients( sts[1]->hTcxEnc->tnsData[k].filter + iFilter ); + ClearTnsFilterCoefficients_flt( sts[0]->hTcxEnc->tnsData[k].filter + iFilter ); + ClearTnsFilterCoefficients_flt( sts[1]->hTcxEnc->tnsData[k].filter + iFilter ); } } maxPredictionGain = max( maxPredictionGain, maxPredGain ); @@ -438,7 +438,7 @@ void TNSAnalysisStereo( sts[ch]->hTcxEnc->tnsData[k].nFilters = 0; for ( iFilter = sts[ch]->hTcxCfg->pCurrentTnsConfig->nMaxFilters - 1; iFilter >= 0; iFilter-- ) { - ClearTnsFilterCoefficients( sts[ch]->hTcxEnc->tnsData[k].filter + iFilter ); + ClearTnsFilterCoefficients_flt( sts[ch]->hTcxEnc->tnsData[k].filter + iFilter ); sts[ch]->hTcxEnc->tnsData[k].filter[iFilter].filterType = TNS_FILTER_OFF; } } @@ -471,11 +471,11 @@ void TNSAnalysisStereo( switch ( pFilter->filterType ) { case TNS_FILTER_OFF: - ClearTnsFilterCoefficients( sts[ch]->hTcxEnc->tnsData[k].filter + iFilter ); + ClearTnsFilterCoefficients_flt( sts[ch]->hTcxEnc->tnsData[k].filter + iFilter ); break; case TNS_FILTER_ON_ZERO: /* Since TNS filter of order 0 is not allowed we have to signal in the stream filter of order 1 with the 0th coefficient equal to 0 */ - ClearTnsFilterCoefficients( pFilter ); + ClearTnsFilterCoefficients_flt( pFilter ); pFilter->order = 1; break; } @@ -539,7 +539,7 @@ void TNSAnalysisStereo( { st->hTcxCfg->pCurrentTnsConfig = &st->hTcxCfg->tnsConfig[st->hTcxEnc->transform_type[k] == TCX_20][( k == 0 ) && ( st->last_core == ACELP_CORE )]; - ApplyTnsFilter( st->hTcxCfg->pCurrentTnsConfig, &st->hTcxEnc->tnsData[k], spectrum, 1 ); + ApplyTnsFilter_flt( st->hTcxCfg->pCurrentTnsConfig, &st->hTcxEnc->tnsData[k], spectrum, 1 ); } if ( st->hTcxEnc->transform_type[k] == TCX_5 ) @@ -621,7 +621,7 @@ void TNSAnalysis( /* If TNS should be used then get the residual after applying it inplace in the spectrum */ if ( *pfUseTns ) { - ApplyTnsFilter( hTcxCfg->pCurrentTnsConfig, pTnsData, spectrum, 1 ); + ApplyTnsFilter_flt( hTcxCfg->pCurrentTnsConfig, pTnsData, spectrum, 1 ); } if ( transform_type == TCX_5 ) @@ -700,7 +700,7 @@ void ShapeSpectrum( } } - tcxGetNoiseFillingTilt( A, L_frame, ( total_brate >= ACELP_13k20 && !st->rf_mode ), &st->hTcxEnc->noiseTiltFactor_flt); + tcxGetNoiseFillingTilt_flt( A, L_frame, ( total_brate >= ACELP_13k20 && !st->rf_mode ), &st->hTcxEnc->noiseTiltFactor_flt); /* Calculate Spectrum Flatness Measure for the TCX Concealment */ if ( st->enablePlcWaveadjust ) @@ -1657,7 +1657,7 @@ void InternalTCXDecoder( /* Replication of ACELP formant enhancement for low rates */ if ( st->total_brate < ACELP_13k20 || st->rf_mode ) { - tcxFormantEnhancement( lf_deemph_fact, gainlpc, spectrum, L_frame ); + tcxFormantEnhancement_flt( lf_deemph_fact, gainlpc, spectrum, L_frame ); } /*-----------------------------------------------------------* @@ -1666,7 +1666,7 @@ void InternalTCXDecoder( if ( fac_ns > 0.0f ) { - iStart = tcxGetNoiseFillingTilt( A, L_frame, ( st->total_brate >= ACELP_13k20 && !st->rf_mode ), &hTcxEnc->noiseTiltFactor_flt); + iStart = tcxGetNoiseFillingTilt_flt( A, L_frame, ( st->total_brate >= ACELP_13k20 && !st->rf_mode ), &hTcxEnc->noiseTiltFactor_flt); noiseTransWidth = GetTransWidth( st->tcxonly, ( L_frame == st->L_frame >> 1 ), hTcxEnc->tcxltp_gain_flt, ( st->hTcxCfg->ctx_hm && st->last_core != ACELP_CORE && hm_active ) ); assert( st->element_mode != IVAS_CPE_MDCT ); @@ -1724,7 +1724,7 @@ void InternalTCXDecoder( L = L_spec; } - tcxInvertWindowGrouping( st->hTcxCfg, xn_buf, spectrum, L, hTcxEnc->fUseTns[frame_cnt], st->last_core, tcx_last_overlap_mode, frame_cnt, 0 ); + tcxInvertWindowGrouping_flt( st->hTcxCfg, xn_buf, spectrum, L, hTcxEnc->fUseTns[frame_cnt], st->last_core, tcx_last_overlap_mode, frame_cnt, 0 ); } /*-----------------------------------------------------------* @@ -1738,7 +1738,7 @@ void InternalTCXDecoder( /* Apply TNS to get the reconstructed signal */ if ( hTcxEnc->fUseTns[frame_cnt] != 0 ) { - ApplyTnsFilter( st->hTcxCfg->pCurrentTnsConfig, &hTcxEnc->tnsData[frame_cnt], spectrum, 0 ); + ApplyTnsFilter_flt( st->hTcxCfg->pCurrentTnsConfig, &hTcxEnc->tnsData[frame_cnt], spectrum, 0 ); if ( ( L_frame == st->L_frame >> 1 ) && ( st->tcxonly ) ) { diff --git a/lib_enc/detect_transient_fx.c b/lib_enc/detect_transient_fx.c new file mode 100644 index 000000000..bab7a501f --- /dev/null +++ b/lib_enc/detect_transient_fx.c @@ -0,0 +1,434 @@ +/****************************************************************************************************** + + (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/*==================================================================================== + EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0 + ====================================================================================*/ +#include +#include "options.h" /* Compilation switches */ +#include "cnst.h" /* Common constants */ +#include "rom_com_fx.h" /* Static table prototypes */ +#include "prot_fx2.h" /* Function prototypes */ + + /*--------------------------------------------------------------------------*/ + /* Function hp_filter */ + /* ~~~~~~~~~~~~~~~~~~~~ */ + /* */ + /* High pass filter */ + /*--------------------------------------------------------------------------*/ + /* float x (i) in Q_new input to filter */ + /* float y (o) in Q_new +2 output of filter */ + /* float *oldy (i/o) previous output of filter */ + /* float *oldx (i/o) in Q_memx previous input of filter */ + /* short L (i) in Q_memx +2 length (32 or 48 kHz) */ + /*--------------------------------------------------------------------------*/ + +static void hp_filter_fx( + const Word16 *x, /*Q_new */ + Word16 *y, /*Q_new */ + Word16 *oldy, /*Q_new */ + Word16 *oldx, /*Q_new */ + const Word16 L +) +{ + Word16 i; + Word32 L_tmp; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + + /*y[0] = 0.4931f * *oldy + 0.7466f*(x[0] - *oldx); */ +#ifdef BASOP_NOGLOB + L_tmp = L_mult(sub_o(x[0], *oldx, &Overflow), 24465);/*Q_new+16 */ +#else /* BASOP_NOGLOB */ + L_tmp = L_mult(sub(x[0], *oldx), 24465);/*Q_new+16 */ +#endif /* BASOP_NOGLOB */ + L_tmp = L_mac(L_tmp, *oldy, 16158);/*Q_new+16 */ + y[0] = round_fx(L_tmp);/*Q_new */ + + FOR(i = 1; i < L; i++) + { + /*y[i] = 0.4931f*y[i-1] + 0.7466f*(x[i] - x[i-1]); */ +#ifdef BASOP_NOGLOB + L_tmp = L_mult(sub_o(x[i], x[i - 1], &Overflow), 24465);/*Q_new+16 */ + L_tmp = L_mac_o(L_tmp, y[i - 1], 16158, &Overflow);/*Q_new+16 */ + y[i] = round_fx_o(L_tmp, &Overflow); /*Q_new */ +#else /* BASOP_NOGLOB */ + L_tmp = L_mult(sub(x[i], x[i - 1]), 24465);/*Q_new+16 */ + L_tmp = L_mac(L_tmp, y[i - 1], 16158);/*Q_new+16 */ + y[i] = round_fx(L_tmp); /*Q_new */ +#endif /* BASOP_NOGLOB */ + } + + *oldx = x[L - 1]; + move16();/*Q_new */ + *oldy = y[L - 1]; + move16();/*Q_new */ + +} +/*--------------------------------------------------------------------------*/ +/* Function detect_transient */ +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* */ +/* Detect if the signal is a transient */ +/*--------------------------------------------------------------------------*/ +/* float in[] (i) input signal Q_new */ +/* Encoder_State *st (i/o) state of coder */ +/* short L (i) length (32 or 48 kHz) */ +/*--------------------------------------------------------------------------*/ +/* short return (o) result of transient check */ +/*--------------------------------------------------------------------------*/ + +Word16 detect_transient_fx( + const Word16 *in_fx, /*Q_new */ + const Word16 L, + Word16 Q_new, + Encoder_State *st_fx +) +{ + Word32 Energy, L_tmp; + Word32 EnergyLT; + Word16 i, blk; + Word16 IsTransient; + Word16 out_filt_fx[L_FRAME48k]; + Word16 position = 0; + Word16 thr; + Word32 L_tmp2; + Word16 shift; + Word32 Energy_fx, E_in_fx = 0, E_out_fx = 0, Energy_in_fx[5] = { 0,0,0,0,0 }; /* Energy_fx can be replaced by Energy */ + Word32 E_low_fx, E_high_fx; + Word16 temp16, Thres_fx = 0; + Word16 exp; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + shift = 0; + move16(); + + IsTransient = 0; + move16(); + IF(NE_16(st_fx->last_extl, st_fx->extl)) + { + st_fx->TransientHangOver = 0; + move16(); + st_fx->old_hpfilt_in_fx = 0; + move16(); + st_fx->old_hpfilt_out_fx = 0; + move16(); + } + + /* High pass filter */ + hp_filter_fx(in_fx, out_filt_fx, &(st_fx->old_hpfilt_in_fx), &(st_fx->old_hpfilt_out_fx), L); + + /* Long term energy */ + test(); + test(); + test(); + IF(NE_16(st_fx->last_extl, st_fx->extl) || (EQ_16(st_fx->last_extl, st_fx->extl) && NE_16(st_fx->last_core, st_fx->core)) || EQ_16(st_fx->last_codec_mode, MODE2)) + { + /*EnergyLT = EPSILON_FX; */ + EnergyLT = L_deposit_l(0); + FOR(i = 0; i < L / 4; i++) + { + /*EnergyLT += out_filt[i] * out_filt[i]; */ +#ifdef BASOP_NOGLOB + EnergyLT = L_mac0_o(EnergyLT, out_filt_fx[i], out_filt_fx[i], &Overflow); /*2Q_new */ +#else + EnergyLT = L_mac0(EnergyLT, out_filt_fx[i], out_filt_fx[i]); /*2Q_new */ +#endif + } + } + ELSE + { + EnergyLT = L_add(st_fx->EnergyLT_fx, 0); /*2Q_new */ + } + IF(EQ_16(L, L_FRAME8k)) + { + Energy_in_fx[0] = st_fx->Energy_Old_fx; + move32(); + /* Compute block energy */ + FOR(blk = 0; blk < 4; blk++) + { + Energy_fx = L_deposit_l(0); + Energy_in_fx[blk + 1] = L_deposit_l(0); + FOR(i = 0; i < L / 4; i++) + { + temp16 = extract_l(L_shr(out_filt_fx[i + blk * (L / 4)], 12)); +#ifdef BASOP_NOGLOB + Energy_fx = L_add_o(Energy_fx, L_mult0(temp16, temp16), &Overflow); +#else + Energy_fx = L_add(Energy_fx, L_mult0(temp16, temp16)); +#endif + temp16 = shr(in_fx[i + blk * (L / 4)], Q_new); +#ifdef BASOP_NOGLOB + Energy_in_fx[blk + 1] = L_add_o(Energy_in_fx[blk + 1], L_mult0(temp16, temp16), &Overflow); +#else + Energy_in_fx[blk + 1] = L_add(Energy_in_fx[blk + 1], L_mult0(temp16, temp16)); +#endif + move32(); + } + +#ifdef BASOP_NOGLOB + E_in_fx = L_add_o(E_in_fx, Energy_in_fx[blk + 1], &Overflow); + E_out_fx = L_add_o(E_out_fx, Energy_fx, &Overflow); +#else + E_in_fx = L_add(E_in_fx, Energy_in_fx[blk + 1]); + E_out_fx = L_add(E_out_fx, Energy_fx); +#endif + + Thres_fx = 2185;/*1 /15 */ + move16(); + IF(GT_32(Mult_32_16(Energy_fx, 5461), EnergyLT)) + { + IsTransient = 1; + move16(); + position = blk; + move16(); + } + + EnergyLT = L_add(Mult_32_16(EnergyLT, 24576), Mult_32_16(Energy_fx, 8192)); + } + } + ELSE + { + /* Compute block energy */ + FOR(blk = 0; blk < 4; blk++) + { + L_tmp = L_deposit_l(0); + FOR(i = 0; i < L / 8; i++) + { + /*Energy += out_filt_fx[i + blk*(L/4)] * out_filt_fx[i + blk*(L/4)]; */ +#ifdef BASOP_NOGLOB + L_tmp = L_mac0_o(L_tmp, out_filt_fx[i + blk * (L / 4)], out_filt_fx[i + blk * (L / 4)], &Overflow); /*2Q_new */ +#else + L_tmp = L_mac0(L_tmp, out_filt_fx[i + blk * (L / 4)], out_filt_fx[i + blk * (L / 4)]); /*2Q_new */ +#endif + } + L_tmp2 = L_deposit_l(0); + FOR(; i < L / 4; i++) + { + /*Energy += out_filt_fx[i + blk*(L/4)] * out_filt_fx[i + blk*(L/4)]; */ +#ifdef BASOP_NOGLOB + L_tmp2 = L_mac0_o(L_tmp2, out_filt_fx[i + blk * (L / 4)], out_filt_fx[i + blk * (L / 4)], &Overflow); /*2Q_new */ +#else + L_tmp2 = L_mac0(L_tmp2, out_filt_fx[i + blk * (L / 4)], out_filt_fx[i + blk * (L / 4)]); /*2Q_new */ +#endif + } + Overflow = 0; + move16(); +#ifdef BASOP_NOGLOB /* Critical Overflow */ + Energy = L_add_o(L_tmp, L_tmp2, &Overflow); +#else + Energy = L_add(L_tmp, L_tmp2); +#endif + shift = 0; + if (Overflow != 0) + { + shift = 1; + move16(); + } + Overflow = 0; + move16(); + +#ifdef BASOP_NOGLOB /* shift is >= 0, not overflow possible for shr */ + Energy = L_add_o(L_shr(L_tmp, shift), L_shr(L_tmp2, shift), &Overflow); +#else + Energy = L_add(L_shr(L_tmp, shift), L_shr(L_tmp2, shift)); +#endif + test(); + IF(EQ_16(st_fx->extl,SWB_BWE) || EQ_16(st_fx->extl,FB_BWE)) + { + /*Calculate shift to get to Q0*/ + test(); + test(); + IF((GT_32(Mult_32_16(Energy, shl(2427, shift)), EnergyLT)) || (GT_32(Mult_32_16(Energy,shl(3277,shift)),EnergyLT) + && EQ_16(st_fx->core,ACELP_CORE) && EQ_16(st_fx->coder_type,INACTIVE))) + { + IsTransient = 1; + move16(); + position = blk; + move16(); + } + } + ELSE + { + test(); + IF(LE_32(st_fx->total_brate,HQ_16k40) && EQ_16(st_fx->bwidth,SWB)) + { + thr = 2427; + move16(); + } + ELSE + { + thr = 5461; + move16(); + } + thr = shl(thr, shift); + /*if(Energy > L_shr(Mult_32_16(EnergyLT,22624),shift_cnt)) //getting in Q0 32*16 = Q_inp1+Q_inp2+1-16 */ + IF(GT_32(Mult_32_16(Energy, thr),EnergyLT)) + /*if(Energy > 6.0f * EnergyLT) */ + { + IsTransient = 1; + move16(); + position = blk; + move16(); + } + } + /*EnergyLT = 0.75f*EnergyLT + 0.25f*Energy; */ + /*0.75f*EnergyLT in Q0 //0.25f*Energy in Q0 */ + #ifdef BASOP_NOGLOB + EnergyLT = L_add_o(Mult_32_16(EnergyLT,24576),Mult_32_16(Energy, shl(8192, shift)), &Overflow); /*2Q_new */ + #else /* BASOP_NOGLOB */ + EnergyLT = L_add(Mult_32_16(EnergyLT,24576),Mult_32_16(Energy, shl(8192, shift))); /*2Q_new */ + #endif + } + } + st_fx->EnergyLT_fx = EnergyLT; + move32(); + + test(); + test(); + test(); + test(); + test(); + if ((NE_16(st_fx->last_extl, SWB_BWE) && NE_16(st_fx->last_extl, SWB_TBE) && EQ_16(st_fx->extl, SWB_BWE)) || + (NE_16(st_fx->last_extl, FB_BWE) && NE_16(st_fx->last_extl, FB_TBE) && EQ_16(st_fx->extl, FB_BWE))) + { + IsTransient = 0; + move16(); + } + + test(); + IF(IsTransient && L == L_FRAME8k) + { + blk = 0; + move16(); + E_low_fx = L_deposit_l(0); + FOR(i = 0; i < position + 1; i++) + { + /*blk++; */ + blk = add(blk, 1); + E_low_fx = L_add(E_low_fx, Energy_in_fx[i]); + } + + exp = norm_s(blk); + temp16 = div_s(16384, shl(blk, exp));/* 15 + 14 - exp; */ + exp = 15 + 14 - exp; + temp16 = shl(temp16, sub(15, exp)); + E_low_fx = Mult_32_16(E_low_fx, temp16); + + blk = 0; + move16(); + E_high_fx = L_deposit_l(0); + FOR(i = position + 1; i < 5; i++) + { + /*blk++; */ + blk = add(blk, 1); + E_high_fx = L_add(E_high_fx, Energy_in_fx[i]); + } + + exp = norm_s(blk); + temp16 = div_s(16384, shl(blk, exp));/* 15 + 14 - exp; */ + exp = 15 + 14 - exp; + temp16 = shl(temp16, 15 - exp); + E_high_fx = Mult_32_16(E_high_fx, temp16); + + test(); + test(); + IF(LT_32(L_shr(E_high_fx, 1), E_low_fx) && GT_32(E_high_fx, Mult_32_16(E_low_fx, 22938)) && GT_32(Mult_32_16(E_in_fx, Thres_fx), E_out_fx)) + { + IsTransient = 0; + move16(); + } + } + IF(EQ_32(st_fx->core_brate, ACELP_24k40)) + { + test(); + IF(NE_16(st_fx->last_core, HQ_CORE) || NE_32(st_fx->last_core_brate, ACELP_24k40)) + { + st_fx->TransientHangOver = 0; + move16(); + IsTransient = 0; + move16(); + } + ELSE + { + IF(IsTransient) + { + IF(EQ_16(position,3)) + { + /* Set Hangover */ + st_fx->TransientHangOver = 1; + move16(); + } + } + ELSE + { + IF(st_fx->TransientHangOver) + { + st_fx->TransientHangOver = 0; + move16(); + IsTransient = 1; + move16(); + } + } + } + } + ELSE + { + IF(IsTransient) + { + st_fx->TransientHangOver = 1; + move16(); + } + ELSE + { + IF(st_fx->TransientHangOver) + { + st_fx->TransientHangOver = 0; + move16(); + IsTransient = 1; + move16(); + } + } + } + + IF(EQ_16(L, L_FRAME8k)) + { + st_fx->Energy_Old_fx = Energy_in_fx[4]; + move32(); + } + + return IsTransient; +} diff --git a/lib_enc/enc_ppp_fx.c b/lib_enc/enc_ppp_fx.c new file mode 100644 index 000000000..00f7991d7 --- /dev/null +++ b/lib_enc/enc_ppp_fx.c @@ -0,0 +1,235 @@ +///*==================================================================================== +// EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0 +// ====================================================================================*/ +//#include +//#include "options.h" /* Compilation switches */ +//#include "cnst.h" /* Common constants */ +//#include "prot_fx2.h" /* Function prototypes */ +// +// /*Temporary location to be move in prot* when merge is done */ +//void E_LPC_f_lsp_a_conversion(const Word16 *lsp, Word16 *a, const Word16 m); +// +///*=======================================================================================*/ +///* FUNCTION : encod_ppp_fx() */ +///*---------------------------------------------------------------------------------------*/ +///* PURPOSE : */ +///*---------------------------------------------------------------------------------------*/ +///* INPUT ARGUMENTS : */ +///* _ (Word16) speech_fx[], i : input speech Q_new */ +///* _ (Word16) Aq_fx[], i : 12k8 Lp coefficient Q12 */ +///* _ (Word16) A_fx[], i : unquantized A(z) filter with bandwidth expansion Q12*/ +///* _ (Word16) coder_type_fx, i : coding type */ +///* _ (Word16) T_op_fx[], i : open loop pitch */ +///* _ (Word16) voicing_fx[], i : voicing Q15 */ +///* _ (Word16) *res_fx, i : residual signal Q_new */ +///* _ (Word16) Q_new i : Q factor for res */ +///* _ (Word16) vadsnr_fx i : SNR for current frame Q7 */ +///*---------------------------------------------------------------------------------------*/ +///* OUTPUT ARGUMENTS : */ +///* _ (Word16) *exc2_fx, o : current enhanced excitation Q0 */ +///* _ (Word16) *pitch_buf_fx, o : floating pitch values for each subframe Q6 */ +///* _ (Word16) *synth_fx, o : core synthesis Q-1 */ +///* _ Encoder_State_fx *st_fx: */ +///* _ lastLgainE_fx - Q11 */ +///* _ lastHgainE_fx - Q11 */ +///* _ lasterbE_fx - Q13 */ +///*---------------------------------------------------------------------------------------*/ +///* INPUT/OUTPUT ARGUMENTS : */ +///* _ Encoder_State_fx *st_fx: */ +///* _ st_fx->dtfs_enc_xxxx */ +///* _ a nd b in st_fx->dtfs_enc_Q */ +///* rest all in Q0 */ +///* - bump_up_fx - Q0 */ +///* _ (Word16) *exc_fx, o : current enhanced excitation Q0 */ +///*---------------------------------------------------------------------------------------*/ +///* RETURN ARGUMENTS : */ +///* _ None. */ +///*---------------------------------------------------------------------------------------*/ +///* CALLED FROM : TX */ +///*=======================================================================================*/ +//ivas_error encod_ppp_fx( +// Encoder_State* st_fx, /* i/o: state structure */ +// const Word16 speech_fx[], /* i : input speech Q_new*/ +// const Word16 Aw_fx[], /* i : weighted A(z) unquantized for subframes */ +// const Word16 Aq_fx[], /* i : 12k8 Lp coefficient */ +// Word16 *res_fx, /* i : residual signal Q_new*/ +// Word16 *synth_fx, /* o : core synthesis Q-1*/ +// Word16 *exc_fx, /* i/o: current non-enhanced excitation Q_new*/ +// Word16 *exc2_fx, /* o : current enhanced excitation Q0*/ +// Word16 *pitch_buf_fx, /* o : floating pitch values for each subframe Q6*/ +// Word16 *voice_factors, /* o : voicing factors */ +// Word16 *bwe_exc, /* o : excitation for SWB TBE */ +// Word16 Q_new, +// Word16 shift +//) +//{ +// Word16 xn_fx[L_SUBFR]; /* Target vector for pitch search */ +// Word16 h1_fx[L_SUBFR + (M + 1)]; /* Impulse response vector */ +// Word16 i_subfr; /* tmp variables */ +// const Word16 *p_Aw_fx, *p_Aq_fx; /* pointer to LP filter coeff. vector*/ +// +// Word16 k; +// Word16 p_Aq_old_fx[M + 1], excQ_ppp_fx[L_FRAME], p_Aq_curr_fx[M], pitch_fx[NB_SUBFR]; +// Word16 LPC_de_old_fx[M + 1], LPC_de_curr_fx[M + 1]; +// Word16 shift_wsp = add(Q_new, shift); +// Word16 rate_ctrl_fx; +// Word16 saved_Q_new = Q_new; +// LPD_state_HANDLE hLPDmem = st_fx->hLPDmem; +// SC_VBR_ENC_HANDLE hSC_VBR = st_fx->hSC_VBR; +// BSTR_ENC_HANDLE hBstr = st_fx->hBstr; +// ivas_error error; +// +// error = IVAS_ERR_OK; +// move16(); +// rate_ctrl_fx = hSC_VBR->rate_control; +// move16(); +// +// /*------------------------------------------------------------------* +// * ACELP subframe loop +// *------------------------------------------------------------------*/ +// p_Aw_fx = Aw_fx; +// p_Aq_fx = Aq_fx; +// FOR(i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) +// { +// /*----------------------------------------------------------------* +// * Bandwidth expansion of A(z) filter coefficients +// * Find the the excitation search target "xn" and innovation +// * target in residual domain "cn" +// * Compute impulse response, h1[], of weighted synthesis filter +// *----------------------------------------------------------------*/ +// +// Copy(&res_fx[i_subfr], &exc_fx[i_subfr], L_SUBFR); +// +// find_targets_fx(speech_fx, hLPDmem->mem_syn, i_subfr, &hLPDmem->mem_w0, p_Aq_fx, +// res_fx, L_SUBFR, p_Aw_fx, TILT_FAC_FX, xn_fx, NULL, h1_fx); +// +// /* scale xn[] and h1[] to avoid overflow in dot_product12() */ +// Scale_sig(xn_fx, L_SUBFR, shift); /* scaling of xn[] to limit dynamic at 12 bits */ +// +// /* call voiced encoder at this point */ +// IF(i_subfr == 0) /* generate the L_FRAME exc */ +// { +// FOR(k = 0; k < M; k++) +// { +// p_Aq_curr_fx[k] = p_Aq_fx[k + (3 * (M + 1)) + 1]; +// move16(); +// } +// +// E_LPC_f_lsp_a_conversion(st_fx->lsp_old_fx, p_Aq_old_fx, M); +// deemph_lpc_fx(p_Aq_curr_fx, p_Aq_old_fx, LPC_de_curr_fx, LPC_de_old_fx, 1); +// /* both outputs LPC_de_curr_fx and LPC_de_old_fx are in Q12 */ +// +// +// /* last frame-end lpc and curr frame-end lpc */ +// IF((error = ppp_voiced_encoder_fx(hBstr, hSC_VBR, st_fx->bwidth, st_fx->last_coder_type_raw, st_fx->old_pitch_buf_fx, res_fx, +// excQ_ppp_fx, st_fx->pitch_fx[1], LPC_de_old_fx, LPC_de_curr_fx, exc_fx, pitch_fx, Q_new)) != IVAS_ERR_OK) +// { +// return error; +// } +// +// Scale_sig(exc_fx, L_FRAME, (saved_Q_new - Q_new)); +// if (EQ_16(hSC_VBR->bump_up, 1)) +// { +// i_subfr = L_FRAME; +// move16(); +// } +// } +// +// IF(NE_16(hSC_VBR->bump_up, 1)) +// { +// /*-----------------------------------------------------------------* +// * Gain clipping test to avoid unstable synthesis on frame erasure +// * or in case of floating point encoder & fixed p. decoder +// *-----------------------------------------------------------------*/ +// gp_clip_fx(st_fx->element_mode, st_fx->core_brate, st_fx->voicing_fx, i_subfr, st_fx->coder_type, xn_fx, st_fx->clip_var_fx, sub(shift_wsp, 1)); +// +// +// /* run the above to maintain gain clipping memories */ +// gp_clip_test_gain_pit_fx(st_fx->element_mode, st_fx->core_brate, hSC_VBR->prev_ppp_gain_pit_fx, st_fx->clip_var_fx); +// +// +// /*-----------------------------------------------------------------* +// * Synthesize speech to update mem_syn[]. +// * Update A(z) filters +// *-----------------------------------------------------------------*/ +// +// Syn_filt_s(1, p_Aq_fx, M, &excQ_ppp_fx[i_subfr], &synth_fx[i_subfr], L_SUBFR, hLPDmem->mem_syn, 1); +// +// +// p_Aw_fx += (M + 1); +// p_Aq_fx += (M + 1); +// } +// +// } /* end of subframe loop */ +// +// IF(hSC_VBR->bump_up) +// { +// /* PPP failed, bump up */ +// hSC_VBR->ppp_mode = 0; +// move16(); +// st_fx->core_brate = ACELP_7k20; +// move16(); +// hSC_VBR->pppcountE = 0; +// move16(); +// +// IF(hSC_VBR->set_ppp_generic) +// { +// st_fx->coder_type = GENERIC; +// move16(); +// } +// ELSE +// { +// st_fx->coder_type = VOICED; +// move16(); +// } +// +// /* We write signalling indices again only in case of bump_up */ +// /* delete previous indices */ +//#ifndef IVAS_CODE_BITSTREAM +// reset_indices_enc_fx(hBstr); +//#else +// reset_indices_enc_fx(hBstr, hBstr->nb_ind_tot); +//#endif +// +// /* signalling matrix (writing of signalling bits) */ +// signalling_enc_fx(st_fx); +// } +// ELSE +// { +// Copy(excQ_ppp_fx, exc_fx, L_FRAME); +// +// /*-----------------------------------------------------------------* +// * Updates: last value of new target is stored in mem_w0 +// *-----------------------------------------------------------------*/ +// +// hLPDmem->mem_w0 = sub(shr(xn_fx[L_SUBFR - 1],shift), shr(exc_fx[L_FRAME - 1],1)); /*Q_new-1 */ +// +// Copy(exc_fx, exc2_fx, L_FRAME); +// +// hLPDmem->dm_fx.prev_state = 2; +// move16();/*Q0 dispMem index 0 */ +// hLPDmem->dm_fx.prev_gain_pit[0] = hSC_VBR->prev_ppp_gain_pit_fx; +// move16();/*Q14 dispMem index 2 */ +// +// FOR(k = 1; k < 5; k++) +// { +// hLPDmem->dm_fx.prev_gain_pit[k] = hLPDmem->dm_fx.prev_gain_pit[k - 1]; +// move16(); +// } +// +// hLPDmem->tilt_code = hSC_VBR->prev_tilt_code_fx; +// move16(); +// Copy(pitch_fx, pitch_buf_fx, NB_SUBFR); +// pitch_buf_fx[NB_SUBFR16k - 1] = pitch_fx[NB_SUBFR - 1]; +// +// interp_code_5over2_fx(exc2_fx, bwe_exc, L_FRAME); +// set16_fx(voice_factors, 0, NB_SUBFR16k); +// } +// +// hSC_VBR->rate_control = rate_ctrl_fx; +// move16(); +// +// set16_fx(hSC_VBR->nelp_lp_fit_mem, 0, NELP_LP_ORDER * 2); +// +// return error; +//} diff --git a/lib_enc/gp_clip_fx.c b/lib_enc/gp_clip_fx.c new file mode 100644 index 000000000..66108aad3 --- /dev/null +++ b/lib_enc/gp_clip_fx.c @@ -0,0 +1,459 @@ +/****************************************************************************************************** + + (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +/*==================================================================================== + EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0 + ====================================================================================*/ + +#include +#include "options.h" /* Compilation switches */ +#include "cnst.h" /* Common constants */ +#include "prot_fx2.h" /* Function prototypes */ +#include "basop_util.h" + + /*-------------------------------------------------------------------* + * Local constants + *-------------------------------------------------------------------*/ + +#define DIST_ISF_MAX_IO 384 /* 150 Hz (6400Hz=16384) */ +#define DIST_ISF_MAX 307 /* 120 Hz (6400Hz=16384) */ +#define DIST_ISF_THRES 154 /* 60 (6400Hz=16384) */ +#define GAIN_PIT_THRES 14746 /* 0.9 in Q14 */ +#define GAIN_PIT_MIN 9830 /* 0.6 in Q14 */ + +#define ALPHA1 32113 /* 0.98f */ +#define ALPHA4 32440 /* 0.99f */ +#define WINDOW_SIZE 50 +#define THRESH_TYPE 13926 /* 0.85f in Q14 */ +#define THRESH_VOICING 14090 /* 0.86f in Q14 */ + +#define GPCLIP_E (6+2) + +#define ALPHA1_M1 21474836l/*1.0f-0.98 Q30*/ +#define ALPHA4_M1 10737408l/*1.0f-0.99f Q30*/ + + /*-------------------------------------------------------------------* + * init_gp_clip + * + * Pitch Gain clipping initializations + *-------------------------------------------------------------------*/ +void init_gp_clip_fx( + Word16 mem[] /* o : memory of gain of pitch clipping algorithm */ +) +{ + mem[0] = DIST_ISF_MAX; + move16(); /* Q0 */ + mem[1] = GAIN_PIT_MIN; + move16(); /* 1Q14 */ + mem[2] = 0; + move16(); /* 8Q7 */ /* old energy of target (dB) */ + mem[3] = 0; + move16(); /* Q0 */ + mem[4] = 0; + move16(); /* Q14 */ + mem[5] = 13107;/*0.8*/ move16(); /* Q14 */ + + return; +} + +/*-------------------------------------------------------------------* + * Function gp_clip + * + * The gain needs to be limited (gain pitch < 1.0) when one of the + * following cases occurs: + * - a resonance on LPC filter (lp_disp < 60 Hz) AND a good pitch + * prediction (lp_gp > 0.9) + * - target energy drops by 6 dB AND a good pitch prediction (lp_gp>1.0) + *-------------------------------------------------------------------*/ + +Word16 gp_clip_fx( + const Word16 element_mode, /* i : element mode */ + const Word32 core_brate, /* i : core bitrate */ + const Word16 *voicing, /* i : normalized correlations (from OL pitch) */ + const Word16 i_subfr, /* i : subframe index */ + const Word16 coder_type, /* i : type of coder */ + const Word16 xn[], /* i : target vector */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + const Word16 Q_new /* i : scaling factor */ +) +{ + Word16 clip; + Word16 i, wener; + Word16 e_ener, f_ener; + Word32 ener; + Word32 L_tmp; + Word16 thres; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + clip = 0; + move16(); + test(); + test(); + IF(EQ_32(core_brate, ACELP_6k60) || EQ_32(core_brate, ACELP_8k85) || GT_16(element_mode, EVS_MONO)) + { + thres = add(14746, mult(1638, extract_l(L_mult(mem[0], (Word16)(16384 / DIST_ISF_MAX_IO))))); /* clipping is activated when filtered pitch gain > threshold (0.94 to 1 in Q14) */ + test(); + if (GT_16(mem[1], thres)) + { + clip = 1; + move16(); + } + } + ELSE + { + test(); + if (LT_16(mem[0], DIST_ISF_THRES) && GT_16(mem[1],GAIN_PIT_THRES)) + { + clip = 1; + move16(); + } + } + +#ifdef BASOP_NOGLOB + ener = L_mac_o(1L, xn[0], xn[0], &Overflow); +#else + ener = L_mac(1L, xn[0], xn[0]); +#endif + FOR(i = 1; i < L_SUBFR; i++) + { +#ifdef BASOP_NOGLOB + ener = L_mac_o(ener, xn[i], xn[i], &Overflow); +#else /* BASOP_NOGLOB */ + ener = L_mac(ener, xn[i], xn[i]); +#endif + } + + /* ener = 10.0f*(float)log10(ener) */ + e_ener = norm_l(ener); + f_ener = Log2_norm_lc(L_shl(ener, e_ener)); + e_ener = sub(30, e_ener); + e_ener = sub(e_ener, Q_new); + ener = Mpy_32_16(e_ener, f_ener, LG10); + wener = round_fx(L_shl(ener, 10)); + + test(); + if (LT_16(wener, sub(mem[2], 1536)) && GT_16(mem[1], 16384)) + { + clip = 1; + move16(); + } + + mem[2] = wener; + move16(); + + L_tmp = L_mult(ALPHA1, mem[4]); + + test(); + test(); + if (EQ_16(coder_type, GENERIC) || EQ_16(coder_type, TRANSITION) || EQ_16(coder_type, INACTIVE)) + { + /* mem[4] = (1-ALPHA1) + ALPHA1 * mem[4], if branch taken */ + /* mem[4] = ALPHA1 * mem[4], otherwise */ + L_tmp = L_add(L_tmp, 32768L * (32768 - ALPHA1)); + } + mem[4] = round_fx(L_tmp); + + L_tmp = L_mult(ALPHA4, mem[5]); + if (i_subfr == 0) + { + /* mem[5] = (1-ALPHA4) * voicing[0] + ALPHA4 * mem[5] */ + mem[5] = mac_r(L_tmp, (32768 - ALPHA4) / 2, voicing[0]); + move16(); /* /2 to put voicing from Q15 to Q14 */ + } + + if (EQ_16(i_subfr, 2 * L_SUBFR)) + { + /* mem[5] = (1-ALPHA4) * voicing[1] + ALPHA4 * mem[5] */ + mem[5] = mac_r(L_tmp, (32768 - ALPHA4) / 2, voicing[1]); + move16(); /* /2 to put voicing from Q15 to Q14 */ + } + + IF(GT_16(mem[3], WINDOW_SIZE)) + { + test(); + if (GT_16(mem[4], THRESH_TYPE) && GT_16(mem[5], THRESH_VOICING)) + { + clip = 1; + move16(); + } + } + ELSE + { + mem[3] = add(mem[3], 1); + move16(); + } + + return (clip); +} + +/*-------------------------------------------------------------------* + * gp_clip_test_lsf() + * + * check the minimum distance of LSFs for pitch gain clipping flag + *-------------------------------------------------------------------*/ + +void gp_clip_test_isf_fx( + const Word16 element_mode, /* i : element mode */ + const Word32 core_brate, /* i : core bitrate */ + const Word16 isf[], /* i : isf values (in frequency domain) */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + const Word16 Opt_AMR_WB /* i : flag indicating AMR-WB IO mode */ +) +{ + Word16 i, dist, dist_min, m; + + dist_min = sub(isf[1], isf[0]); + + m = M; + move16(); + if (EQ_16(Opt_AMR_WB, 1)) + { + m = M - 1; + move16(); + } + + move16(); /* ptr init*/ + FOR(i = 2; i < m; i++) + { + dist = sub(isf[i], isf[i - 1]); + dist_min = s_min(dist, dist_min); + } + + dist = extract_h(L_mac(L_mult(26214, mem[0]), 6554, dist_min)); + + test(); + test(); + IF(EQ_32(core_brate, ACELP_6k60) || EQ_32(core_brate, ACELP_8k85) || GT_16(element_mode, EVS_MONO)) + { + dist = s_min(dist, DIST_ISF_MAX_IO); + } + ELSE + { + dist = s_min(dist, DIST_ISF_MAX); + } + mem[0] = dist; + move16(); + + return; +} + +/*-------------------------------------------------------------------* + * gp_clip_test_gain_pit() + * + * low-pass filtering of the pitch gain for pitch gain clipping flag + *-------------------------------------------------------------------*/ + +void gp_clip_test_gain_pit_fx( + const Word16 element_mode, /* i : element mode */ + const Word32 core_brate, /* i : core bitrate */ + const Word16 gain_pit, /* i : gain of quantized pitch Q14 */ + Word16 mem[] /* i/o: memory of gain of pitch clipping algorithm 1Q14 */ +) +{ + Word16 gain; + Word32 L_tmp; + + test(); + test(); + IF(EQ_32(core_brate, ACELP_6k60) || EQ_32(core_brate, ACELP_8k85) || GT_16(element_mode, EVS_MONO)) + { + L_tmp = L_mult(32113, mem[1]); /* long term LTP gain average (>250ms) */ + L_tmp = L_mac(L_tmp, 655, gain_pit); + } + ELSE + { + L_tmp = L_mult(29491, mem[1]); + L_tmp = L_mac(L_tmp, 3277, gain_pit); + } + gain = extract_h(L_tmp); + gain = s_max(gain, GAIN_PIT_MIN); + mem[1] = gain; + move16(); + + return; +} + + +/*-------------------------------------------------------------------* + * Function gp_clip + * + * The gain needs to be limited (gain pitch < 1.0) when one of the + * following cases occurs: + * - a resonance on LPC filter (lp_disp < 60 Hz) AND a good pitch + * prediction (lp_gp > 0.9) + * - target energy drops by 6 dB AND a good pitch prediction (lp_gp>1.0) + *-------------------------------------------------------------------*/ +Word16 Mode2_gp_clip( + const Word16 voicing[3], /* i : normalized correlations from OL pitch Q15 */ + const Word16 i_subfr, /* i : subframe index */ + const Word16 coder_type, /* i : type of coder */ + const Word16 xn[], /* i : target vector Q_xn */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + /* mem[0]: Q0 */ + /* mem[1]: 1Q14 */ + /* mem[2]: 8Q7 */ + /* mem[3]: Q0 (integer) */ + /* mem[4]: Q14 */ + /* mem[5]: Q14 */ + const Word16 L_subfr, + const Word16 Q_xn /* i : scaling factor of vector xn[] */ +) +{ + Word16 clip, tmp, exp_xn; + Word16 i; + Word32 wener, Ltmp; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + move16(); + clip = 0; + + test(); + if ((LT_16(mem[0], DIST_ISF_THRES)) && (GT_16(mem[1], GAIN_PIT_THRES))) + { + move16(); + clip = 1; + } + + /*ener_exp = exp_xn * 2 + 1*/ + exp_xn = add(shl(sub(15, Q_xn), 1), 1); + wener = L_shr(21474836l/*0.01f Q31*/, s_min(31, exp_xn)); + wener = L_max(1, wener); + + FOR(i = 0; i < L_subfr; i++) + { +#ifdef BASOP_NOGLOB + wener = L_mac0_o(wener, xn[i], xn[i], &Overflow); +#else + wener = L_mac0(wener, xn[i], xn[i]); +#endif + } + + /*wener = 10.0f*(float)log10(wener);*/ + wener = BASOP_Util_Log2(wener); + wener = L_add(wener, L_shl(exp_xn, 31 - LD_DATA_SCALE)); + wener = Mpy_32_16_1(wener, LG10); /* wener in 8Q7 */ +#if (GPCLIP_E != 6+2) + wener = shl(wener, GPCLIP_E - (6 + 2)); +#endif + tmp = round_fx(wener); + /* exponent of wener = 6+2 */ + + test(); + if (LT_16(tmp, sub(mem[2], 768/*6.0f Q7*/)) && + GT_16(mem[1], 16384/*1.0f Q14*/)) + { + move16(); + clip = 1; + } + + move16(); + mem[2] = tmp; /* wener in 8Q7 format */ + Ltmp = Mpy_32_16_1(ALPHA1, mem[4]); /* mem[4] in Q14 format, Ltmp in Q14 */ + + if (s_or((Word16)EQ_16(coder_type, GENERIC), (Word16)EQ_16(coder_type, TRANSITION))) + { + Ltmp = L_add(Ltmp, ALPHA1_M1); + } + mem[4] = round_fx(Ltmp); + + Ltmp = Mpy_32_16_1(ALPHA4, mem[5]); /* mem[5] in Q14 format, Ltmp in Q14 */ + IF(i_subfr == 0) + { + move16(); /* voicing: Q15 */ + mem[5] = round_fx(L_add(Mpy_32_16_1(ALPHA4_M1, voicing[0]), Ltmp)); + } + ELSE IF(EQ_16(i_subfr, shl(L_subfr, 1))) + { + move16(); + mem[5] = round_fx(L_add(Mpy_32_16_1(ALPHA4_M1, voicing[1]), Ltmp)); + } + + IF(GT_16(mem[3], WINDOW_SIZE)) + { + test(); + if ((GT_16(mem[4], THRESH_TYPE)) && (GT_16(mem[5], THRESH_VOICING))) + { + move16(); + clip = 1; + } + } + ELSE + { + move16(); + mem[3] = add(mem[3], 1); + } + + + return (clip); +} + +/*-------------------------------------------------------------------* +* gp_clip_test_lsf: +* +* check the minimum distance of LSFs for pitch gain clipping flag +*-------------------------------------------------------------------*/ +void gp_clip_test_lsf_fx( + const Word16 element_mode, /* i : element mode */ + const Word16 lsf[], /* i : lsf values (in frequency domain) 14Q1*1.28 */ + Word16 mem[], /* i/o: memory of gain of pitch clipping algorithm */ + const Word16 m /* i : dimension of lsf */ +) +{ + Word16 i; + Word16 dist, dist_min, dist_max; + + dist_max = DIST_ISF_MAX; + move16(); + if (GT_16(element_mode, EVS_MONO)) + { + dist_max = DIST_ISF_MAX_IO; + move16(); + } + dist_min = sub(lsf[1], lsf[0]); + + FOR(i = 2; i < m - 1; i++) + { + dist = sub(lsf[i], lsf[i - 1]); + dist_min = s_min(dist, dist_min); + } + /*dist = 0.8f*mem[0] + 0.2f*dist_min;*/ + dist = s_min(dist_max, mac_r(L_mult(26214/*0.8f Q15*/, mem[0]), 6554/*0.2f Q15*/, dist_min)); + + mem[0] = dist; + move16(); + + + return; +} diff --git a/lib_enc/isf_enc_amr_wb_fx.c b/lib_enc/isf_enc_amr_wb_fx.c new file mode 100644 index 000000000..de6a422f3 --- /dev/null +++ b/lib_enc/isf_enc_amr_wb_fx.c @@ -0,0 +1,571 @@ +/****************************************************************************************************** + + (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include "options.h" /* Compilation switches */ +#include "cnst.h" /* Common constants */ +#include "rom_com.h" /* Static table prototypes */ +#include "prot_fx2.h" /* Function prototypes */ + + + /*-----------------------------------------------------------------* + * Local constants + *-----------------------------------------------------------------*/ + +#define DICO1_NS_19b 16 /* codebook dimensions for SID ISF quantizers */ +#define DICO2_NS_19b 16 +#define DICO3_NS_19b 16 +#define DICO4_NS_19b 8 +#define DICO5_NS_19b 16 + +#define DICO1_NS_28b 64 +#define DICO2_NS_28b 64 +#define DICO3_NS_28b 64 +#define DICO4_NS_28b 32 +#define DICO5_NS_28b 32 + +#define N_SURV_MAX 4 /* maximum number of survivors */ + + /*---------------------------------------------------------------------* + * Local function prototypes + *---------------------------------------------------------------------*/ + +static void qisf_ns_28b_fx(BSTR_ENC_HANDLE hBstr, Word16 *isf); +static void qisf_2s_46b_fx(BSTR_ENC_HANDLE hBstr, Word16 *isf, Word16 nb_surv, Word16 *mem_AR, Word16 *mem_MA); +static void qisf_2s_36b_fx(BSTR_ENC_HANDLE hBstr, Word16 *isf, Word16 nb_surv, Word16 *mem_AR, Word16 *mem_MA); +static void VQ_stage1_fx(const Word16 *x, const Word16 *dico, const Word16 dim, const Word16 dico_size, Word16 *index, const Word16 surv); +static Word16 sub_VQ_fx(Word16 *x, const Word16 *dico, const Word16 dim, const Word16 dico_size, Word32 *distance); + +/*-------------------------------------------------------------------* + * isf_enc_amr_wb() + * + * Quantization of ISF parameters in AMR-WB IO mode + *-------------------------------------------------------------------*/ + +void isf_enc_amr_wb_fx( + Encoder_State *st, /* i/o: state structure */ + Word16 *isf_new, /* i/o: quantized ISF vector */ + Word16 *isp_new, /* i/o: ISP vector to quantize/quantized */ + Word16 *Aq /* o : quantized A(z) for 4 subframes */ +) +{ + BSTR_ENC_HANDLE hBstr = st->hBstr; + + /*---------------------------------* + * ISF quantization of SID frames + *---------------------------------*/ + + IF(EQ_32(st->core_brate, SID_1k75)) + { + qisf_ns_28b_fx(hBstr, isf_new); + + reorder_isf_fx(isf_new, ISF_GAP_FX, M, Fs_2); + + E_LPC_isf_isp_conversion(isf_new, isp_new, M); + + /* return if SID frame (conversion to A(z) done in the calling function) */ + return; + } + + /* check resonance for pitch clipping algorithm */ + gp_clip_test_isf_fx(st->element_mode, st->core_brate, isf_new, st->clip_var_fx, 1); + + /*---------------------------------------* + * ISF quantization of all other frames + *---------------------------------------*/ + + IF(EQ_32(st->core_brate, ACELP_6k60)) + { + qisf_2s_36b_fx(hBstr, isf_new, 4, st->mem_AR_fx, st->mem_MA_fx); + } + ELSE IF(GE_32(st->core_brate, ACELP_8k85)) + { + qisf_2s_46b_fx(hBstr, isf_new, 4, st->mem_AR_fx, st->mem_MA_fx); + } + + reorder_isf_fx(isf_new, ISF_GAP_FX, M, Fs_2); + /* convert quantized ISFs back to ISPs */ + E_LPC_isf_isp_conversion(isf_new, isp_new, M); + + /*-------------------------------------------------------------------------------------* + * ISP interpolation + * A(z) calculation + *-------------------------------------------------------------------------------------*/ + + if (st->rate_switching_reset) + { + Copy(isf_new, st->lsf_old_fx, M); + Copy(isp_new, st->lsp_old_fx, M); + } + + int_lsp_fx(L_FRAME, st->lsp_old_fx, isp_new, Aq, M, interpol_isp_amr_wb_fx, 1); + + /*------------------------------------------------------------------* + * Calculate ISF stability (distance between old ISF and current ISF) + *------------------------------------------------------------------*/ + IF(NE_32(st->last_core_brate, SID_1k75)) + { + st->stab_fac_fx = lsf_stab_fx(isf_new, st->lsf_old_fx, 1, L_FRAME); + } + + return; +} + +/*-------------------------------------------------------------------* +* qisf_ns_28b() +* +* ISF quantizer for SID frames (only in AMR-WB IO mode) +*-------------------------------------------------------------------*/ + +static void qisf_ns_28b_fx( + BSTR_ENC_HANDLE hBstr, /* i/o: encoder state structure */ + Word16 *isf /* i/o: unquantized/quantized ISF vector */ +) +{ + Word16 i, indice[5]; + Word32 tmp; + + FOR(i = 0; i < M; i++) + { + /*isf[i] -= mean_isf_noise_amr_wb[i];*/ + isf[i] = sub(isf[i], mean_isf_noise_amr_wb_fx[i]); + move16(); + } + + indice[0] = sub_VQ_fx(&isf[0], dico1_ns_28b_fx, 2, DICO1_NS_28b, &tmp); + move16(); + indice[1] = sub_VQ_fx(&isf[2], dico2_ns_28b_fx, 3, DICO2_NS_28b, &tmp); + move16(); + indice[2] = sub_VQ_fx(&isf[5], dico3_ns_28b_fx, 3, DICO3_NS_28b, &tmp); + move16(); + indice[3] = sub_VQ_fx(&isf[8], dico4_ns_28b_fx, 4, DICO4_NS_28b, &tmp); + move16(); + indice[4] = add(sub_VQ_fx(&isf[12], dico5_ns_28b_fx + 4, 4, DICO5_NS_28b - 1, &tmp), 1); /* First vector has a problem -> do not allow */ + + /* write indices to array */ + push_indice_fx(hBstr, IND_ISF_0_0, indice[0], 6); + push_indice_fx(hBstr, IND_ISF_0_1, indice[1], 6); + push_indice_fx(hBstr, IND_ISF_0_2, indice[2], 6); + push_indice_fx(hBstr, IND_ISF_0_3, indice[3], 5); + push_indice_fx(hBstr, IND_ISF_0_4, indice[4], 5); + + /* decoding the ISFs */ + disf_ns_28b_fx(indice, isf); + + return; +} + + +/*---------------------------------------------------------------------* + * qisf_2s_36b() + * + * ISF quantizer for AMR-WB 6k60 frames + * + * The ISF vector is quantized using two-stage MA-prediction VQ with split-by-2 + * in 1st stage and split-by-3 in the second stage. + *---------------------------------------------------------------------*/ + +static void qisf_2s_36b_fx( + BSTR_ENC_HANDLE hBstr, /* i/o: encoder state structure */ + Word16 *isf, /* i/o: unquantized/quantized ISF vector */ + Word16 nb_surv, /* i : number of survivors (1, 2, 3 or 4) */ + Word16 *mem_AR, /* o : quantizer memory for AR model */ + Word16 *mem_MA /* i/o: quantizer memory for MA model */ +) +{ + Word16 i, k, indice[5], tmp_ind[2]; + Word16 surv1[N_SURV_MAX], tmp16; /* indices of survivors from 1st stage */ + Word32 temp, min_err, distance; + Word16 isf2[M]; + + /*------------------------------------------------------------------------* + * Subtract mean + *------------------------------------------------------------------------*/ + + FOR(i = 0; i < M; i++) + { + /*isf[i] -= mean_isf_amr_wb[i] + MU_MA * mem_MA[i];*/ + tmp16 = sub(isf[i], mean_isf_amr_wb_fx[i]); + isf[i] = sub(tmp16, mult(MU_MA_FX, mem_MA[i])); + move16(); + + } + + /*------------------------------------------------------------------------* + * Quantize ISFs 0 - 8 + *------------------------------------------------------------------------*/ + + VQ_stage1_fx(&isf[0], dico1_isf_fx, 9, SIZE_BK1, surv1, nb_surv); + + distance = MAX_32; + move32(); + nb_surv = s_min(nb_surv, N_SURV_MAX); + + FOR(k = 0; k < nb_surv; k++) + { + tmp16 = i_mult2(surv1[k], 9); + FOR(i = 0; i < 9; i++) + { + /*isf2[i] = isf[i] - dico1_isf[i+surv1[k]*9];*/ + isf2[i] = sub(isf[i], dico1_isf_fx[i + tmp16]); + move16(); + } + + tmp_ind[0] = sub_VQ_fx(&isf2[0], dico21_isf_36b_fx, 5, SIZE_BK21_36b, &min_err); + temp = L_add(min_err, 0); + + tmp_ind[1] = sub_VQ_fx(&isf2[5], dico22_isf_36b_fx, 4, SIZE_BK22_36b, &min_err); + temp = L_add(temp, min_err); + + IF(LT_32(temp, distance)) + { + distance = L_add(temp, 0); + indice[0] = surv1[k]; + move16(); + FOR(i = 0; i < 2; i++) + { + indice[i + 2] = tmp_ind[i]; + move16(); + } + } + } + + /*------------------------------------------------------------------------* + * Quantize ISFs 9 - 15 + *------------------------------------------------------------------------*/ + + VQ_stage1_fx(&isf[9], dico2_isf_fx, 7, SIZE_BK2, surv1, nb_surv); + + distance = MAX_32; + move32(); + FOR(k = 0; k < nb_surv; k++) + { + tmp16 = i_mult2(surv1[k], 7); + FOR(i = 0; i < 7; i++) + { + /*isf2[9+i] = isf[9+i] - dico2_isf[i+surv1[k]*7];*/ + isf2[i + 9] = sub(isf[9 + i], dico2_isf_fx[i + tmp16]); + move16(); + } + + tmp_ind[0] = sub_VQ_fx(&isf2[9], dico23_isf_36b_fx, 3, SIZE_BK23_36b, &min_err); + move16(); + temp = L_add(min_err, 0); + IF(LT_32(temp, distance)) + { + distance = L_add(temp, 0); + indice[1] = surv1[k]; + move16(); + indice[4] = tmp_ind[0]; + move16(); + } + } + + /*------------------------------------------------------------------------* + * decoding the ISFs + *------------------------------------------------------------------------*/ + + disf_2s_36b_fx(indice, isf, mem_AR, mem_MA, 0); + + /*------------------------------------------------------------------------* + * write indices to array + *------------------------------------------------------------------------*/ + + indice[0] = Indirect_dico1[indice[0]]; + move16(); /* Make interoperable with G722.2 */ + + push_indice_fx(hBstr, IND_ISF_0_0, indice[0], 8); + push_indice_fx(hBstr, IND_ISF_0_1, indice[1], 8); + push_indice_fx(hBstr, IND_ISF_1_0, indice[2], 7); + push_indice_fx(hBstr, IND_ISF_1_1, indice[3], 7); + push_indice_fx(hBstr, IND_ISF_1_2, indice[4], 6); + + return; +} + + +/*-------------------------------------------------------------------* + * qisf_2s_46b() + * + * ISF quantizer for all other AMR-WB frames + * + * The ISF vector is quantized using two-stage VQ with split-by-2 + * in 1st stage and split-by-5 in the second stage. + *-------------------------------------------------------------------*/ + +static void qisf_2s_46b_fx( + BSTR_ENC_HANDLE hBstr, /* i/o: encoder state structure */ + Word16 *isf, /* i/o: unquantized/quantized ISF vector */ + Word16 nb_surv, /* i : number of survivors (1, 2, 3 or 4) */ + Word16 *mem_AR, /* o : quantizer memory for AR model */ + Word16 *mem_MA /* i/o: quantizer memory for MA model */ +) +{ + Word16 i, k, indice[7], tmp_ind[5]; + Word16 surv1[N_SURV_MAX]; /* indices of survivors from 1st stage */ + Word32 temp, min_err, distance; + Word16 tmp16, isf2[M]; + + + /*------------------------------------------------------------------------* + * Subtract mean + *------------------------------------------------------------------------*/ + + FOR(i = 0; i < M; i++) + { + /*isf[i] -= mean_isf_amr_wb[i] + MU_MA * mem_MA[i];*/ + tmp16 = sub(isf[i], mean_isf_amr_wb_fx[i]); + isf[i] = sub(tmp16, mult(MU_MA_FX, mem_MA[i])); + move16(); + } + + /*------------------------------------------------------------------------* + * Quantize ISFs 0 - 8 + *------------------------------------------------------------------------*/ + + VQ_stage1_fx(&isf[0], dico1_isf_fx, 9, SIZE_BK1, surv1, nb_surv); + + distance = MAX_32; + move32(); + nb_surv = s_min(nb_surv, N_SURV_MAX); + + FOR(k = 0; k < nb_surv; k++) + { + tmp16 = i_mult2(surv1[k], 9); + FOR(i = 0; i < 9; i++) + { + /*isf2[i] = isf[i] - dico1_isf[i+surv1[k]*9];*/ + isf2[i] = sub(isf[i], dico1_isf_fx[i + tmp16]); + move16(); + } + + tmp_ind[0] = sub_VQ_fx(&isf2[0], dico21_isf_46b_fx, 3, SIZE_BK21, &min_err); + temp = L_add(min_err, 0); + tmp_ind[1] = sub_VQ_fx(&isf2[3], dico22_isf_46b_fx, 3, SIZE_BK22, &min_err); + temp = L_add(temp, min_err); + tmp_ind[2] = sub_VQ_fx(&isf2[6], dico23_isf_46b_fx, 3, SIZE_BK23, &min_err); + temp = L_add(temp, min_err); + IF(LT_32(temp, distance)) + { + distance = L_add(temp, 0); + indice[0] = surv1[k]; + move16(); + FOR(i = 0; i < 3; i++) + { + indice[i + 2] = tmp_ind[i]; + move16(); + } + } + } + + /*------------------------------------------------------------------------* + * Quantize ISFs 9 - 15 + *------------------------------------------------------------------------*/ + + VQ_stage1_fx(&isf[9], dico2_isf_fx, 7, SIZE_BK2, surv1, nb_surv); + + distance = MAX_32; + move32(); + FOR(k = 0; k < nb_surv; k++) + { + tmp16 = i_mult2(surv1[k], 7); + FOR(i = 0; i < 7; i++) + { + /*isf2[9+i] = isf[9+i] - dico2_isf[i+surv1[k]*7];*/ + isf2[i + 9] = sub(isf[9 + i], dico2_isf_fx[i + tmp16]); + move16(); + } + tmp_ind[0] = sub_VQ_fx(&isf2[9], dico24_isf_46b_fx, 3, SIZE_BK24, &min_err); + move16(); + temp = L_add(min_err, 0); + + tmp_ind[1] = sub_VQ_fx(&isf2[12], dico25_isf_46b_fx, 4, SIZE_BK25, &min_err); + move16(); + temp = L_add(temp, min_err); + + IF(LT_32(temp, distance)) + { + distance = L_add(temp, 0); + indice[1] = surv1[k]; + move16(); + FOR(i = 0; i < 2; i++) + { + indice[i + 5] = tmp_ind[i]; + move16(); + } + } + } + + /*------------------------------------------------------------------------* + * decoding the ISFs + *------------------------------------------------------------------------*/ + + disf_2s_46b_fx(indice, isf, mem_AR, mem_MA, 0); + + /*------------------------------------------------------------------------* + * write indices to array + *------------------------------------------------------------------------*/ + indice[0] = Indirect_dico1[indice[0]]; + move16(); /* Make interoperable with G722.2 */ + + push_indice_fx(hBstr, IND_ISF_0_0, indice[0], 8); + push_indice_fx(hBstr, IND_ISF_0_1, indice[1], 8); + push_indice_fx(hBstr, IND_ISF_1_0, indice[2], 6); + push_indice_fx(hBstr, IND_ISF_1_1, indice[3], 7); + push_indice_fx(hBstr, IND_ISF_1_2, indice[4], 7); + push_indice_fx(hBstr, IND_ISF_1_3, indice[5], 5); + push_indice_fx(hBstr, IND_ISF_1_4, indice[6], 5); + + return; +} + +/*-------------------------------------------------------------------* + * VQ_stage1() + * + * 1st stage of ISF quantization + *-------------------------------------------------------------------*/ + +static void VQ_stage1_fx( + const Word16 *x, /* i : ISF vector */ + const Word16 *dico, /* i : ISF codebook */ + const Word16 dim, /* i : codebook dimension */ + const Word16 dico_size, /* i : codebook size */ + Word16 *index, /* o : indices of best vector candidates */ + const Word16 surv /* i : nb of surviving best candidates */ +) +{ + Word32 dist_min[N_SURV_MAX]; + Word32 dist; + const Word16 *p_dico; + Word16 i, j, k, l, temp; + + + FOR(i = 0; i < surv; i++) + { + dist_min[i] = MAX_32; + move32(); + index[i] = i; + move16(); + } + + p_dico = dico; + + FOR(i = 0; i < dico_size; i++) + { + dist = L_deposit_l(0); + FOR(j = 0; j < dim; j++) + { + /*temp = x[j] - *p_dico++;*/ + temp = sub(x[j], *p_dico++); + /*dist += temp * temp;*/ + dist = L_mac(dist, temp, temp); + } + + FOR(k = 0; k < surv; k++) + { + IF(LT_32(dist, dist_min[k])) + { + FOR(l = sub(surv, 1); l > k; l--) + { + dist_min[l] = dist_min[l - 1]; + move32(); + index[l] = index[l - 1]; + move16(); + } + dist_min[k] = dist; + move32(); + index[k] = i; + move16(); + BREAK; + } + } + } + return; +} + +/*-------------------------------------------------------------------* + * sub_VQ_fx() + * + * Quantization of a subvector in Split-VQ of ISFs + *-------------------------------------------------------------------*/ + +static Word16 sub_VQ_fx( /* o : selected codebook vector index */ + Word16 *x, /* i/o: ISF vector */ + const Word16 *dico, /* i : ISF codebook */ + const Word16 dim, /* i : codebook dimension */ + const Word16 dico_size, /* i : codebook size */ + Word32 *distance /* o : quantization error (min. distance) */ +) +{ + Word32 dist_min, dist; + const Word16 *p_dico; + Word16 i, j, index, temp; + + + dist_min = MAX_32; + move32(); + p_dico = dico; + move16(); + + index = 0; + move16(); + FOR(i = 0; i < dico_size; i++) + { + dist = L_deposit_l(0); + FOR(j = 0; j < dim; j++) + { + /*temp = x[j] - *p_dico++;*/ + temp = sub(x[j], *p_dico++); + /*dist += temp * temp;*/ + dist = L_mac(dist, temp, temp); + } + + IF(LT_32(dist, dist_min)) + { + dist_min = L_add(dist, 0); + index = i; + move16(); + } + } + + *distance = dist_min; + move32(); + + /* Reading the selected vector */ + p_dico = &dico[i_mult2(index, dim)]; + FOR(j = 0; j < dim; j++) + { + x[j] = *p_dico++; + move16(); + } + return index; +} diff --git a/lib_enc/nelp_enc.c b/lib_enc/nelp_enc.c index 1c065a517..9f72248ff 100644 --- a/lib_enc/nelp_enc.c +++ b/lib_enc/nelp_enc.c @@ -317,7 +317,7 @@ void nelp_encoder( } else if ( st->bwidth == NB ) { - polezero_filter( ptr, ptr_tmp, L_FRAME, bp1_num_coef_nb_fx_order7, bp1_den_coef_nb_fx_order7, 7, hSC_VBR->bp1_filt_mem_nb ); + polezero_filter( ptr, ptr_tmp, L_FRAME, bp1_num_coef_nb_fx_order7_flt, bp1_den_coef_nb_fx_order7_flt, 7, hSC_VBR->bp1_filt_mem_nb ); mvr2r( ptr_tmp, ptr, L_FRAME ); } diff --git a/lib_enc/nelp_enc_fx.c b/lib_enc/nelp_enc_fx.c new file mode 100644 index 000000000..c5042c48a --- /dev/null +++ b/lib_enc/nelp_enc_fx.c @@ -0,0 +1,1028 @@ +/****************************************************************************************************** + + (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include "control.h" +#include "options.h" /* Compilation switches */ +#include "cnst.h" /* Common constants */ +#include "prot_fx2.h" /* Function prototypes */ +#include "prot_fx1.h" +#include "rom_com.h" + +/*===================================================================*/ +/* FUNCTION : quantize_uvg_fx() */ +/*-------------------------------------------------------------------*/ +/* PURPOSE : This function returns the quantized gain vector */ +/* and corresponding table indices, given the +input unquantized gain vector */ +/*-------------------------------------------------------------------*/ +/* INPUT ARGUMENTS : */ +/* _ (Word16*) G : Un-quantized gain vector (Q0) */ +/*-------------------------------------------------------------------*/ +/* OUTPUT ARGUMENTS : */ +/* _ (Word16) iG1 : UVG1CB_fx table index (Q0) */ +/* _ (Word16*) iG2 : UVG2CB_fx table indices (Q0) */ +/* _ (Word16*) quantG : Output quantized gain vector */ +/*-------------------------------------------------------------------*/ +/* INPUT/OUTPUT ARGUMENTS : */ +/* _ None. */ +/*-------------------------------------------------------------------*/ +/* RETURN ARGUMENTS : */ +/* _ None. */ +/*===================================================================*/ + +void quantize_uvg_fx(Word16 *G, Word16 *iG1, Word16 *iG2, Word16 *quantG, Word16 bwidth_fx) +{ + Word16 G1[2], G2[10], L16, L16_1; + Word16 i, j, k, ind, temp; + Word32 mmse; + Word16 exp, tmp, frac; + Word32 Lacc, Lexp[2], L_tmp; + const Word16(*UVG1CB_fx)[2] = NULL; + const Word16(*UVG2CB1_fx)[5] = NULL; + const Word16(*UVG2CB2_fx)[5] = NULL; + test(); + IF(EQ_16(bwidth_fx, NB)) + { + UVG1CB_fx = UVG1CB_NB_FX; + move16();/*Q13 */ + UVG2CB1_fx = UVG2CB1_NB_FX; + move16();/*Q12 */ + UVG2CB2_fx = UVG2CB2_NB_FX; + move16();/*Q12 */ + } + ELSE IF(EQ_16(bwidth_fx, WB) || EQ_16(bwidth_fx, SWB)) + { + UVG1CB_fx = UVG1CB_WB_FX; + move16();/*Q13 */ + UVG2CB1_fx = UVG2CB1_WB_FX; + move16();/*Q12 */ + UVG2CB2_fx = UVG2CB2_WB_FX; + move16();/*Q12 */ + } + + + FOR(i = 0; i < 2; i++) + { + Lacc = L_deposit_l(0); + FOR(j = 0; j < 5; j++) + { + ind = add(shr(extract_l(L_mult(i, 5)), 1), j); + Lacc = L_mac0(Lacc, G[ind], G[ind]); /*Q0 */ + } + + IF(Lacc == 0) + { + Lacc = L_deposit_l(1); /* to avoid log10(0) */ + } + + /*G1[i] = (float) log10(sqrt(G1[i]/5)); */ + L_tmp = Mult_32_16(Lacc, 13108); + IF(L_tmp) + { + exp = norm_l(L_tmp); + frac = Log2_norm_lc(L_shl(L_tmp, exp)); + exp = (30 - exp - 1); + move16();/*(+1)=/2 in log */ + L_tmp = Mpy_32_16(exp, frac, 4932); /*Q16 ; 0.5*log10(2) in Q15 */ + G1[i] = round_fx(L_shl(L_tmp, 13)); /*Q13 */ + } + ELSE + { + G1[i] = 0; + move16(); + } + + } + + + mmse = L_add(MAX_32, 0); + *iG1 = 0; + move16(); + FOR(i = 0; i < UVG1_CBSIZE; i++) + { + L16 = shr(sub(G1[0], UVG1CB_fx[i][0]), 1); /* Q12 */ + L16_1 = shr(sub(G1[1], UVG1CB_fx[i][1]), 1); /* Q12 */ + Lacc = 0; + Lacc = L_mac0(Lacc, L16, L16); /*Q24 */ + Lacc = L_mac0(Lacc, L16_1, L16_1);/*Q24 */ + + IF(LT_32(Lacc, mmse)) + { + *iG1 = i; + move16(); + mmse = Lacc; + } + + } + + L_tmp = L_mult0(UVG1CB_fx[*iG1][0], 27213);/*Q26 */ + L_tmp = L_shr(L_tmp, 10); /* From Q26 to Q16 */ + frac = L_Extract_lc(L_tmp, &exp); /* Extract exponent of L_tmp */ + L_tmp = Pow2(30, frac); + exp = exp - 30; /*move16(); */ + Lexp[0] = L_shl(L_tmp, exp + 15); + + + L_tmp = L_mult0(UVG1CB_fx[*iG1][1], 27213);/*Q26 */ + L_tmp = L_shr(L_tmp, 10); /* From Q26 to Q16 */ + frac = L_Extract_lc(L_tmp, &exp); /* Extract exponent of L_tmp */ + L_tmp = Pow2(30, frac); + exp = exp - 30; /*move16(); */ + Lexp[1] = L_shl(L_tmp, exp + 15); + + + FOR(i = 0; i < 2; i++) + { + FOR(j = 0; j < 5; j++) + { + exp = norm_l(Lexp[i]); + tmp = extract_h(L_shl(Lexp[i], exp)); + exp = sub(sub(30, exp), 15); + tmp = div_s(16384, tmp); /*Q(15+exp) */ + L_tmp = L_shr(L_mult0(G[i * 5 + j], tmp), exp + 3); /*Q12 */ + G2[i * 5 + j] = extract_l(L_tmp); /*Q12 */ + } + } + + + FOR(i = 0; i < 2; i++) + { + mmse = MAX_32; + iG2[i] = 0; + FOR(j = 0; j < UVG2_CBSIZE; j++) + { + Lacc = L_deposit_l(0); + FOR(k = 0; k < 5; k++) + { + IF(i == 0) + { + /*mse += SQR(G2[i*5+k]-UVG2CB1[j][k]); */ + ind = add(shr(extract_l(L_mult(i, 5)), 1), k); + temp = sub(G2[ind], UVG2CB1_fx[j][k]); + Lacc = L_mac0(Lacc, temp, temp); /*Q24 */ + } + ELSE IF(i == 1) + { + /*mse += SQR(G2[i*5+k]-UVG2CB2[j][k]); */ + ind = add(shr(extract_l(L_mult(i, 5)), 1), k); + temp = sub(G2[ind], UVG2CB2_fx[j][k]); + Lacc = L_mac0(Lacc, temp, temp); /*Q24 */ + } + } + + IF(LT_32(Lacc, mmse)) + { + mmse = Lacc; + iG2[i] = j; + move16(); + } + } + } + + dequantize_uvg_fx(*iG1, iG2, quantG, bwidth_fx, 0); + +} + +/*===================================================================*/ +/* FUNCTION : normalize_arr() */ +/*-------------------------------------------------------------------*/ +/* PURPOSE : Normalize array */ +/* */ +/*-------------------------------------------------------------------*/ +/* GLOBAL INPUT ARGUMENTS : */ +/* _ (Word16*) qf */ +/* _ (Word16*) size */ +/* _ (Word16*) hdr */ +/*-------------------------------------------------------------------*/ +/* OUTPUT ARGUMENTS : */ +/* _ (Word16*) arr : Normalized array */ +/*-------------------------------------------------------------------*/ + +/* _ None */ +/*-------------------------------------------------------------------*/ +/* RETURN ARGUMENTS : */ +/* _ None */ +/*===================================================================*/ +static void normalize_arr(Word16 *arr, Word16 *qf, Word16 size, Word16 hdr) +{ + Word16 i; + Word16 max_s = 0; + + FOR(i = 0; i < size; i++) + { + max_s = s_max(max_s, abs_s(arr[i])); + } + + *qf = norm_s((Word16)max_s); + test(); + IF((*qf == 0) && (((Word16)max_s) == 0)) + { + *qf = 15; + move16(); + } + + *qf = *qf - hdr; + + FOR(i = 0; i < size; i++) + { + arr[i] = shl(arr[i], *qf); + move16(); /* saturation can occur here */ + } + + return; +} + + +/*===================================================================*/ +/* FUNCTION : nelp_encoder_fx() */ +/*-------------------------------------------------------------------*/ +/* PURPOSE : NELP encoder */ +/* */ +/*-------------------------------------------------------------------*/ +/* GLOBAL INPUT ARGUMENTS : */ +/* _ (Struct) st : encoder state */ +/* _ (Word16[]) in_fx : residual signal (qIn) */ +/*-------------------------------------------------------------------*/ +/* OUTPUT ARGUMENTS : */ +/* _ (Word16[]) exc_fx : NELP quantized excitation signal (qIn) */ +/* _ (Word16) qIn1 : input/output qformat */ +/*-------------------------------------------------------------------*/ + +/* _ (Word16[]) shape1_filt_mem_fx : filter memory (Q0) */ +/* _ (Word16[]) shape2_filt_mem_fx : filter memory (Q0) */ +/* _ (Word16[]) shape3_filt_mem_fx : filter memory (Q0) */ +/* _ (Word16[]) bp1_filt_mem_wb_fx : filter memory (Q0) */ +/* _ (Word16[]) txlpf1_filt1_mem_fx : filter memory (Q0) */ +/* _ (Word16[]) txlpf1_filt1_mem_fx : filter memory (Q0) */ +/* _ (Word16[]) txhpf1_filt2_mem_fx : filter memory (Q-1) */ +/* _ (Word16[]) txlpf1_filt2_mem_fx : filter memory (Q0) */ +/* _ (Word16) nelp_gain_mem_fx : gain memory (Q0) */ +/* _ (Word16) nelp_enc_seed : */ +/*-------------------------------------------------------------------*/ +/* RETURN ARGUMENTS : */ +/* _ None */ +/*===================================================================*/ + +void nelp_encoder_fx( + Encoder_State *st_fx,/* i/o: encoder state */ + Word16 *in_fx, /* i : residual signal */ + Word16 *exc_fx, /* o : NELP quantized excitation signal */ + Word16 *qIn1, + Word16 reduce_gains +) +{ + Word16 i, j; + Word16 *ptr_fx = exc_fx; + Word16 lag = 25; /* to cover 25*9 + 31 */ + Word16 sqrt_inv_lag = 6554; /* sqrt(1/lag) in Q15 */ + Word16 sqrt_inv_lframe_lag = 5885; /* sqrt(1/(L_FRAME-lag*9)) */ + Word16 Gains_fx[10], gain_fac_fx; + Word16 iG1_fx, iG2_fx[2]; + Word16 fid; + Word16 fdbck_fx; + Word32 var_dB_fx; + Word32 E1_fx = 0, EL1_fx = 0, EH1_fx = 0, E2_fx = 0, E3_fx = 0, EL2_fx = 0, EH2_fx = 0; + Word32 RL_fx = 0, RH_fx = 0; + Word16 R_fx = 0; + Word16 filtRes_fx[L_FRAME]; + Word16 ptr_tmp_fx[L_FRAME]; + + Word16 qE1 = 0, qE2 = 0, qE3 = 0, qEL1 = 0, qEL2 = 0, qEH1 = 0, qEH2 = 0; + Word16 qIn = 0, qGain = 0, qf = 0, qf1 = 0, qNelpGain = 0; + Word16 exp1, exp2, tmp1, tmp2; + Word16 f_Noise, etmp, e_Noise; + Word16 max1 = 0; + Word32 l_nelp_gain_mem; + Word32 Ltemp = 0, Ltemp1 = 0, L_tmp = 0, L_const_1; + Word16 BP1_ORDER; + Word16 rf_flag; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + SC_VBR_ENC_HANDLE hSC_VBR = st_fx->hSC_VBR; + BSTR_ENC_HANDLE hBstr = st_fx->hBstr; + RF_ENC_HANDLE hRF = st_fx->hRF; + + rf_flag = st_fx->rf_mode; + + if (EQ_16(hSC_VBR->last_nelp_mode, 1) && NE_16(st_fx->bwidth, st_fx->last_bwidth)) + { + hSC_VBR->last_nelp_mode = 0; + } + + qIn = *qIn1; + move16(); + test(); + IF(EQ_16(st_fx->bwidth, NB)) + { + IF(hSC_VBR->last_nelp_mode != 1) + { + BP1_ORDER = 7; + move16(); + set32_fx(hSC_VBR->bp1_filt_mem_nb_fx, 0, BP1_ORDER * 2); + hSC_VBR->qprevGain_fx = 0; + move16(); + } + } + ELSE IF(EQ_16(st_fx->bwidth, WB) || EQ_16(st_fx->bwidth, SWB)) + { + IF(hSC_VBR->last_nelp_mode != 1) + { + BP1_ORDER = 4; + move16(); + set16_fx(hSC_VBR->bp1_filt_mem_wb_fx, 0, BP1_ORDER * 2); + } + } + + IF(hSC_VBR->last_nelp_mode != 1) + { + test(); + IF(st_fx->bwidth == WB || EQ_16(st_fx->bwidth, SWB)) + { + set16_fx(hSC_VBR->shape1_filt_mem_fx, 0, 10); + set16_fx(hSC_VBR->shape2_filt_mem_fx, 0, 10); + set16_fx(hSC_VBR->shape3_filt_mem_fx, 0, 10); + set16_fx(hSC_VBR->txlpf1_filt1_mem_fx, 0, 10); + set16_fx(hSC_VBR->txlpf1_filt2_mem_fx, 0, 10); + set16_fx(hSC_VBR->txhpf1_filt1_mem_fx, 0, 10); + set16_fx(hSC_VBR->txhpf1_filt2_mem_fx, 0, 10); + hSC_VBR->qprevIn_fx = 0; + move16(); + hSC_VBR->qprevGain_fx = 0; + move16(); + } + } + + /* Start Unvoiced/NELP Processing */ + test(); + IF(EQ_16(st_fx->bwidth, WB) || EQ_16(st_fx->bwidth, SWB)) + { + qE1 = qIn; + move16(); + E1_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { +#ifdef BASOP_NOGLOB + E1_fx = L_mac0_o(E1_fx, in_fx[i], in_fx[i], &Overflow); /*Q(qE1+qE1) */ +#else + E1_fx = L_mac0(E1_fx, in_fx[i], in_fx[i]); /*Q(qE1+qE1) */ +#endif + } + + qE1 = shl(qE1, 1);; + + qf = qIn; + move16(); + Scale_sig(hSC_VBR->txlpf1_filt1_mem_fx, 10, (qf - hSC_VBR->qprevIn_fx)); + pz_filter_sp_fx(txlpf1_num_coef_fx, txlpf1_den_coef_fx, in_fx, filtRes_fx, hSC_VBR->txlpf1_filt1_mem_fx, 10, 10, L_FRAME, 3);/*1 = (16-qformat of shape1 cofficient) */ + + qEL1 = qf; + move16(); + EL1_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { +#ifdef BASOP_NOGLOB + EL1_fx = L_mac0_o(EL1_fx, filtRes_fx[i], filtRes_fx[i], &Overflow); /*Q(2*qIn) */ +#else + EL1_fx = L_mac0(EL1_fx, filtRes_fx[i], filtRes_fx[i]); /*Q(2*qIn) */ +#endif + } + qEL1 = shl(qEL1, 1); + + qf = qIn; + move16(); + Scale_sig(hSC_VBR->txhpf1_filt1_mem_fx, 10, qf - hSC_VBR->qprevIn_fx); + pz_filter_sp_fx(txhpf1_num_coef_fx, txhpf1_den_coef_fx, in_fx, filtRes_fx, hSC_VBR->txhpf1_filt1_mem_fx, 10, 10, L_FRAME, 3);/*1 = (16-qformat of shape1 cofficient) */ + hSC_VBR->qprevIn_fx = qf; + move16(); + + qEH1 = qf; + move16(); + EH1_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { +#ifdef BASOP_NOGLOB + EH1_fx = L_mac0_o(EH1_fx, filtRes_fx[i], filtRes_fx[i], &Overflow); /*Q(2*qEH1) */ +#else + EH1_fx = L_mac0(EH1_fx, filtRes_fx[i], filtRes_fx[i]); /*Q(2*qEH1) */ +#endif + } + qEH1 = 2 * qEH1; + move16(); + + } + + qGain = qIn; + move16(); + qGain = 2 * qGain; + move16(); + + FOR(i = 0; i < 9; i++) + { + Ltemp = L_deposit_l(0); + FOR(j = (Word16)(i*lag); j < (Word16)((i + 1)*lag); j++) + { +#ifdef BASOP_NOGLOB + Ltemp = L_mac0_o(Ltemp, in_fx[j], in_fx[j], &Overflow); /*Q(2*qGain) */ +#else + Ltemp = L_mac0(Ltemp, in_fx[j], in_fx[j]); /*Q(2*qGain) */ +#endif + } + + /*Gains[i] = (float) sqrt(Gains[i]/lag); */ + IF(Ltemp != 0) + { + exp1 = norm_l(Ltemp); + tmp1 = extract_h(L_shl(Ltemp, exp1));/*2*qGain+exp1-16 */ + exp1 = sub(exp1, 30 - qGain); /* */ + + tmp1 = div_s(16384, tmp1);/*14-2*qGain-exp1+16 */ + L_tmp = L_deposit_h(tmp1); + L_tmp = Isqrt_lc(L_tmp, &exp1); + L_tmp = Mult_32_16(L_tmp, sqrt_inv_lag); + Ltemp = L_shl(L_tmp, sub(exp1, 12));/*Q3 */ + } + + Gains_fx[i] = round_fx(Ltemp); + } + + + Ltemp = L_deposit_l(0); + FOR(j = (Word16)(i*lag); j < L_FRAME; j++) + { +#ifdef BASOP_NOGLOB + Ltemp = L_mac0_o(Ltemp, in_fx[j], in_fx[j], &Overflow); /*Q(2*qGain) */ +#else + Ltemp = L_mac0(Ltemp, in_fx[j], in_fx[j]); /*Q(2*qGain) */ +#endif + } + + /*Gains[i] = (float) sqrt(Gains[i]/(L_FRAME-(lag*i))); */ + IF(Ltemp != 0) + { + exp1 = norm_l(Ltemp); + tmp1 = extract_h(L_shl(Ltemp, exp1)); + exp1 = sub(exp1, 30 - qGain); /* */ + + tmp1 = div_s(16384, tmp1); + L_tmp = L_deposit_h(tmp1); + L_tmp = Isqrt_lc(L_tmp, &exp1); + L_tmp = Mult_32_16(L_tmp, sqrt_inv_lframe_lag); + Ltemp = L_shl(L_tmp, sub(exp1, 12)); + } + + Gains_fx[i] = round_fx(Ltemp); + + IF(EQ_16(reduce_gains, 1)) + { + FOR(i = 0; i < 10; i++) + { + Gains_fx[i] = mult(Gains_fx[i], 19661); + } + } + + + qGain = 3; + move16(); + IF(hSC_VBR->last_nelp_mode != 1) /* if prev frame was not NELP then init mem*/ + { + hSC_VBR->nelp_gain_mem_fx = Gains_fx[0]; + move16(); + qNelpGain = qGain; + move16(); + } + + /* tmp = (float) (20.0 * (log10 (Gains[0]) - log10 (st->nelp_gain_mem) ) ); */ + /* var_dB = tmp * tmp; */ + L_tmp = L_deposit_l(Gains_fx[0]); + L_tmp = L_max(L_tmp, 1); + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qEL1-qEL2-exp1+exp2 */ + exp2 = 30 - exp2 - qGain; + move16(); + tmp1 = Log2_norm_lc(L_tmp); + Ltemp = Mpy_32_16(exp2, tmp1, 9864); /*log(2) in Q13 format = Q0 format */ + /*tmp1 = round_fx(L_shl(Ltemp,12)); Q12 */ + + L_tmp = L_deposit_l(hSC_VBR->nelp_gain_mem_fx); /*Q0 */ + L_tmp = L_max(L_tmp, 1); + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qEL1-qEL2-exp1+exp2 */ + exp2 = 30 - exp2 - qNelpGain; + move16(); + tmp2 = Log2_norm_lc(L_tmp); + Ltemp1 = Mpy_32_16(exp2, tmp2, 9864); /*log(2) in Q13 format = Q0 format */ + Ltemp1 = L_sub(Ltemp, Ltemp1);/*Q16 */ + Ltemp = Mult_32_16(Ltemp1, 20480);/*Q11 (20 in Q10) */ + L_tmp = L_shl(Ltemp, 12);/*Q23 */ + var_dB_fx = Mult_32_32(L_tmp, L_tmp);/*Q15 */ + + FOR(i = 1; i < 10; i++) + { + L_tmp = L_deposit_l(Gains_fx[i]); + L_tmp = L_max(L_tmp, 1); + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qEL1-qEL2-exp1+exp2 */ + exp2 = 30 - exp2 - qGain; + move16(); + tmp1 = Log2_norm_lc(L_tmp); + Ltemp = Mpy_32_16(exp2, tmp1, 9864); /*log(2) in Q13 format = Q0 format */ + + L_tmp = L_deposit_l(Gains_fx[i - 1]); /*Q0 */ + L_tmp = L_max(L_tmp, 1); + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qEL1-qEL2-exp1+exp2 */ + exp2 = 30 - exp2 - qGain; + move16(); + tmp2 = Log2_norm_lc(L_tmp); + Ltemp1 = Mpy_32_16(exp2, tmp2, 9864); /*log(2) in Q13 format = Q0 format */ + Ltemp1 = L_sub(Ltemp, Ltemp1);/*Q16 */ + Ltemp = Mult_32_16(Ltemp1, 20480);/*Q11 (20 in Q10) */ + L_tmp = L_shl(Ltemp, 12);/*Q23 */ + L_tmp = Mult_32_32(L_tmp, L_tmp);/*Q15 */ + var_dB_fx = L_add(L_tmp, var_dB_fx);/*Q15 */ + } + + IF(hSC_VBR->last_nelp_mode != 1) + { + /*var_dB *= 0.111f; */ + var_dB_fx = Mult_32_16(var_dB_fx, 3637); /*0.111 in Q15 */ + } + ELSE + { + /*var_dB *= 0.1f; */ + var_dB_fx = Mult_32_16(var_dB_fx, 3277); /*0.1 in Q15 */ + } + + max1 = 0; + move16(); + FOR(i = 0; i < 10; i++) + { + max1 = s_max(max1, abs_s(Gains_fx[i])); + } + + qf = norm_s((Word16)max1); + test(); + IF((qf == 0) && (((Word16)max1) == 0)) + { + qf = 15; + move16(); + } + qf = sub(qf, 1); + qGain = add(qGain, qf); + + Scale_sig(Gains_fx, 10, qf); + + L_tmp = L_sub(var_dB_fx, 655360); /* 20 in Q15 */ + Ltemp = L_shr_r(L_tmp, 2);/*Q15 */ + { + /*exp = pow(2, x*log2(e)) */ + L_tmp = Mult_32_16(Ltemp, 23637); /*15 + 14 -15 ->Q14 */ + L_tmp = L_shl(L_tmp, 2); /*Q16 */ + f_Noise = L_Extract_lc(L_tmp, &e_Noise); /*Q16 */ + etmp = extract_l(Pow2(14, f_Noise)); /* Put 14 as exponent */ + e_Noise = sub(e_Noise, 14); /* Retreive exponent of etmp */ + + + IF(e_Noise > 0) + { + L_tmp = L_shl(etmp, e_Noise); /* Result in Q30 */ + L_tmp = L_add(1, L_tmp); + + exp1 = norm_l(L_tmp); + tmp1 = extract_h(L_shl(L_tmp, exp1));/*exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(exp1-16)-> 30+15-exp1 */ + fdbck_fx = mult(26870, tmp1);/*45-exp1+15-15=>45-exp1 */ + fdbck_fx = shr_r(fdbck_fx, 14); + exp1 = sub(31, exp1); + } + ELSE + { + L_tmp = L_shl(etmp,add(e_Noise, 14)); /* Result in Q30 */ + L_tmp = L_add(16384, L_tmp); + + exp1 = norm_l(L_tmp); + tmp1 = extract_h(L_shl(L_tmp, exp1));/*14+exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(14+exp1-16)-> 16+15-exp1 */ + fdbck_fx = mult(26870, tmp1);/*31-exp1+15-15=>31-exp1 */ + exp1 = sub(31,exp1); + } + } + + IF(exp1 == 31) + { + L_const_1 = 0x7fffffff; + move32(); + } + ELSE + { + L_const_1 = L_shl(1, exp1); + } + + l_nelp_gain_mem = L_deposit_l(hSC_VBR->nelp_gain_mem_fx); + IF(NE_16(qNelpGain, qGain)) + { + l_nelp_gain_mem = L_shl(l_nelp_gain_mem, sub(qGain, qNelpGain)); + } + + FOR(i = 0; i < 10; i++) + { + /*Gains[i] = (float)((1.0f - fdbck) * Gains[i] + fdbck * st->nelp_gain_mem); */ + L_tmp = L_sub(L_const_1, L_deposit_l(fdbck_fx));/*31-exp1 */ + L_tmp = Mult_32_16(L_tmp, Gains_fx[i]);/*exp1+qGain-15=>exp1-15+qGain */ + Ltemp1 = Mult_32_16(l_nelp_gain_mem, fdbck_fx);/*exp1+qGain-15 */ + L_tmp = L_add(L_tmp, Ltemp1); + L_tmp = L_shr_r(L_tmp, (exp1 - 15)); + Gains_fx[i] = round_fx(L_shl(L_tmp, 16)); + move16(); + l_nelp_gain_mem = L_tmp; + } + + hSC_VBR->nelp_gain_mem_fx = round_fx(L_shl(l_nelp_gain_mem, 16)); + + Scale_sig(&hSC_VBR->nelp_gain_mem_fx, 1, -qGain); + Scale_sig(Gains_fx, 10, -qGain); + qGain = 0; + move16(); + + quantize_uvg_fx(Gains_fx, &iG1_fx, iG2_fx, Gains_fx, st_fx->bwidth); + + IF(EQ_16(rf_flag, 1)) + { + hRF->rf_indx_nelp_iG1[0] = iG1_fx; + hRF->rf_indx_nelp_iG2[0][0] = iG2_fx[0]; + hRF->rf_indx_nelp_iG2[0][1] = iG2_fx[1]; + } + ELSE + { + push_indice_fx(hBstr, IND_IG1, iG1_fx, 5); + push_indice_fx(hBstr, IND_IG2A, iG2_fx[0], 6); + push_indice_fx(hBstr, IND_IG2B, iG2_fx[1], 6); + } + + test(); + IF(EQ_16(st_fx->bwidth, WB) || EQ_16(st_fx->bwidth, SWB)) + { + gain_fac_fx = 19005; + move16();/* 1.16f in Q14 */ + } + ELSE + { + gain_fac_fx = 22446; + move16(); /* 1.37f in Q14 */ + } + + /* Normalize Gains_fx[10] with headroom 4 */ + /* This fills up qGain with some new value */ + normalize_arr(Gains_fx, &qGain, 10, 4); + + generate_nelp_excitation_fx(&(hSC_VBR->nelp_enc_seed), Gains_fx, ptr_fx, gain_fac_fx); + test(); + IF(EQ_16(st_fx->bwidth, WB) || EQ_16(st_fx->bwidth, SWB)) + { + BP1_ORDER = 4; + Scale_sig(hSC_VBR->bp1_filt_mem_wb_fx, BP1_ORDER * 2, qGain - hSC_VBR->qprevGain_fx);/*qf-qAdj */ + pz_filter_sp_fx(bp1_num_coef_wb_fx, bp1_den_coef_wb_fx, ptr_fx, ptr_tmp_fx, hSC_VBR->bp1_filt_mem_wb_fx, BP1_ORDER, BP1_ORDER, L_FRAME, 2); + Copy(ptr_tmp_fx, ptr_fx, L_FRAME); + } + ELSE IF(EQ_16(st_fx->bwidth, NB)) + { + BP1_ORDER = 7; + move16(); + Scale_sig32(hSC_VBR->bp1_filt_mem_nb_fx, BP1_ORDER * 2, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_dp_fx(bp1_num_coef_nb_fx_order7, bp1_den_coef_nb_fx_order7, ptr_fx, ptr_tmp_fx, hSC_VBR->bp1_filt_mem_nb_fx, BP1_ORDER, BP1_ORDER, L_FRAME, (sub(16, BP1_COEF_NB_QF_ORDER7))); + Copy(ptr_tmp_fx, ptr_fx, L_FRAME); + + Scale_sig(ptr_fx, L_FRAME, -1); /* bring exc to qgain-1 */ + *qIn1 = qGain - 1; /* use this temp only in the parent */ + } + + E3_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { + E3_fx = L_mac(E3_fx, ptr_fx[i], ptr_fx[i]); /*Q1 */ + } + qE3 = 2 * qGain + 1; + move16(); + test(); + IF(st_fx->bwidth == WB || EQ_16(st_fx->bwidth, SWB)) + { + Scale_sig(hSC_VBR->shape1_filt_mem_fx, 10, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(shape1_num_coef_fx, shape1_den_coef_fx, ptr_fx, ptr_tmp_fx, hSC_VBR->shape1_filt_mem_fx, 10, 10, L_FRAME, 1);/*1 = (16-qformat of shape1 cofficient) */ + Copy(ptr_tmp_fx, ptr_fx, L_FRAME); + + qf = qGain; + move16(); + E2_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { + Ltemp = L_mult0(ptr_fx[i], ptr_fx[i]); /*Q(2*qE2+1) */ + Ltemp = L_shr_r(Ltemp, 4); + E2_fx = L_add(E2_fx, Ltemp); + } + qE2 = 2 * qf - 4; + move16(); + + test(); + IF(E1_fx == 0) + { + R_fx = 0; + move16(); + } + ELSE IF((E2_fx == 0) && (E1_fx != 0)) + { + exp1 = norm_l(E1_fx); + tmp1 = extract_h(L_shl(E1_fx, exp1));/*qE1+exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(qE1+exp1-16)-> 30-qE1-exp1 */ + exp1 = sub(exp1, 30 - qE1); + + L_tmp = L_deposit_h(tmp1); + L_tmp = Isqrt_lc(L_tmp, &exp1); + Ltemp = L_shl(L_tmp, sub(exp1, 12)); + R_fx = round_fx(Ltemp); + } + ELSE + { + exp1 = norm_l(E1_fx); + tmp1 = extract_h(L_shl(E1_fx, exp1));/*qE1+exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(qE1+exp1-16)-> 30-qE1-exp1 */ + L_tmp = Mult_32_16(E2_fx, tmp1);/*qE2+30-qE1-exp1-15=>15+qE2-qE1-exp1 */ + + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qE2-qE1-exp1+exp2 */ + exp2 = 30 - (15 + qE2 - qE1 - exp1 + exp2); + move16(); + L_tmp = Isqrt_lc(L_tmp, &exp2);/*Q(31+exp2) */ + R_fx = round_fx(L_tmp); + exp1 = 31 - exp2 - 16 - 7; + move16(); + } + + FOR(i = 0; i < L_FRAME; i++) + { + Ltemp = L_mult0(R_fx, ptr_fx[i]); + Ltemp = L_shr_r(Ltemp, exp1); + filtRes_fx[i] = round_fx(L_shl(Ltemp, 16)); + } + + qf1 = qGain; + move16(); + Scale_sig(hSC_VBR->txlpf1_filt2_mem_fx, 10, (qf1 - hSC_VBR->qprevGain_fx)); + + pz_filter_sp_fx(txlpf1_num_coef_fx, txlpf1_den_coef_fx, filtRes_fx, ptr_tmp_fx, hSC_VBR->txlpf1_filt2_mem_fx, 10, 10, L_FRAME, 3);/*1 = (16-qformat of shape1 cofficient) */ + Copy(ptr_tmp_fx, filtRes_fx, L_FRAME); + + qEL2 = qf1; + move16(); + EL2_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { + EL2_fx = L_mac0(EL2_fx, filtRes_fx[i], filtRes_fx[i]); /*Q(2*qEL2) */ + } + qEL2 = 2 * qEL2; + move16(); + + FOR(i = 0; i < L_FRAME; i++) + { + Ltemp = L_mult0(R_fx, ptr_fx[i]); + Ltemp = L_shr_r(Ltemp, exp1); + filtRes_fx[i] = round_fx(L_shl(Ltemp, 16)); + } + + qf = qGain; + move16(); + Scale_sig(hSC_VBR->txhpf1_filt2_mem_fx, 10, (qf - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(txhpf1_num_coef_fx, txhpf1_den_coef_fx, filtRes_fx, ptr_tmp_fx, hSC_VBR->txhpf1_filt2_mem_fx, 10, 10, L_FRAME, 3);/*1 = (16-qformat of shape1 cofficient) */ + + Copy(ptr_tmp_fx, filtRes_fx, L_FRAME); + + qEH2 = qf; + move16(); + EH2_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { + EH2_fx = L_mac0(EH2_fx, filtRes_fx[i], filtRes_fx[i]); /*Q(2*qEH2) */ + } + qEH2 = 2 * qEH2; + move16(); + IF(EL2_fx == 0) + { + exp2 = norm_l(EL1_fx); + L_tmp = L_shl(EL1_fx, exp2); + exp2 = 30 - exp2 - qEL1; + move16(); + tmp1 = Log2_norm_lc(L_tmp); + Ltemp = Mpy_32_16(exp2, tmp1, 9864); /*10*log(2) in Q15 format = Q0 format */ + tmp1 = round_fx(L_shl(Ltemp, 12));/* Q12 */ + RL_fx = L_mult0(tmp1, 10); + } + ELSE + { + exp1 = norm_l(EL2_fx); + tmp1 = extract_h(L_shl(EL2_fx, exp1));/*qEL2+exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(qEL2+exp1-16)-> 30-qEL2-exp1 */ + L_tmp = Mult_32_16(EL1_fx, tmp1);/*qEL1+30-qEL2-exp1-15=>15+qE1-qEL2-exp1 */ + + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qEL1-qEL2-exp1+exp2 */ + exp2 = 30 - (30 + qEL1 - qEL2 - exp1 + exp2); + move16(); + tmp1 = Log2_norm_lc(L_tmp); + Ltemp = Mpy_32_16(exp2, tmp1,9864); /*10*log(2) in Q15 format = Q0 format */ + tmp1 = round_fx(L_shl(Ltemp,12));/* Q12 */ + RL_fx = L_mult0(tmp1, 10); + } + + IF(EH2_fx == 0) + { + exp2 = norm_l(EH2_fx); + L_tmp = L_shl(EH2_fx, exp2); + exp2 = 30 - exp2 - qEH2; + move16(); + tmp1 = Log2_norm_lc(L_tmp); + Ltemp = Mpy_32_16(exp2, tmp1, 9864); /*10*log(2) in Q13 format = Q0 format */ + tmp1 = round_fx(L_shl(Ltemp, 12));/* Q12 */ + RH_fx = L_mult0(tmp1, 10); + } + ELSE + { + exp1 = norm_l(EH2_fx); + tmp1 = extract_h(L_shl(EH2_fx, exp1));/*qEH2+exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(qEH2+exp1-16)-> 30-qEH2-exp1 */ + L_tmp = Mult_32_16(EH1_fx, tmp1);/*15+qEH1-qEH2-exp1 */ + + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qEH1-qEH2-exp1+exp2 */ + exp2 = 30 - (30 + qEH1 - qEH2 - exp1 + exp2); + move16(); + tmp1 = Log2_norm_lc(L_tmp); + Ltemp = Mpy_32_16(exp2, tmp1,9864); /*10*log(2) in Q13 format = Q0 format */ + tmp1 = round_fx(L_shl(Ltemp,12));/* Q12 */ + RH_fx = L_mult0(tmp1, 10); + } + + fid = 0; + move16(); + IF(LT_32(RL_fx, -12288)) /* -3 in Q12 */ + { + fid = 1; + move16(); + } + ELSE IF(LT_32(RH_fx, -12288)) /* -3 in Q12 */ + { + fid = 2; + move16(); + } + + IF(rf_flag == 0) + { + + SWITCH(fid) + { + case 1: + /* Update other filter memory */ + Scale_sig(hSC_VBR->shape3_filt_mem_fx, 10, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(shape3_num_coef_fx, shape3_den_coef_fx, ptr_fx, filtRes_fx, hSC_VBR->shape3_filt_mem_fx, 10, 10, L_FRAME, 1);/*1 = (16-qformat of shape1 cofficient) */ + + /* filter the residual to desired shape */ + Scale_sig(hSC_VBR->shape2_filt_mem_fx, 10, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(shape2_num_coef_fx, shape2_den_coef_fx, ptr_fx, ptr_tmp_fx, hSC_VBR->shape2_filt_mem_fx, 10, 10, L_FRAME, 1);/*1 = (16-qformat of shape1 cofficient) */ + Copy(ptr_tmp_fx, ptr_fx, L_FRAME); + + BREAK; + case 2: + /* Update other filter memory */ + Scale_sig(hSC_VBR->shape2_filt_mem_fx, 10, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(shape2_num_coef_fx, shape2_den_coef_fx, ptr_fx, filtRes_fx, hSC_VBR->shape2_filt_mem_fx, 10, 10, L_FRAME, 1);/*1 = (16-qformat of shape1 cofficient) */ + + /* filter the residual to desired shape */ + Scale_sig(hSC_VBR->shape3_filt_mem_fx, 10, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(shape3_num_coef_fx, shape3_den_coef_fx, ptr_fx, ptr_tmp_fx, hSC_VBR->shape3_filt_mem_fx, 10, 10, L_FRAME, 1);/*1 = (16-qformat of shape1 cofficient) */ + + Copy(ptr_tmp_fx, ptr_fx, L_FRAME); + + BREAK; + default: + Scale_sig(hSC_VBR->shape2_filt_mem_fx, 10, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(shape2_num_coef_fx, shape2_den_coef_fx, ptr_fx, filtRes_fx, hSC_VBR->shape2_filt_mem_fx, 10, 10, L_FRAME, 1);/*1 = (16-qformat of shape1 cofficient) */ + + Scale_sig(hSC_VBR->shape3_filt_mem_fx, 10, (qGain - hSC_VBR->qprevGain_fx)); + pz_filter_sp_fx(shape3_num_coef_fx, shape3_den_coef_fx, ptr_fx, filtRes_fx, hSC_VBR->shape3_filt_mem_fx, 10, 10, L_FRAME, 1);/*1 = (16-qformat of shape1 cofficient) */ + + BREAK; + } + + qE2 = qGain; + move16(); + + E2_fx = L_deposit_l(0); + FOR(i = 0; i < L_FRAME; i++) + { + Ltemp = L_mult0(ptr_fx[i], ptr_fx[i]); /*Q(2*qE2+1) */ + Ltemp = L_shr_r(Ltemp, 4); + E2_fx = L_add(E2_fx, Ltemp); + } + qE2 = (2 * qE2) - 4; + move16(); + test(); + IF(E3_fx == 0) + { + R_fx = 0; + move16(); + } + ELSE IF((E2_fx == 0) && (E3_fx != 0)) + { + exp1 = norm_l(E3_fx); + tmp1 = extract_h(L_shl(E3_fx, exp1));/*qE3+exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(qE3+exp1-16)-> 30-qE3-exp1 */ + exp1 = sub(exp1, 30 - qE3); + + L_tmp = L_deposit_h(tmp1); + L_tmp = Isqrt_lc(L_tmp, &exp1); + Ltemp = L_shl(L_tmp, sub(exp1, 12)); + R_fx = round_fx(Ltemp); + } + ELSE + { + exp1 = norm_l(E3_fx); + tmp1 = extract_h(L_shl(E3_fx, exp1));/*qE3+exp1-16 */ + tmp1 = div_s(16384, tmp1);/*14-(qE3+exp1-16)-> 30-qE3-exp1 */ + L_tmp = Mult_32_16(E2_fx, tmp1);/*qE2+30-qE3-exp1-15=>15+qE2-qE3-exp1 */ + + exp2 = norm_l(L_tmp); + L_tmp = L_shl(L_tmp, exp2);/*15+qE2-qE3-exp1+exp2 */ + exp2 = 30 - (15 + qE2 - qE3 - exp1 + exp2); + move16(); + L_tmp = Isqrt_lc(L_tmp, &exp2);/*Q(31+exp2) */ + R_fx = round_fx(L_tmp); + exp1 = 31 - exp2 - 16 - 7; + move16(); + } + + FOR(i = 0; i < L_FRAME; i++) + { + L_tmp = L_mult0(R_fx, ptr_fx[i]); + L_tmp = L_shr_r(L_tmp, exp1 + 1); + ptr_fx[i] = round_fx(L_shl(L_tmp, 16)); + } + *qIn1 = qGain - 1; + move16(); + } + + IF(EQ_16(rf_flag, 1)) + { + hRF->rf_indx_nelp_fid[0] = fid; + move16(); + } + ELSE + { + push_indice_fx(hBstr, IND_NELP_FID, fid, 2); + } + } + + hSC_VBR->qprevGain_fx = qGain; + move16(); + + IF(rf_flag == 0) + { + FOR(i = 0; i < L_FRAME; i++) + { + exc_fx[i] = ptr_fx[i]; + move16(); + } + } + + return; +} + + diff --git a/lib_enc/stat_enc.h b/lib_enc/stat_enc.h index 4ce027a19..97411839c 100644 --- a/lib_enc/stat_enc.h +++ b/lib_enc/stat_enc.h @@ -977,6 +977,9 @@ typedef struct sc_vbr_enc_structure int16_t last_nelp_mode; int16_t nelp_mode; + Word16 qprevIn_fx; + Word16 qprevGain_fx; + /* PPP variables */ int16_t pppcountE; int16_t bump_up; diff --git a/lib_enc/swb_bwe_enc_lr_fx.c b/lib_enc/swb_bwe_enc_lr_fx.c new file mode 100644 index 000000000..4088bb500 --- /dev/null +++ b/lib_enc/swb_bwe_enc_lr_fx.c @@ -0,0 +1,1128 @@ +/****************************************************************************************************** + + (C) 2022-2023 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository. All Rights Reserved. + + This software is protected by copyright law and by international treaties. + The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB, + Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD., + Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange, + Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other + contributors to this repository retain full ownership rights in their respective contributions in + the software. This notice grants no license of any kind, including but not limited to patent + license, nor is any license granted by implication, estoppel or otherwise. + + Contributors are required to enter into the IVAS codec Public Collaboration agreement before making + contributions. + + This software is provided "AS IS", without any express or implied warranties. The software is in the + development stage. It is intended exclusively for experts who have experience with such software and + solely for the purpose of inspection. All implied warranties of non-infringement, merchantability + and fitness for a particular purpose are hereby disclaimed and excluded. + + Any dispute, controversy or claim arising under or in relation to providing this software shall be + submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in + accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and + the United Nations Convention on Contracts on the International Sales of Goods. + +*******************************************************************************************************/ + +#include +#include "options.h" +#include "prot_fx2.h" +#include "rom_com.h" +#include "enh32.h" + + /*--------------------------------------------------------------------------* + * GetSubbandCorrIndex2_har() + * + * Finds the index of best correlation between highband (*inBuf) and lowband (*predBuf) for current subband of length (fLen) + *--------------------------------------------------------------------------*/ +static +Word16 GetSubbandCorrIndex2_har_fx( /* o : best correlation index */ + const Word32 *L_inBuf, /* i : target buffer (i.e., highband signal) : spectra */ + const Word16 fLen, /* i : window length */ + const Word16 *predBuf_fx, /* i : prediction buffer (i.e., lowband) : sspectra */ + const Word16 predBufLen, /* i : sspectra buffer size */ + const Word16 maxLag_fx, /* i : search length */ + const GainItem_fx *G_item_fx, /* i : */ + const Word16 nZero_fx, /* i : number of nonzero components used in */ + Word16 *prev_frame_bstindx_fx /* i : previous frame best Indices */ +) +{ + Word16 i, j; + Word16 bestIdx_fx; + Word32 L_lagCorr_sq; + Word32 L_lagEnergy; + + Word32 L_energy; + Word32 L_corr; + Word32 L_corr_sq; + + Word16 corr_sq_hi_fx; + Word32 L_corr_sq_tmp; + Word32 L_lagCorr_sq_tmp; + Word16 corr_sq_fx; + Word16 lagCorr_sq_fx; + Word32 L_energy_tmp; + Word32 L_lagEnergy_tmp; + Word16 energy_fx; + Word16 lagEnergy_fx; + + Word16 N1_fx, N2_fx; + Word16 exp_safe_e; + + Word16 exp_corr; + Word16 exp_energy; + + Word32 L_buf; + + Word16 ibuf_fx[L_FRAME32k]; + Word16 pbuf_fx[L_FRAME32k]; + Word16 *ptr_pbuf; + Word16 exp_shift; + + Word16 exp_norm; + + Word32 L_tmp; + +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + exp_safe_e = 4; + + L_tmp = L_deposit_l(0); + FOR(i = 0; i < fLen; i++) + { + L_tmp = L_or(L_tmp, L_abs(L_inBuf[i])); + } + exp_norm = norm_l(L_tmp); + exp_shift = sub(exp_norm, exp_safe_e); + + FOR(i = 0; i < fLen; i++) + { + ibuf_fx[i] = extract_h(L_shl(L_inBuf[i], exp_shift)); /* Qi+exp_shift-16 */ + } + + FOR(i = 0; i < predBufLen; i++) + { + pbuf_fx[i] = shr(predBuf_fx[i], exp_safe_e); + move16(); /* Qss-exp_safe_e */ + } + + bestIdx_fx = 0; + move16(); + L_lagCorr_sq = L_deposit_l(0); + L_lagEnergy = 0x7FFFFFFF; + move32(); + + N1_fx = s_max(0x0, sub(*prev_frame_bstindx_fx, shr(maxLag_fx, 1))); + IF(*prev_frame_bstindx_fx < 0) + { + N2_fx = sub(maxLag_fx, 1); + } + ELSE + { + N2_fx = s_min(sub(maxLag_fx, 1), add(*prev_frame_bstindx_fx, shr(maxLag_fx,1))); + } + predBuf_fx += N1_fx; + ptr_pbuf = pbuf_fx + N1_fx; + + + Overflow = 0; + move16(); + + /* find the best lag */ + FOR(i = N1_fx; i <= N2_fx; i++) + { + L_corr = L_deposit_l(0); + + /* get the energy, remove the old and update with the new energy index */ + + L_energy = L_deposit_l(0); + FOR(j = 0; j < fLen; j++) + { + /*energy += *predBuf * *predBuf; */ +#ifdef BASOP_NOGLOB /* Critical Overflow , as well as those below*/ + L_energy = L_mac_o(L_energy, *ptr_pbuf, *ptr_pbuf, &Overflow); /* Q*2-1; */ +#else + L_energy = L_mac(L_energy, *ptr_pbuf, *ptr_pbuf); /* Q*2-1; */ +#endif + ptr_pbuf++; + } + + ptr_pbuf -= fLen; + + /* get cross-correlation */ + IF(L_energy != 0x0L) + { + L_corr = L_deposit_l(0); + FOR(j = 0; j < nZero_fx; j++) + { + /*corr += inBuf[G_item[j].gainIndex]* predBuf[G_item[j].gainIndex]; */ +#ifdef BASOP_NOGLOB /* Critical Overflow */ + L_corr = L_mac_o(L_corr, ibuf_fx[G_item_fx[j].gainIndex_fx], ptr_pbuf[G_item_fx[j].gainIndex_fx], &Overflow); /* Q*2-1 */ +#else + L_corr = L_mac(L_corr, ibuf_fx[G_item_fx[j].gainIndex_fx], ptr_pbuf[G_item_fx[j].gainIndex_fx]); /* Q*2-1 */ +#endif + } + + /*corr_sq = corr*corr; */ + exp_norm = norm_l(L_corr); + exp_norm = sub(exp_norm, 1); /* added for Overflow 0x8000 * 0x8000 -> Overflow */ + L_corr_sq = L_shl(L_corr, exp_norm); + corr_sq_hi_fx = extract_h(L_corr_sq); + +#ifdef BASOP_NOGLOB /* Critical Overflow */ + L_corr_sq = L_mult_o(corr_sq_hi_fx, corr_sq_hi_fx, &Overflow); /* (((Qhi:Qsh+exp_norm_hi-16)+Qss+1)+exp_norm-16)*2+1 */ + L_corr_sq = L_shr_o(L_corr_sq, s_min(shl(exp_norm, 1), 31), &Overflow); /* (QCorr-16)*2+1 */ +#else + L_corr_sq = L_mult(corr_sq_hi_fx, corr_sq_hi_fx); /* (((Qhi:Qsh+exp_norm_hi-16)+Qss+1)+exp_norm-16)*2+1 */ + L_corr_sq = L_shr(L_corr_sq, s_min(shl(exp_norm, 1), 31)); /* (QCorr-16)*2+1 */ +#endif + IF(Overflow != 0) + { + L_corr_sq = 0x0L; + move16(); + Overflow = 0; + move16(); + } + + /* normalize for L_lagCorr_sq and L_corr_sq */ + L_buf = L_or(L_lagCorr_sq, L_corr_sq); + exp_corr = norm_l(L_buf); + L_corr_sq_tmp = L_shl(L_corr_sq, exp_corr); + L_lagCorr_sq_tmp = L_shl(L_lagCorr_sq, exp_corr); + corr_sq_fx = extract_h(L_corr_sq_tmp); + lagCorr_sq_fx = extract_h(L_lagCorr_sq_tmp); + + /* normalize for L_lagEnergy and L_energy */ + L_buf = L_or(L_lagEnergy, L_energy); + exp_energy = norm_l(L_buf); + L_energy_tmp = L_shl(L_energy, exp_energy); + L_lagEnergy_tmp = L_shl(L_lagEnergy, exp_energy); + energy_fx = extract_h(L_energy_tmp); + lagEnergy_fx = extract_h(L_lagEnergy_tmp); + + /*if( (double)lagCorr_sq*(double)energy < (double)corr_sq*(double)lagEnergy ) */ + IF(L_msu(L_mult(lagCorr_sq_fx, energy_fx), corr_sq_fx, lagEnergy_fx) < 0) + { + bestIdx_fx = i; + move16(); + L_lagCorr_sq = L_add(L_corr_sq, 0); + L_lagEnergy = L_add(L_energy, 0); + } + + } + predBuf_fx++; + ptr_pbuf++; + } + + test(); + IF(L_lagCorr_sq == 0x0 && *prev_frame_bstindx_fx < 0) + { + bestIdx_fx = 0x0; + move16(); + } + ELSE + { + if (L_lagCorr_sq == 0x0) + { + bestIdx_fx = *prev_frame_bstindx_fx; + move16(); + } + } + + *prev_frame_bstindx_fx = bestIdx_fx; + move16(); + + return bestIdx_fx; +} + +/*--------------------------------------------------------------------------* + * getswbindices_har() + * + * Finds the pulse index of best correlation between highband (*yos) and lowband (*y2) for two groups of length sbLen + *--------------------------------------------------------------------------*/ + +static void getswbindices_har_fx( + const Word32 *L_yos, /* i : original input spectrum */ + Word16 exp_refBuf, /* i : */ + Word16 *y2_fx, /* i : decoded spectrum */ + const Word16 nBands_search_fx, /* i : number of bands */ + Word16 *lagIndices_fx, /* o : pulse index */ + Word16 *prev_frame_bstindx_fx, /* i/o: prev frame index */ + const Word16 swb_lowband_fx, /* i : length of the LF spectrum */ + const Word16 *subband_offsets_fx, /* i : */ + const Word16 *sbWidth_fx, /* i : */ + const Word16 *subband_search_offset_fx /* i : */ +) +{ + Word16 i, j, k, sb, tmp; + Word16 *ptr_predBuf; + GainItem_fx Nbiggest_fx[(NB_SWB_SUBBANDS_HAR_SEARCH_SB)*N_NBIGGEST_PULSEARCH]; + Word16 n_nbiggestsearch_fx[NB_SWB_SUBBANDS_HAR]; + + Word16 search_offset_fx[NB_SWB_SUBBANDS_HAR_SEARCH_SB]; + Word16 nlags_fx[NB_SWB_SUBBANDS_HAR_SEARCH_SB]; + + Word16 low_freqsgnl_fx[L_FRAME32k]; /* Qy2 (sspectra) */ + + ptr_predBuf = y2_fx; + + /* Get the number of HF groups for performing Similarity search */ + FOR(sb = 0; sb < nBands_search_fx; sb++) + { + /*nlags[sb] = (short)pow(2, bits_lagIndices_mode0_Har[sb]); */ + nlags_fx[sb] = shl(1, bits_lagIndices_mode0_Har[sb]); + } + + j = 0; + move16(); + FOR(sb = 0; sb < nBands_search_fx; sb++) + { + /* Find NBiggest samples in HF Groups */ + FindNBiggest2_simple_fx_har(L_yos + add(swb_lowband_fx, subband_offsets_fx[sb]), exp_refBuf, Nbiggest_fx + j, + sbWidth_fx[sb], &n_nbiggestsearch_fx[sb], N_NBIGGEST_PULSEARCH); + + search_offset_fx[sb] = subband_search_offset_fx[sb]; + j = add(j, N_NBIGGEST_PULSEARCH); + } + + /* Similarity Search for the HF spectrum */ + FOR(sb = 0; sb < nBands_search_fx; sb++) + { + IF(sb == 0) + { + /* copy SSmoothed LF Spectrum */ + ptr_predBuf = y2_fx + sub(search_offset_fx[sb], shr(nlags_fx[sb], 1)); + tmp = add(sbWidth_fx[sb], nlags_fx[sb]); + FOR(i = 0; i < tmp; i++) + { + low_freqsgnl_fx[i] = *ptr_predBuf++; + move16(); + } + } + ELSE + { + /* copy SSmoothed LF Spectrum */ + k = 0; + move16(); + tmp = sub(search_offset_fx[sb], add(sbWidth_fx[sb], shr(nlags_fx[sb], 1))); + FOR(j = add(search_offset_fx[sb], shr(nlags_fx[sb], 1)); j > tmp; j--) + { + low_freqsgnl_fx[k] = y2_fx[j]; + k = add(k, 1); + } + } + /* correlation b/w HF spectrum Group1 of length sbLen and decoded LF spectrum */ + lagIndices_fx[sb] = (Word16)GetSubbandCorrIndex2_har_fx(L_yos + add(swb_lowband_fx, subband_offsets_fx[sb]), + sbWidth_fx[sb], + low_freqsgnl_fx, + add(sbWidth_fx[sb], nlags_fx[sb]), + nlags_fx[sb], Nbiggest_fx + (sb*N_NBIGGEST_PULSEARCH), + n_nbiggestsearch_fx[sb], &prev_frame_bstindx_fx[sb] + ); + } + + return; +} +/*--------------------------------------------------------------------------* + * GetSubbandCorrIndex2_pulsestep_fx() + * + *--------------------------------------------------------------------------*/ + +static Word16 GetSubbandCorrIndex2_pulsestep_fx( + const Word32 *L_inBuf, /* i: original input vector (highband) */ + const Word16 *predBuf_fx, /* i: spectrum smoothing vector */ + const Word16 *predBufMa_fx, /* i: moving averaged spectrum smoothing vector Q=Qss */ + const Word16 fLen, /* i: subband length of highband */ + const Word16 maxLag, /* i: number of search pulse number */ + const GainItem_fx *gi_fx, /* i: lag gain structure */ + const Word16 nZero, /* i: */ + const Word16 ssearch_buflim, /* i: length of search buffer */ + const Word16 *predBuf_ni_fx /* i: spectrum including noise smoothing vector */ +) +{ + Word16 i, j; + Word16 absPos_fx; + Word16 bestIdx_fx; + Word32 L_lagCorr_sq; + Word32 L_lagEnergy; + + const Word16 *ptr_predBuf; + const Word16 *ptr_predBuf_ni; + + Word32 L_energy; + Word32 L_corr; + Word16 corr_fx; + + Word32 L_corr_sq; + + + Word16 hiBuf_fx[L_FRAME32k]; + Word16 exp_norm_hi; + + Word16 exp_norm; + Word32 L_corr_sq_tmp; + Word32 L_lagCorr_sq_tmp; + Word16 corr_sq_fx; + Word16 lagCorr_sq_fx; + Word32 L_energy_tmp; + Word32 L_lagEnergy_tmp; + Word16 energy_fx; + Word16 lagEnergy_fx; + + Word16 ib_flag_fx; + + Word32 L_buf; + Word32 L_buf2; + Word32 L_temp; + + Word16 ssBuf_fx[L_FRAME32k]; + Word16 ssBuf_ni_fx[L_FRAME32k]; + Word16 *ptr_ssBuf_ni_fx; + Word16 exp_norm_ss; + + set16_fx(hiBuf_fx, 0x0, L_FRAME32k); + set16_fx(ssBuf_fx, 0x0, L_FRAME32k); + + ib_flag_fx = 0; + move16(); + + absPos_fx = 0; + move16(); + bestIdx_fx = -1; + move16(); + L_lagCorr_sq = L_deposit_l(0); + L_lagEnergy = 0x7FFFFFFFL; + move32(); + + ptr_predBuf = predBuf_fx; + ptr_predBuf_ni = predBuf_ni_fx; + + /* This part must be computed on parent function. */ + exp_norm_ss = 2; + move16(); + + j = add(ssearch_buflim, fLen); + FOR(i = 0; i < j; i++) + { + ssBuf_fx[i] = shr(predBuf_fx[i], exp_norm_ss); + move16(); /* Qss+exp_norm_ss */ + ssBuf_ni_fx[i] = shr(predBuf_ni_fx[i], exp_norm_ss); + move16(); /* Qss+exp_norm_ss */ + } + + L_temp = L_deposit_l(0); + FOR(i = 0; i < fLen; i++) + { + L_temp = L_or(L_temp, L_abs(L_inBuf[i])); + } + exp_norm_hi = norm_l(L_temp); + exp_norm_hi = sub(exp_norm_hi, 3); /* max 109 < 2^7 , sspectrum is sparse, it is't need 4 */ + + FOR(i = 0; i < fLen; i++) + { + hiBuf_fx[i] = extract_h(L_shl(L_inBuf[i], exp_norm_hi)); + move16(); /* Qsh+exp_norm_hi-16 */ + } + + /* Get the initial energy for zero lag */ + WHILE(*ptr_predBuf == 0 && LT_16(absPos_fx, ssearch_buflim)) + { + ptr_predBuf++; + ptr_predBuf_ni++; + absPos_fx = add(absPos_fx, 1); + } + + IF(EQ_16(absPos_fx, ssearch_buflim)) + { + ptr_predBuf--; + ptr_predBuf_ni--; + absPos_fx = sub(absPos_fx, 1); + } + + ptr_ssBuf_ni_fx = ssBuf_ni_fx + absPos_fx; + L_energy = L_deposit_l(0); + FOR(i = 0; i < fLen; i++) + { + L_energy = L_mac(L_energy, *ptr_ssBuf_ni_fx, *ptr_ssBuf_ni_fx); /* (Qss-exp_norm_ss)*2+1 */ + ptr_ssBuf_ni_fx++; + ptr_predBuf_ni++; + } + + ptr_ssBuf_ni_fx -= fLen; + ptr_predBuf_ni -= fLen; + + L_lagEnergy = L_add(L_energy, 0); + + /* Find the best lag */ + FOR(i = 0; i < maxLag; i++) + { + L_corr = L_deposit_l(0); + + /* Get the energy, remove the old and update with the new energy index */ + L_energy = L_deposit_l(0); + FOR(j = 0; j < fLen; j++) + { + L_energy = L_mac(L_energy, *ptr_ssBuf_ni_fx, *ptr_ssBuf_ni_fx); + ptr_ssBuf_ni_fx++; + ptr_predBuf_ni++; + } + ptr_ssBuf_ni_fx -= fLen; + ptr_predBuf_ni -= fLen; + + /* Get cross-correlation */ + IF(L_energy != 0x0L) + { + L_corr = L_deposit_l(0); + FOR(j = 0; j < nZero; j++) + { + /*corr += inBuf[G_item[j].gainIndex]* predBufMa[G_item[j].gainIndex]; */ + L_corr = L_mac(L_corr, hiBuf_fx[gi_fx[j].gainIndex_fx], predBufMa_fx[gi_fx[j].gainIndex_fx]); /* Qsh+Qss+1 */ + } + + /*corr_sq = corr*corr; */ + exp_norm = norm_l(L_corr); + exp_norm = sub(exp_norm, 1); /* added for Overflow 0x8000 * 0x8000 -> Overflow */ + L_corr_sq = L_shl(L_corr, exp_norm); + corr_fx = extract_h(L_corr_sq); + L_corr_sq = L_mult(corr_fx, corr_fx); /* (((Qhi:Qsh+exp_norm_hi-16)+Qss+1)+exp_norm-16)*2+1 */ + L_corr_sq = L_shr(L_corr_sq, s_min(shl(exp_norm, 1), 31)); /* (QCorr-16)*2+1 */ + + /*if( (lagCorr_sq == 0.0f && corr_sq == 0.0f) || (double)lagCorr_sq*(double)energy < (double)corr_sq*(double)lagEnergy ) */ + /*{ */ + /* bestIdx = i; */ + /* bestAbsPos = absPos; */ + /* lagCorr_sq = corr_sq; */ + /* lagCorr = corr; */ + /* lagEnergy = energy; */ + /*} */ + /* normalize for L_lagCorr_sq and L_corr_sq */ + L_buf = L_or(L_lagCorr_sq, L_corr_sq); + exp_norm = norm_l(L_buf); /* overflow allowed */ + L_corr_sq_tmp = L_shl(L_corr_sq, exp_norm); + L_lagCorr_sq_tmp = L_shl(L_lagCorr_sq, exp_norm); + corr_sq_fx = extract_h(L_corr_sq_tmp); + lagCorr_sq_fx = extract_h(L_lagCorr_sq_tmp); + + /* normalize for L_lagEnergy and L_energy */ + L_buf = L_or(L_lagEnergy, L_energy); + exp_norm = norm_l(L_buf); /* overflow allowed */ + L_energy_tmp = L_shl(L_energy, exp_norm); + L_lagEnergy_tmp = L_shl(L_lagEnergy, exp_norm); + energy_fx = extract_h(L_energy_tmp); + lagEnergy_fx = extract_h(L_lagEnergy_tmp); + + L_buf = L_or(L_lagCorr_sq, L_corr_sq); + L_buf2 = L_msu(L_mult(lagCorr_sq_fx, energy_fx), corr_sq_fx, lagEnergy_fx); + test(); + IF(L_buf == 0 || L_buf2 < 0) + { + bestIdx_fx = i; + move16(); + L_lagCorr_sq = L_add(L_corr_sq, 0); + L_lagEnergy = L_add(L_energy, 0); + } + } + ptr_predBuf++; + ptr_ssBuf_ni_fx++; + ptr_predBuf_ni++; + absPos_fx++; + + WHILE(*ptr_predBuf == 0 && LT_16(absPos_fx, ssearch_buflim)) + { + ptr_predBuf++; + ptr_ssBuf_ni_fx++; + ptr_predBuf_ni++; + absPos_fx = add(absPos_fx, 1); + } + + IF(GE_16(absPos_fx, ssearch_buflim)) + { + if (EQ_16(bestIdx_fx, -1)) + { + ib_flag_fx = 1; + move16(); + } + + BREAK; + } + } + + IF(EQ_16(ib_flag_fx, 1)) + { + bestIdx_fx = 0; + move16(); + } + + return bestIdx_fx; +} +/*--------------------------------------------------------------------------* + * GetSWBIndices_fx() + * + *--------------------------------------------------------------------------*/ +static void GetSWBIndices_fx( + const Word16 *predBuf_fx, /* i : low-frequency band */ + /*const Word16 Qss,*/ /* i : Q value of predBuf_fx */ + const Word32 *L_targetBuf, /* i : SWB MDCT coeff. */ + const Word16 Qsh, /* i : Q value of L_targetBuf */ + const Word16 nBands_search, /* i : number of search subbands */ + const Word16 *sbWidth, /* i : subband lengths */ + Word16 *lagIndices, /* o : selected lags for subband coding */ + const Word16 predBufLen, /* i : low-frequency band length */ + GainItem_fx *gi_fx, /* o : most representative region */ + const Word16 *subband_offsets, /* o : N biggest components */ + Word16 *predBuf_ni_fx /* i : low-frequency band filled noise */ +) +{ + Word16 j; + Word16 sb, tmp; + Word16 sbLen; + Word16 n_nbiggestsearch_fx[NB_SWB_SUBBANDS]; + Word16 ssearch_buflim_fx; + Word16 search_offset_fx[NB_SWB_SUBBANDS]; + Word16 nlags_fx[NB_SWB_SUBBANDS]; + + Word16 exp_refBuf; + Word16 sspectra_ma_fx[L_FRAME32k]; + + + Word32 L_temp; + + + /* Initializations */ + exp_refBuf = Qsh; + + j = 0; + move16(); + FOR(sb = 0; sb < nBands_search; sb++) + { + FindNBiggest2_simple_fx_har(L_targetBuf + subband_offsets[sb], exp_refBuf, gi_fx + j, sbWidth[sb], &n_nbiggestsearch_fx[sb], N_NBIGGEST_PULSEARCH); + + j = add(j, N_NBIGGEST_PULSEARCH); + move16(); + } + + /* Selection of most representative subband (full search) */ + FOR(sb = 0; sb < nBands_search; sb++) + { + nlags_fx[sb] = shl(1, bits_lagIndices_modeNormal[sb]); + move16(); + } + + FOR(sb = 0; sb < nBands_search; sb++) + { + search_offset_fx[sb] = subband_search_offsets[sb]; + move16(); + } + + sspectra_ma_fx[0] = add(shr(predBuf_ni_fx[0], 1), shr(predBuf_ni_fx[1], 1)); + tmp = sub(predBufLen, 1); + FOR(sb = 1; sb < tmp; sb++) + { + /*sspectra_ma[sb] = (predBuf[sb-1] + predBuf[sb] + predBuf[sb+1])/3.0f; */ + L_temp = L_mult(predBuf_ni_fx[sb], 10922); /* 10922 = 0.33333 (Q15) */ + L_temp = L_add(L_temp, L_mult(predBuf_ni_fx[sb - 1], 10922)); + L_temp = L_add(L_temp, L_mult(predBuf_ni_fx[sb + 1], 10922)); /* Qss+15+1 */ + sspectra_ma_fx[sb] = round_fx(L_temp); + } + sspectra_ma_fx[sb] = add(shr(predBuf_ni_fx[sb - 1], 1), shr(predBuf_ni_fx[sb], 1)); + + /* Partial search for rest of subbands except the last which is fixed */ + FOR(sb = 0; sb < nBands_search; sb++) + { + sbLen = sbWidth[sb]; + ssearch_buflim_fx = sub(predBufLen, add(sbLen, search_offset_fx[sb])); + lagIndices[sb] = GetSubbandCorrIndex2_pulsestep_fx( + L_targetBuf + subband_offsets[sb], + predBuf_fx + search_offset_fx[sb], + sspectra_ma_fx + search_offset_fx[sb], + sbLen, nlags_fx[sb], gi_fx + (sb*N_NBIGGEST_PULSEARCH), + n_nbiggestsearch_fx[sb], + ssearch_buflim_fx, predBuf_ni_fx + search_offset_fx[sb]); + } + +} +/*--------------------------------------------------------------------------* + * gethar_noisegn_fx() + * + *--------------------------------------------------------------------------*/ + +static void gethar_noisegn_fx( + BSTR_ENC_HANDLE hBstr, /* i/o: bitstream handle */ + const Word32 L_spectra[], /* i : Qs input MDCT */ + const Word16 QsL, /* i : Q0 Q value for L_spectra, L_xSynth_har */ + const Word16 noise_flr_fx[], /* i : Qss noise floor */ + const Word16 Qss, /* i : Q0 Q value for noise_flr_fx, sspectra */ + Word32 L_xSynth_har[], /* o : Qs output SWB MDCT */ + const Word16 sbWidth[], /* i : Q0 band width for SWB */ + const Word16 lagIndices[], /* i : Q0 lag Indices */ + const Word16 bands, /* i : Q0 all band number */ + const Word16 har_bands, /* i : Q0 harmonic band number */ + const Word16 fLenLow, /* i : Q0 low frequency band width */ + const Word16 fLenHigh, /* i : Q0 SWB band width */ + const Word16 subband_offsets[], /* i : Q0 offset */ + const Word16 subband_search_offset[], /* i : Q0 offset */ + const Word16 band_start[], /* i : Q0 band start array */ + const Word16 band_end[], /* i : Q0 band end array */ + const Word16 band_width[], /* i : Q0 band width */ + Word32 L_band_energy[], /* i : Qbe band energy (Log scale) */ + const Word16 Qbe, /* i : Q0 Q value for L_band_energy */ + Word32 L_be_tonal[], /* o : QbeL tonal energy */ + Word16 *QbeL, /* o : Q0 Q value for L_be_tonal */ + const Word16 *sspectra_fx, /* i : Qss smoothed spectrum */ + const Word16 har_freq_est2, /* i : Q0 for harmonic structure */ + const Word16 pos_max_hfe2, /* i/o : Q0 for harmonic structure */ + Word16 *pul_res_fx, /* o : Q0 */ + GainItem_fx pk_sf_fx[] /* o : */ +) +{ + Word16 i; + + Word32 L_xSynth_har_sft[L_FRAME32k]; + Word32 L_hfspec_sft[L_FRAME32k]; + + Word32 L_hfspec[L_FRAME32k]; + + GainItem_fx get_pk_fx[N_NBIGGEST_SEARCH_LRG_B]; + Word16 n_nbiggestsearch_fx, imin_fx, gqlevs_fx; + + Word32 L_g1, L_g2; + Word16 exp_safe; + Word32 L_temp; + + Word16 exp_normn, exp_normd; + Word16 temp_fx; + Word16 div_fx; + + Word16 exp_norm_g1, exp_norm_g2; + Word16 sqrt_fx, Qsqrt; + Word16 g_fx; + Word16 exp, frac; + + Word16 dmin_fx, d_fx; + + Word16 temp_lo, temp_hi; + Word16 Qg; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + /*Generate HF noise*/ + genhf_noise_fx(noise_flr_fx, Qss, L_xSynth_har, QsL, sspectra_fx, bands, har_bands, har_freq_est2, pos_max_hfe2, pul_res_fx, pk_sf_fx, fLenLow, + fLenHigh, sbWidth, lagIndices, subband_offsets, subband_search_offset); + + Copy32(&L_spectra[fLenLow], L_hfspec, fLenHigh); + FindNBiggest2_simple_fx_har(L_hfspec, QsL, get_pk_fx, fLenHigh, &n_nbiggestsearch_fx, N_NBIGGEST_SEARCH_LRG_B); + FOR(i = 0; i < n_nbiggestsearch_fx; i++) + { + L_hfspec[get_pk_fx[i].gainIndex_fx] = 0x0; + move16(); + } + + L_temp = 0x0; + FOR(i = 0; i < fLenHigh; i++) + { + L_temp = L_or(L_temp, L_abs(L_hfspec[i])); + } + exp_norm_g1 = norm_l(L_temp); + FOR(i = 0; i < fLenHigh; i++) + { + L_hfspec_sft[i] = L_shl(L_hfspec[i], exp_norm_g1); + } + + L_temp = 0x0; + FOR(i = 0; i < fLenHigh; i++) + { + L_temp = L_or(L_temp, L_abs(L_xSynth_har[i])); + } + exp_norm_g2 = norm_l(L_temp); + FOR(i = 0; i < fLenHigh; i++) + { + L_xSynth_har_sft[i] = L_shl(L_xSynth_har[i], exp_norm_g2); + } + + exp_safe = 4; + move16(); + L_g1 = L_deposit_l(0); + L_g2 = L_deposit_l(0); + FOR(i = 0; i < fLenHigh; i++) + { + temp_fx = round_fx(L_shr(L_hfspec_sft[i], exp_safe)); + L_g1 = L_mac(L_g1, temp_fx, temp_fx); /* 4: safe shift */ + temp_fx = round_fx(L_shr(L_xSynth_har_sft[i], exp_safe)); + L_g2 = L_mac(L_g2, temp_fx, temp_fx); /* 4: safe shift */ + } + + /*g = (float) log10(sqrt(g1/g2));*/ + /* Div Part */ + exp_normn = norm_l(L_g1); + exp_normn = sub(exp_normn, 1); + exp_normd = norm_l(L_g2); + temp_fx = extract_h(L_shl(L_g2, exp_normd)); + exp_normd = sub(exp_normd, 16); + + imin_fx = 0; + move16(); + test(); + IF(L_g1 != 0 && temp_fx != 0x0) + { + div_fx = div_l(L_shl(L_g1, exp_normn), temp_fx); + /* SQRT Part */ + sqrt_32n_16_fx(L_deposit_h(div_fx), add(add(sub(exp_normn, exp_normd), shl(sub(exp_norm_g1, exp_norm_g2), 1)), 15), &sqrt_fx, &Qsqrt); /* (exp_normn-exp_normd+(exp_norm_g1-exp_norm_g2)*2 -1)+16 */ + + /* Log10 Part */ + g_fx = 0x0; + move16(); + IF(sqrt_fx > 0x0) + { + L_temp = L_deposit_l(sqrt_fx); + + exp = norm_l(L_temp); + frac = Log2_norm_lc(L_shl(L_temp, exp)); + exp = sub(30, exp); + exp = sub(exp, Qsqrt); + L_temp = L_Comp(exp, frac); + + L_temp = Mpy_32_16_1(L_temp, 19728); /* log(2)/log(10)=.30102999566398119521 = 19728.3(Q16) Q(0+16+1)=Q17 */ +#ifdef BASOP_NOGLOB + L_temp = L_shl_o(L_temp, 13, &Overflow); /* Q17+13=30 30-16=14 */ + g_fx = round_fx_o(L_temp, &Overflow); +#else + L_temp = L_shl(L_temp, 13); /* Q17+13=30 30-16=14 */ + g_fx = round_fx(L_temp); +#endif + } + + gqlevs_fx = 4; + move16(); + dmin_fx = 32767; + move16(); + imin_fx = 0; + move16(); + + FOR(i = 0; i < gqlevs_fx; i++) + { + d_fx = abs_s(g_fx - gain_table_SWB_BWE_fx[i]); + IF(LT_16(d_fx, dmin_fx)) + { + dmin_fx = d_fx; + move16(); + imin_fx = i; + move16(); + } + } + } + + push_indice_fx(hBstr, IND_NOISEG, imin_fx, 2); + + /*g=(float) pow (10.0f,gain_table[imin]);*/ + L_temp = L_mult(gain_table_SWB_BWE_fx[imin_fx], 27213); /* Q14+Q13+1=Q28 log(10)/log(2)=3.3219 27213.23(Q13) */ + L_temp = L_shr(L_temp, 12); /* Q28-Q12 -> Q16 */ + temp_lo = L_Extract_lc(L_temp, &temp_hi); + Qg = sub(14, temp_hi); + g_fx = extract_l(Pow2(14, temp_lo)); + g_fx = shl(g_fx, sub(11, Qg)); + + ton_ene_est_fx( + L_xSynth_har, QsL, L_be_tonal, QbeL, L_band_energy, Qbe, + band_start, band_end, band_width, fLenLow, fLenHigh, bands, har_bands, g_fx, + pk_sf_fx, Qss, pul_res_fx + ); + + return; +} +/*--------------------------------------------------------------------------* + * EncodeSWBSubbands() + * + * Main routine for generic SWB coding. High-frequency subband + * replicated based on the lowband signal. A search is perform + * find lowband indices denoting the selected lowband subband. + *--------------------------------------------------------------------------*/ +static void EncodeSWBSubbands_fx( + Encoder_State *st_fx, /* i/o: encoder state structure */ + Word32 *L_spectra, /* i/o: MDCT domain spectrum */ + Word16 QsL, /* i : Q value for L_spectra */ + const Word16 fLenLow_fx, /* i : lowband length */ + const Word16 fLenHigh_fx, /* i : highband length */ + const Word16 nBands_fx, /* i : number of subbands */ + const Word16 nBands_search_fx, /* i : number of subbands to be searched for BWE */ + const Word16 *sbWidth_fx, /* i : subband lengths */ + const Word16 *subband_offsets_fx, /* i : Subband offset for BWE */ + Word16 *lagIndices_fx, /* o : lowband index for each subband */ + const Word16 BANDS_fx, /* i : noise estimate from WB part */ + const Word16 *band_start_fx, /* i : Number subbands/Frame */ + const Word16 *band_end_fx, /* i : Band Start of each SB */ + Word32 *L_band_energy, /* i : Band end of each SB, :Qbe */ + Word16 Qbe, /* i : Q value of band energy */ + const Word16 *p2a_flags_fx, /* i : BAnd energy of each SB */ + const Word16 hqswb_clas_fx, /* i : lowband synthesis */ + Word16 *prev_frm_index_fx, /* i : clas information */ + const Word16 har_bands_fx, /* i/o: Index of the previous Frame */ + const Word16 *subband_search_offset_fx, /* i : Number of harmonic LF bands */ + Word16 *prev_frm_hfe2_fx, /* i/o: */ + Word16 *prev_stab_hfe2_fx, /* i/o: */ + const Word16 band_width_fx[], /* i : band width */ + const Word32 L_spectra_ni[], /* i : Qs noise injected spectra */ + Word16 *ni_seed_fx /* i/o: random seed */ +) +{ + Word16 i, k; + Word16 sspectra_fx[L_FRAME32k]; + Word16 sspectra_ni_fx[L_FRAME32k]; + Word16 sspectra_diff_fx[L_FRAME32k]; + Word16 Qss; /* Q value of Smoothed Spectrum low-subband */ + Word32 L_be_tonal[SWB_HAR_RAN1]; /* Q */ + Word16 ss_min_fx; /* Qss */ + Word32 L_th_g[NB_SWB_SUBBANDS]; + Word16 QbeL; + GainItem_fx pk_sf_fx[(NB_SWB_SUBBANDS) * 8]; + Word16 pul_res_fx[NB_SWB_SUBBANDS]; + + GainItem_fx Nbiggest_fx[NB_SWB_SUBBANDS*N_NBIGGEST_PULSEARCH]; + + Word32 L_xSynth_har[L_FRAME32k]; /* Qs */ + + Word16 lagGains_fx[NB_SWB_SUBBANDS]; + Word16 QlagGains[NB_SWB_SUBBANDS]; + Word16 har_freq_est1, har_freq_est2; + Word16 flag_dis; + Word16 pos_max_hfe2; + HQ_ENC_HANDLE hHQ_core = st_fx->hHQ_core; + + har_freq_est1 = 0; + move16(); + har_freq_est2 = 0; + move16(); + flag_dis = 1; + move16(); + pos_max_hfe2 = 0; + move16(); + + set16_fx(sspectra_fx, 0, fLenLow_fx); + set16_fx(sspectra_ni_fx, 0, fLenLow_fx); + set32_fx(L_xSynth_har, 0, L_FRAME32k); + set16_fx(pul_res_fx, 0, NB_SWB_SUBBANDS); + + + IF(EQ_16(hqswb_clas_fx, HQ_HARMONIC)) + { + pos_max_hfe2 = har_est_fx(L_spectra, fLenLow_fx, &har_freq_est1, &har_freq_est2, &flag_dis, prev_frm_hfe2_fx, subband_search_offset_fx, sbWidth_fx, prev_stab_hfe2_fx); + noise_extr_corcod_fx(L_spectra, L_spectra_ni, sspectra_fx, sspectra_diff_fx, sspectra_ni_fx, fLenLow_fx, hHQ_core->prev_hqswb_clas, &hHQ_core->prev_ni_ratio_fx, &Qss); + /* Find best indices for each group */ + getswbindices_har_fx( + L_spectra, + QsL, sspectra_ni_fx, + nBands_search_fx, lagIndices_fx, prev_frm_index_fx, fLenLow_fx, subband_offsets_fx, sbWidth_fx, subband_search_offset_fx); + + /* Write the indices into the bitstream */ + FOR(k = 0; k < nBands_search_fx; k++) + { + push_indice_fx(st_fx->hBstr, IND_LAGINDICES, lagIndices_fx[k], bits_lagIndices_mode0_Har[k]); + } + + IF(flag_dis == 0) + { + test(); + if (NE_16(har_freq_est2, SWB_HAR_RAN1) || NE_16(har_freq_est2, *prev_frm_hfe2_fx)) + { + har_freq_est2 = add(har_freq_est2, lagIndices_fx[0]); + move16(); + } + } + + gethar_noisegn_fx(st_fx->hBstr, L_spectra, QsL, sspectra_diff_fx, Qss, L_xSynth_har, + sbWidth_fx, lagIndices_fx, BANDS_fx, har_bands_fx, fLenLow_fx, fLenHigh_fx, + subband_offsets_fx, subband_search_offset_fx, band_start_fx, band_end_fx, band_width_fx, + L_band_energy, Qbe, L_be_tonal, &QbeL, sspectra_fx, + har_freq_est2, pos_max_hfe2, pul_res_fx, pk_sf_fx); + + + Gettonl_scalfact_fx(L_xSynth_har, QsL, L_spectra_ni, fLenLow_fx, fLenHigh_fx, har_bands_fx, BANDS_fx, L_band_energy, Qbe, band_start_fx, band_end_fx, + p2a_flags_fx, L_be_tonal, QbeL, pk_sf_fx, Qss, pul_res_fx); + + IF(flag_dis == 0) + { + *prev_frm_hfe2_fx = 0; + move16(); + } + ELSE + { + *prev_frm_hfe2_fx = har_freq_est2; + move16(); + } + + FOR(k = BANDS_fx - NB_SWB_SUBBANDS; k < BANDS_fx; k++) + { + FOR(i = band_start_fx[k]; i <= band_end_fx[k]; i++) + { + L_spectra[i] = L_xSynth_har[i - fLenLow_fx]; + move32(); /* QsL */ + } + } + } + ELSE + { + ss_min_fx = spectrumsmooth_noiseton_fx(L_spectra, /*QsL,*/ L_spectra_ni, sspectra_fx, sspectra_diff_fx, sspectra_ni_fx, &Qss, fLenLow_fx, ni_seed_fx); + + /* Get lag indices */ + GetSWBIndices_fx(sspectra_fx, /*Qss,*/ L_spectra + fLenLow_fx, QsL, nBands_fx, sbWidth_fx, lagIndices_fx, fLenLow_fx, + Nbiggest_fx, subband_offsets_fx, sspectra_fx); + + /* Bitstream operations */ + FOR(k = 0; k < nBands_fx; k++) + { + IF(EQ_16(p2a_flags_fx[BANDS_fx - NB_SWB_SUBBANDS + k], 1)) + { + lagIndices_fx[k] = 0; + move16(); + lagGains_fx[k] = 0; + move16(); + QlagGains[k] = 15; + move16(); + } + ELSE + { + push_indice_fx(st_fx->hBstr, IND_LAGINDICES, lagIndices_fx[k], bits_lagIndices_modeNormal[k]); + } + } + + convert_lagIndices_pls2smp_fx(lagIndices_fx, nBands_fx, lagIndices_fx, sspectra_fx, sbWidth_fx, fLenLow_fx); + + GetlagGains_fx(sspectra_ni_fx, Qss, &L_band_energy[BANDS_fx - NB_SWB_SUBBANDS], Qbe, nBands_fx, sbWidth_fx, lagIndices_fx, fLenLow_fx, lagGains_fx, QlagGains); + FOR(k = 0; k < NB_SWB_SUBBANDS; k++) + { + lagGains_fx[k] = mult_r(lagGains_fx[k], 29491); /* lagGains[k]*0.9f; */ + } + + FOR(k = 0; k < NB_SWB_SUBBANDS; k++) + { + L_th_g[k] = L_deposit_l(0); + IF(p2a_flags_fx[BANDS_fx - NB_SWB_SUBBANDS + k] == 0) + { + L_th_g[k] = L_shl(L_mult(lagGains_fx[k], ss_min_fx), sub(QsL, add(add(QlagGains[k], Qss), 1))); /* QlagGain+Qss -> QsL */ + } + } + + GetSynthesizedSpecThinOut_fx(sspectra_ni_fx, Qss, L_xSynth_har, QsL, nBands_fx, sbWidth_fx, lagIndices_fx, lagGains_fx, QlagGains, fLenLow_fx); + + /*Level adjustment for the missing bands*/ + noiseinj_hf_fx(L_xSynth_har, QsL, L_th_g, L_band_energy, Qbe, hHQ_core->prev_En_sb_fx, p2a_flags_fx, BANDS_fx, band_start_fx, band_end_fx, fLenLow_fx, fLenHigh_fx); + + + FOR(k = BANDS_fx - NB_SWB_SUBBANDS; k < BANDS_fx; k++) + { + IF(p2a_flags_fx[k] == 0) + { + FOR(i = band_start_fx[k]; i <= band_end_fx[k]; i++) + { + L_spectra[i] = L_xSynth_har[i - fLenLow_fx]; + move32(); /* Qob */ + } + } + ELSE + { + FOR(i = band_start_fx[k]; i <= band_end_fx[k]; i++) + { + L_spectra[i] = L_spectra_ni[i]; + move32(); + } + } + } + } + + return; +} +/*--------------------------------------------------------------------------* + * swb_bwe_enc_lr() + * + * Main encoding routine of SWB BWE for the LR MDCT core + *--------------------------------------------------------------------------*/ +void swb_bwe_enc_lr_fx( + Encoder_State *st_fx, /* i/o: encoder state structure */ + const Word32 L_m_core[], /* i : lowband synthesis */ + Word16 QsL, /* i : Q value */ + const Word32 L_m_orig[], /* i/o: scaled orig signal (MDCT) */ + Word32 L_m[], /* o : highband synthesis with lowband zeroed */ + const Word32 L_total_brate, /* i : total bitrate for selecting subband pattern */ + Word16 BANDS_fx, /* i : Total number of Subbands in a frame */ + Word16 *band_start_fx, /* i : band start of each SB */ + Word16 *band_end_fx, /* i : band end of each SB */ + Word32 *L_band_energy, /* i : band_energy of each SB */ + Word16 Qbe, /* i : Q value of band energy */ + Word16 *p2a_flags_fx, /* i : HF tonal indicator */ + const Word16 hqswb_clas_fx, /* i : HQ_NORMAL2 or HQ_HARMONIC mode */ + Word16 lowlength_fx, /* i : lowband length */ + Word16 highlength_fx, /* i : highband length */ + Word16 *prev_frm_index_fx, /* i/o: previous frame lag index for harmonic mode */ + const Word16 har_bands_fx, /* i : Number of LF harmonic bands */ + Word16 *prev_frm_hfe2, /* i/o: */ + Word16 *prev_stab_hfe2, /* i/o: */ + const Word16 band_width_fx[],/* i : band_width information */ + const Word32 L_y2_ni[], /* i : band_width information */ + Word16 *ni_seed_fx /* i/o: random seed for search buffer NI */ +) +{ + Word16 k; + Word16 nBands_fx; + Word16 nBands_search_fx; + Word16 wBands_fx[NB_SWB_SUBBANDS]; + Word16 lagIndices_fx[NB_SWB_SUBBANDS]; + Word16 swb_lowband_fx, swb_highband_fx, allband_fx; + + const Word16 *subband_offsets_fx; + const Word16 *subband_search_offset_fx; + + Word32 *p_L_m; + + subband_search_offset_fx = subband_search_offsets_13p2kbps_Har; + subband_offsets_fx = subband_offsets_sub5_13p2kbps_Har; + + hf_parinitiz_fx(L_total_brate, hqswb_clas_fx, lowlength_fx, highlength_fx, wBands_fx, &subband_search_offset_fx, &subband_offsets_fx, &nBands_fx, &nBands_search_fx, &swb_lowband_fx, &swb_highband_fx); + allband_fx = add(swb_lowband_fx, swb_highband_fx); + move16(); + + /* Prepare m[], low part from WB core, high part from 32k input */ + Copy32(L_m_core, L_m, swb_lowband_fx); + Copy32(&L_m_orig[swb_lowband_fx], &L_m[swb_lowband_fx], swb_highband_fx); + + EncodeSWBSubbands_fx( + st_fx, + L_m, QsL, + swb_lowband_fx, swb_highband_fx, nBands_fx, nBands_search_fx, wBands_fx, subband_offsets_fx, + lagIndices_fx, + BANDS_fx, band_start_fx, band_end_fx, + L_band_energy, Qbe, + p2a_flags_fx, + hqswb_clas_fx, prev_frm_index_fx, har_bands_fx, subband_search_offset_fx, + prev_frm_hfe2, prev_stab_hfe2, + band_width_fx, L_y2_ni, ni_seed_fx + ); + + p_L_m = &L_m[sub(allband_fx, 1)]; + *p_L_m = Mult_32_16(*p_L_m, 2028); + move32(); + p_L_m--; /* 0.0625 = 2028 (Q15) */ + *p_L_m = Mult_32_16(*p_L_m, 4096); + move32(); + p_L_m--; /* 0.125 = 4096 (Q15) */ + *p_L_m = Mult_32_16(*p_L_m, 8192); + move32(); + p_L_m--; /* 0.25 = 8192 (Q15) */ + *p_L_m = Mult_32_16(*p_L_m, 16384); + move32(); + p_L_m--; /* 0.5 = 16384 (Q15) */ + + /* set low frequencies to zero */ + FOR(k = 0; k < swb_lowband_fx; k++) + { + L_m[k] = L_deposit_l(0); + } + + return; +} diff --git a/lib_enc/tns_base_enc.c b/lib_enc/tns_base_enc.c index 37a0b10a2..aaa3df2c4 100644 --- a/lib_enc/tns_base_enc.c +++ b/lib_enc/tns_base_enc.c @@ -79,7 +79,7 @@ int16_t DetectTnsFilt( float *predictionGain /* o : TNS prediction gain */ ) { - ResetTnsData( pTnsData ); + ResetTnsData_flt( pTnsData ); if ( pTnsConfig->maxOrder <= 0 ) { @@ -261,7 +261,7 @@ static void GetFilterParameters( { int16_t i; float parCoeff[TNS_MAX_FILTER_ORDER]; - const float *values = tnsCoeff4; + const float *values = tnsCoeff4_flt; int16_t *indexes = pTnsFilter->coefIndex; /* Variable initialization */ @@ -308,7 +308,7 @@ static void Parcor2Index( ) { const int16_t nValues = 1 << TNS_COEF_RES; - const float *values = tnsCoeff4; + const float *values = tnsCoeff4_flt; int16_t i; int16_t iIndex; float x; @@ -464,20 +464,20 @@ static void TnsDecision( } else { - ClearTnsFilterCoefficients( pFilter ); + ClearTnsFilterCoefficients_flt( pFilter ); } } } else if ( pTnsData->nFilters > 0 ) /* If a previous filter is turned on */ { /* Since TNS filter of order 0 is not allowed we haved to signal in the stream filter of order 1 with the 0th coefficient equal to 0 */ - ClearTnsFilterCoefficients( pFilter ); + ClearTnsFilterCoefficients_flt( pFilter ); pFilter->order = 1; ++pTnsData->nFilters; } else { - ClearTnsFilterCoefficients( pFilter ); + ClearTnsFilterCoefficients_flt( pFilter ); } } -- GitLab