diff --git a/Workspace_msvc/lib_dec.vcxproj b/Workspace_msvc/lib_dec.vcxproj index f51c45ee2c6a8e8a78acc0398424acdae26b664a..d6e4a7c672d91bb76b7e3e30fdca199c56285df7 100644 --- a/Workspace_msvc/lib_dec.vcxproj +++ b/Workspace_msvc/lib_dec.vcxproj @@ -297,6 +297,7 @@ + diff --git a/lib_com/basop32.h b/lib_com/basop32.h index b0ad2a428b6b4e522d852f49fd98042d48027d34..e9f16437a6d2b6388a69c7c3f74ec62793177d20 100644 --- a/lib_com/basop32.h +++ b/lib_com/basop32.h @@ -239,6 +239,7 @@ Word32 L_abs( Word32 L_var1 ); /* Word32 DEPR_L_sat_co( Word32 L_var1, Flag Overflow, Flag Carry ); /* Long saturation, 4 */ Word16 norm_s( Word16 var1 ); /* Short norm, 1 */ Word16 div_s( Word16 var1, Word16 var2 ); /* Short division, 18 */ +Word32 div_w(Word32 L_num, Word32 L_den); Word16 norm_l( Word32 L_var1 ); /* Long norm, 1 */ #endif /* BASOP_NOGLOB */ diff --git a/lib_com/basop_util.c b/lib_com/basop_util.c index 40a3c3baa3383cc9259916dcd42483bf7f46f6d2..2760f4feb2a305deea136d65d2cda99aac9ca0d9 100644 --- a/lib_com/basop_util.c +++ b/lib_com/basop_util.c @@ -933,6 +933,104 @@ Word16 BASOP_Util_Divide3232_uu_1616_Scale(Word32 x, Word32 y, Word16 *s) return (z); } +Word32 div_w( Word32 L_num, Word32 L_den ) +{ + Word32 L_var_out = (Word32) 0; + Word16 iteration; + + + if ( L_den == (Word32) 0 ) + { + /* printf("Division by 0 in div_l, Fatal error in "); printStack(); */ + return ( 0 ); + } + + if ( ( L_num < (Word32) 0 ) || ( L_den < (Word32) 0 ) ) + { + /* printf("Division Error in div_l, Fatal error in "); printStack(); */ + return ( 0 ); + } + Word64 W_num, W_den; + W_num = W_deposit32_h( L_num ); + W_den = W_deposit32_h( L_den ); + + if ( W_num >= W_den ) + { + return MAX_32; + } + else + { + W_num = W_shr( W_num, (Word16) 1 ); + W_den = W_shr( W_den, (Word16) 1 ); + + for ( iteration = (Word16) 0; iteration < (Word16) 31; iteration++ ) + { + L_var_out = L_shl( L_var_out, (Word16) 1 ); + W_num = W_shl( W_num, (Word16) 1 ); + + if ( W_num >= W_den ) + { + W_num = W_sub( W_num, W_den ); + L_var_out = L_add( L_var_out, (Word32) 1 ); + } + } + + return L_var_out; + } +} + +Word32 BASOP_Util_Divide3232_Scale_cadence( Word32 x, Word32 y, Word16 *s ) +{ + Word32 z; + Word16 sx; + Word16 sy; + Word32 sign; + + /* assert (x >= (Word32)0); */ + assert( y != (Word32) 0 ); + + sign = 0; + move16(); + + IF( x < 0 ) + { + x = L_negate( x ); + sign = L_xor( sign, 1 ); + } + + IF( y < 0 ) + { + y = L_negate( y ); + sign = L_xor( sign, 1 ); + } + + IF( x == (Word32) 0 ) + { + *s = 0; + return ( (Word32) 0 ); + } + + sx = norm_l( x ); + x = L_shl( x, sx ); + x = L_shr( x, 1 ); + move16(); + *s = sub( 1, sx ); + + sy = norm_l( y ); + y = L_shl( y, sy ); + move16(); + *s = add( *s, sy ); + + z = div_w( x, y ); + + if ( sign != 0 ) + { + z = L_negate( z ); + } + + return z; +} + Word16 BASOP_Util_Divide3232_Scale(Word32 x, Word32 y, Word16 *s) { Word16 z; diff --git a/lib_com/basop_util.h b/lib_com/basop_util.h index 61b170af39e05cf657c5cfc8a228b35d6e2edad3..267c5c03475627206d2606fad83d2205f474f2b2 100644 --- a/lib_com/basop_util.h +++ b/lib_com/basop_util.h @@ -325,6 +325,9 @@ Word16 BASOP_Util_Divide3232_Scale(Word32 x, /*!< i : Numerator*/ Word32 y, /*!< i : Denominator*/ Word16 *s); /*!< o : Additional scalefactor difference*/ +Word32 BASOP_Util_Divide3232_Scale_cadence(Word32 x, /*!< i : Numerator*/ + Word32 y, /*!< i : Denominator*/ + Word16 *s); /*!< o : Additional scalefactor difference*/ /************************************************************************/ /*! diff --git a/lib_com/ivas_mdct_imdct_fx.c b/lib_com/ivas_mdct_imdct_fx.c index d9c8a58ec1f72fd60a6f8b9516a5cbae6b1a8348..a9c7370fa8aa07f8db91f7d123069a5690db54fc 100644 --- a/lib_com/ivas_mdct_imdct_fx.c +++ b/lib_com/ivas_mdct_imdct_fx.c @@ -71,10 +71,12 @@ void ivas_tda_fx( Word16 i; Word16 len_by_2 = shr(length, 1); - FOR ( i = 0; i < len_by_2; i++ ) + FOR( i = 0; i < len_by_2; i++ ) { - pOut[i] = L_sub(pIn[len_by_2 + i], pIn[len_by_2 - i - 1]); - pOut[len_by_2 + i] = L_add(pIn[length * 2 - i - 1], pIn[length + i]); + pOut[i] = L_sub( pIn[add( len_by_2, i )], pIn[sub( sub( len_by_2, i ), 1 )] ); + move32(); + pOut[add( len_by_2, i )] = L_add( pIn[sub( sub( i_mult( length, 2 ), i ), 1 )], pIn[add( length, i )] ); + move32(); } return; @@ -105,23 +107,23 @@ void ivas_dct_windowing_fx( Copy32( pTemp_lfe, ( pOut_buf + fade_len + zero_pad_len ), dct_len ); - set32_fx(pOut_buf, 0, zero_pad_len); + set32_fx( pOut_buf, 0, zero_pad_len ); Copy32( ( pOut_buf + full_len - fade_len ), pBuffer_prev, fade_len ); - FOR ( i = 0; i < fade_len; i++ ) + FOR( i = 0; i < fade_len; i++ ) { - pOut_buf[zero_pad_len + i] = Mult_32_32(pOut_buf[zero_pad_len + i], pWindow_coeffs[i]); + pOut_buf[add( zero_pad_len, i )] = Mult_32_32( pOut_buf[add( zero_pad_len, i )], pWindow_coeffs[i] ); } - rem_len = full_len - ( zero_pad_len * 3 + fade_len ); + rem_len = sub( full_len, ( add( i_mult( zero_pad_len, 3 ), fade_len ) ) ); - FOR ( i = 0; i < rem_len; i++ ) + FOR( i = 0; i < rem_len; i++ ) { - pOut_buf[zero_pad_len * 3 + fade_len + i] = Mult_32_32(pOut_buf[zero_pad_len * 3 + fade_len + i], pWindow_coeffs[fade_len - i - 1]); + pOut_buf[add( add( i_mult( zero_pad_len, 3 ), fade_len ), i )] = Mult_32_32( pOut_buf[add( add( i_mult( zero_pad_len, 3 ), fade_len ), i )], pWindow_coeffs[sub( sub( fade_len, i ), 1 )] ); } - set32_fx(&pOut_buf[full_len], 0, frame_len - full_len); + set32_fx( &pOut_buf[full_len], 0, sub( frame_len, full_len ) ); return; } diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index 6e03bb27d0f17988d3d4379df191dc90ea466d8b..900ac1a9d76adfe6b066710a34af8f6c60176a9c 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -815,6 +815,13 @@ void ivas_lfe_dec_fx( Word32 output_lfe_ch[] /* o : output LFE synthesis */ ); +void ivas_lfe_tdplc_fx( + LFE_DEC_HANDLE hLFE, /* i/o: LFE decoder handle */ + const Word32 *prevsynth, /* i : previous frame synthesis */ + Word32 *ytda, /* o : output time-domain buffer */ + const Word16 output_frame /* i : output frame length */ +); + void ivas_lfe_dec_close_fx( LFE_DEC_HANDLE *hLFE /* i/o: LFE decoder handle */ ); diff --git a/lib_com/ivas_rom_com.c b/lib_com/ivas_rom_com.c index 038c09f5d4d98ec1abc94fd75acb30818ad32866..f6b121a5419eec5b47ec5f13c494a05dafb8e161 100644 --- a/lib_com/ivas_rom_com.c +++ b/lib_com/ivas_rom_com.c @@ -3950,6 +3950,26 @@ const int16_t ivas_lfe_min_shift_tbl[IVAS_LFE_NUM_COEFFS_IN_SUBGRP] = { 1, 0 }; const float ivas_lfe_lpf_delay[2] = { 0.00175f, 0.0035f }; const Word16 ivas_lfe_lpf_delay_Q15[2] = { 57, 114 }; +#ifdef IVAS_FLOAT_FIXED +//Q31 +const UWord32 d_hamm_lfe_plc_fx[LFE_PLC_LENANA / 2] = { + 171798691, 172140039, 173163845, 174869403, 177255533, 180320587, 184062447, 188478526, + 193565772, 199320670, 205739242, 212817053, 220549212, 228930373, 237954746, 247616094, + 257907739, 268822570, 280353042, 292491188, 305228618, 318556530, 332465713, 346946555, + 361989047, 377582794, 393717019, 410380572, 427561937, 445249239, 463430255, 482092421, + 501222838, 520808286, 540835229, 561289828, 582157945, 603425159, 625076772, 647097821, + 669473086, 692187106, 715224182, 738568392, 762203605, 786113486, 810281510, 834690976, + 859325014, 884166600, 909198565, 934403610, 959764316, 985263157, 1010882509, 1036604668, + 1062411858, 1088286242, 1114209939, 1140165034, 1166133589, 1192097656, 1218039293, 1243940572, + 1269783591, 1295550491, 1321223465, 1346784770, 1372216740, 1397501800, 1422622476, 1447561406, + 1472301355, 1496825225, 1521116069, 1545157098, 1568931699, 1592423440, 1615616087, 1638493611, + 1661040202, 1683240277, 1705078494, 1726539762, 1747609248, 1768272390, 1788514910, 1808322817, + 1827682422, 1846580346, 1865003529, 1882939237, 1900375077, 1917298998, 1933699304, 1949564660, + 1964884103, 1979647046, 1993843284, 2007463009, 2020496806, 2032935668, 2044771000, 2055994621, + 2066598775, 2076576133, 2085919801, 2094623320, 2102680676, 2110086301, 2116835076, 2122922337, + 2128343877, 2133095950, 2137175272, 2140579023, 2143304850, 2145350871, 2146715671, 2147398307 +}; +#else const double d_hamm_lfe_plc[LFE_PLC_LENANA / 2] = { 0.08000000000000002, 0.08015895227847719, 0.08063569926248770, 0.08142991147368656, 0.08254104003450596, 0.08396831704748331, 0.08571075612595230, 0.08776715307573196, @@ -3968,7 +3988,7 @@ const double d_hamm_lfe_plc[LFE_PLC_LENANA / 2] = 0.96233504613317988, 0.96698111571154954, 0.97133209998031445, 0.97538499198789563, 0.97913699079334116, 0.98258550340204664, 0.98572814655776630, 0.98856274838967395, 0.99108734991333569, 0.99330020638455863, 0.99519978850517732, 0.99678478347994692, 0.99805409592381300, 0.99900684861892730, 0.99964238312089115, 0.99996026021380402 }; - +#endif /*------------------------------------------------------------------------------------------* * MDFT/iMDFT ROM tables diff --git a/lib_com/ivas_rom_com.h b/lib_com/ivas_rom_com.h index cbbe264584ec2ce03c92e3344b570e6ba57e6370..b56f631c26b4c2c3d64f12231d004147953b46de 100644 --- a/lib_com/ivas_rom_com.h +++ b/lib_com/ivas_rom_com.h @@ -451,9 +451,11 @@ extern const int16_t ivas_lfe_min_shift_tbl[IVAS_LFE_NUM_COEFFS_IN_SUBGRP]; extern const ivas_lfe_freq_models ivas_str_lfe_freq_models; extern const float ivas_lfe_lpf_delay[2]; extern const Word16 ivas_lfe_lpf_delay_Q15[2]; - +#ifdef IVAS_FLOAT_FIXED +extern const UWord32 d_hamm_lfe_plc_fx[LFE_PLC_LENANA / 2]; +#else extern const double d_hamm_lfe_plc[LFE_PLC_LENANA / 2]; - +#endif extern const float ivas_sin_twiddle_480[IVAS_480_PT_LEN >> 1]; extern const float ivas_cos_twiddle_480[IVAS_480_PT_LEN >> 1]; extern const float ivas_sin_twiddle_320[IVAS_320_PT_LEN >> 1]; diff --git a/lib_com/modif_fs_fx.c b/lib_com/modif_fs_fx.c index 8cd86a314652c3272162f05f763d6264f522d2fd..be45576b7951bf6d65dc95976585089fb9f8e32a 100644 --- a/lib_com/modif_fs_fx.c +++ b/lib_com/modif_fs_fx.c @@ -221,7 +221,7 @@ Word16 modify_Fs_fx( /* o : length of output Q0 */ } /* interpolation */ - datastep = shr(div_s(shl(fac_den,8), shl(fac_num,11)),12); + datastep = shr(div_s(shl(fac_den,7), shl(fac_num,10)),12); /* equivalent to 'datastep = fac_den % fac_num' */ temp_n = i_mult2(datastep,fac_num); /*Q0*/ fracstep = sub(fac_den,temp_n); diff --git a/lib_dec/ivas_lfe_dec.c b/lib_dec/ivas_lfe_dec.c index b6b88e0e4f45f9e67872f321bbbe4deacda3f498..a7c0fe222efaf292e8d93c8f89d9a27835efc09b 100644 --- a/lib_dec/ivas_lfe_dec.c +++ b/lib_dec/ivas_lfe_dec.c @@ -47,7 +47,7 @@ /* Delay handling of LFE: overall_lfe_delay = max(11.5, BLOCK_OFFSET_MS); */ #define BLOCK_OFFSET_MS 12 - +#ifndef IVAS_FLOAT_FIXED /*-----------------------------------------------------------------------------------------* * Function ivas_lfe_dec_delay_adjust() * @@ -472,3 +472,4 @@ void ivas_lfe_dec_close( return; } #endif +#endif \ No newline at end of file diff --git a/lib_dec/ivas_lfe_dec_fx.c b/lib_dec/ivas_lfe_dec_fx.c index 4efe4a477c006a53f320429a325f9d80f1882418..ecda2cb2e16976ed28b9695ba30f40cfc798c83b 100644 --- a/lib_dec/ivas_lfe_dec_fx.c +++ b/lib_dec/ivas_lfe_dec_fx.c @@ -352,27 +352,8 @@ void ivas_lfe_dec_fx( { /* note: in BFI branch, buffer 't_audio' is in time-domain ('wtda' signal) */ hLFE->bfi_count++; -#ifdef IVAS_FLOAT_FIXED_TBD - ivas_lfe_tdplc_fx( hLFE, hLFE->prevsynth_buf, t_audio, output_frame ); -#else - float t_audio_flt[L_FRAME48k]; - FOR( int k = 0; k < 240; k++ ) - { - - hLFE->prevsynth_buf[k] = (float) hLFE->prevsynth_buf_fx[k] / ONE_IN_Q9; - } - - ivas_lfe_tdplc( hLFE, hLFE->prevsynth_buf, t_audio_flt, output_frame ); - FOR( int k = 0; k < 960; k++ ) - { - if ( k < 240 ) - { - hLFE->prevsynth_buf_fx[k] = (Word32) ( hLFE->prevsynth_buf[k] * ONE_IN_Q9 ); - } - t_audio[k] = (Word32) ( t_audio_flt[k] * ONE_IN_Q9 ); - } -#endif // IVAS_FLOAT_FIXED_TBD + ivas_lfe_tdplc_fx( hLFE, hLFE->prevsynth_buf_fx, t_audio, output_frame ); ivas_itda_fx( t_audio, out, dct_len ); ivas_lfe_dec_windowing_fx( hLFE, out ); diff --git a/lib_dec/ivas_lfe_plc.c b/lib_dec/ivas_lfe_plc.c index 1844ca8ee470708fbdaf5be2e607997b021f7744..6fe8d59394dfd51932ab8cf7255f887286c7ecf1 100644 --- a/lib_dec/ivas_lfe_plc.c +++ b/lib_dec/ivas_lfe_plc.c @@ -54,7 +54,7 @@ #define MAX_LEN_LP 960 #define EPS_STOP 1e-5 - +#ifndef IVAS_FLOAT_FIXED /*------------------------------------------------------------------------------------------* * Static function declarations * @@ -535,3 +535,4 @@ void ivas_lfe_tdplc( return; } +#endif \ No newline at end of file diff --git a/lib_dec/ivas_lfe_plc_fx.c b/lib_dec/ivas_lfe_plc_fx.c new file mode 100644 index 0000000000000000000000000000000000000000..f4f2d355191b5ca8d2ab22562af6e1f7cc560968 --- /dev/null +++ b/lib_dec/ivas_lfe_plc_fx.c @@ -0,0 +1,976 @@ +/****************************************************************************************************** + + (C) 2022-2024 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.h" +#include "prot_fx1.h" +#include "prot_fx2.h" +#include "ivas_prot.h" +#include "ivas_rom_com.h" +#include +#include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#endif + +/*------------------------------------------------------------------------------------------* + * Local constants + *------------------------------------------------------------------------------------------*/ + +#define LFE_PLC_DSF ( 48000 / LFE_PLC_FS ) +#define LFE_PLC_LPCORD ( 20 ) +#define LFE_PLC_MAXITER ( 10 ) +#define POW_THR ( 1.0e-8f ) +#define LFE_PLC_RECLEN_48K ( ( IVAS_LFE_NUM_COEFFS_IN_SUBGRP + 1 ) * L_FRAME48k / IVAS_LFE_NUM_COEFFS_IN_SUBGRP + LFE_PLC_FDEL ) +#define LFE_PLC_RECLEN ( ( LFE_PLC_RECLEN_48K / LFE_PLC_DSF ) ) +#define LFE_PLC_MUTE_THR ( 10 ) +#define LFE_PLC_BURST_ATT ( pow( pow( 10.0, -3.0 / 20.0 ), 1.0 / ( LFE_PLC_FS * 0.02 ) ) ) /* attenuate 3dB per frame starting with 10th consecutive loss */ + +#define MAX_LEN_LP 960 + +#define EPS_STOP 1e-5 +#ifdef IVAS_FLOAT_FIXED +#define POW_THR_Q50 ( 11258999 ) +#define EPS_STOP_Q31 ( 21475 ) +#define LFE_PLC_BURST_ATT_Q31 ( 2124429696 ) + +/*------------------------------------------------------------------------------------------* + * Static function declarations + * + * Note (DLB): the local double precision functions defined below are replica of corresponding + * float functions defined in tools.c, lpc_tools.c and syn_filt.c. + * Double precision arithmetic is required for proper functioning of the lfe_plc. + *------------------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------* + * autocorr_fx() + * + * Compute autocorrelations of input signal + *---------------------------------------------------------------------*/ + +static void d_autocorr_fx( + const Word32 *x_fx, /* i : input signal */ + Word16 x_q_fx, + Word32 *r_fx, /* o : autocorrelations vector */ + Word16 *r_q_fx, + const Word16 m, /* i : order of LP filter */ + const Word16 len, /* i : window size */ + const UWord32 *wind_fx, /* i : window */ + const Word16 rev_flag, /* i : flag to reverse window */ + const Word16 sym_flag, /* i : symmetric window flag */ + const Word16 no_thr /* i : flag to avoid thresholding */ +) +{ + Word16 i, j; + Word32 t_fx[MAX_LEN_LP]; + Word64 s_fx; + Word32 temp; + Word16 tmp_q, exp1, exp2; + + /* Windowing of signal */ + IF( EQ_16( rev_flag, 1 ) ) + { + /* time reversed window */ + FOR( i = 0; i < len; i++ ) + { + t_fx[i] = Mpy_32_32( x_fx[i], wind_fx[sub( sub( len, i ), 1 )] ); // Q = x_q_fx + move32(); + } + } + ELSE IF( EQ_16( sym_flag, 1 ) ) + { + /* symmetric window of even length */ + FOR( i = 0; i < len / 2; i++ ) + { + t_fx[i] = Mpy_32_32( x_fx[i], wind_fx[i] ); // Q = x_q_fx + move32(); + } + + FOR( ; i < len; i++ ) + { + t_fx[i] = Mpy_32_32( x_fx[i], wind_fx[sub( sub( len, 1 ), i )] ); // Q = x_q_fx + move32(); + } + } + ELSE /* assymetric window */ + { + FOR( i = 0; i < len; i++ ) + { + t_fx[i] = Mpy_32_32( x_fx[i], wind_fx[i] ); // Q = x_q_fx + move32(); + } + } + + /* Compute r[1] to r[m] */ + FOR( i = 0; i <= m; i++ ) + { + exp1 = norm_l( t_fx[0] ); + exp2 = norm_l( t_fx[i] ); + s_fx = W_deposit32_l( Mpy_32_32( L_shl( t_fx[0], exp1 ), L_shl( t_fx[i], exp2 ) ) ); + r_q_fx[i] = sub( add( add( x_q_fx, exp1 ), add( x_q_fx, exp2 ) ), 31 ); + move16(); + FOR( j = 1; j < sub( len, i ); j++ ) + { + exp1 = norm_l( t_fx[j] ); + exp2 = norm_l( t_fx[add( i, j )] ); + temp = Mpy_32_32( L_shl( t_fx[j], exp1 ), L_shl( t_fx[add( i, j )], exp2 ) ); + tmp_q = sub( add( add( x_q_fx, exp1 ), add( x_q_fx, exp2 ) ), 31 ); + + IF( LT_16( tmp_q, r_q_fx[i] ) ) + { + s_fx = W_add( W_shr( s_fx, sub( r_q_fx[i], tmp_q ) ), W_deposit32_l( temp ) ); + r_q_fx[i] = tmp_q; + move16(); + } + ELSE + { + s_fx = W_add( s_fx, W_shr( temp, sub( tmp_q, r_q_fx[i] ) ) ); + } + } + exp1 = W_norm( s_fx ); + r_fx[i] = W_extract_h( W_shl( s_fx, exp1 ) ); + move32(); + r_q_fx[i] = sub( add( r_q_fx[i], exp1 ), 32 ); + move16(); + } + + IF( L_and( LT_32( L_shr( r_fx[0], r_q_fx[0] ), 1000 ), EQ_16( no_thr, 0 ) ) ) + { + r_fx[0] = 2097152000; // 1000 Q21 + move32(); + r_q_fx[0] = Q21; + move16(); + } + + return; +} + +/*---------------------------------------------------------------------* + * lev_dur_fx() + * + * Wiener-Levinson-Durbin algorithm to compute LP parameters from the autocorrelations + * of input signal + *---------------------------------------------------------------------*/ + +/*! r: energy of prediction error */ +static Word16 d_lev_dur_fx( + Word32 *a_fx, /* o : LP coefficients (a[0] = 1.0) */ + Word16 *a_q_fx, + Word32 *r_fx, /* i : vector of autocorrelations */ + Word16 *r_q_fx, + const Word16 m, /* i : order of LP filter */ + Word32 *epsP_fx, /* o : prediction error energy */ + Word16 *epsP_q_fx ) +{ + Word16 i, j, l; + Word16 flag = 0; + Word32 buf_fx[TCXLTP_LTP_ORDER]; + Word16 rc_q_fx[TCXLTP_LTP_ORDER]; + Word32 *rc_fx; /* reflection coefficients 0,...,m-1 */ + Word32 temp1, temp2, err_fx, at_fx, s, a_tmp; + Word16 temp_q1, temp_q2, s_q_fx, err_q_fx, exp1, exp2; + Word64 s_fx; + + rc_fx = &buf_fx[0]; + rc_fx[0] = BASOP_Util_Divide3232_Scale_cadence( -r_fx[1], r_fx[0], &temp_q2 ); + move32(); + rc_q_fx[0] = add( sub( r_q_fx[1], r_q_fx[0] ), sub( 31, temp_q2 ) ); + move16(); + + a_fx[0] = ONE_IN_Q30; + move32(); + a_q_fx[0] = 30; + move16(); + a_fx[1] = rc_fx[0]; + move32(); + a_q_fx[1] = rc_q_fx[0]; + move32(); + + temp1 = Mpy_32_32( r_fx[1], rc_fx[0] ); + temp_q1 = sub( add( r_q_fx[1], rc_q_fx[0] ), 31 ); + + IF( LT_16( temp_q1, r_q_fx[0] ) ) + { + err_fx = L_add( L_shr( r_fx[0], sub( r_q_fx[0], temp_q1 ) ), temp1 ); + err_q_fx = temp_q1; + move16(); + } + ELSE + { + err_fx = L_add( r_fx[0], L_shr( temp1, sub( temp_q1, r_q_fx[0] ) ) ); + err_q_fx = r_q_fx[0]; + move16(); + } + + IF( epsP_fx != NULL ) + { + epsP_fx[0] = r_fx[0]; + move32(); + epsP_q_fx[0] = r_q_fx[0]; + move16(); + epsP_fx[1] = err_fx; + move32(); + epsP_q_fx[1] = err_q_fx; + move16(); + } + + FOR( i = 2; i <= m; i++ ) + { + s_fx = 0; + move64(); + + FOR( j = 0; j < i; j++ ) + { + exp1 = norm_l( r_fx[i - j] ); + exp2 = norm_l( a_fx[j] ); + temp1 = Mpy_32_32( L_shl( r_fx[i - j], exp1 ), L_shl( a_fx[j], exp2 ) ); + temp_q1 = sub( add( add( r_q_fx[i - j], exp1 ), add( a_q_fx[j], exp2 ) ), 31 ); + + IF( EQ_16( j, 0 ) ) + { + s_fx = W_deposit32_l( temp1 ); + s_q_fx = temp_q1; + move16(); + } + ELSE + { + IF( LT_16( temp_q1, s_q_fx ) ) + { + s_fx = W_add( W_shr( s_fx, sub( s_q_fx, temp_q1 ) ), W_deposit32_l( temp1 ) ); + s_q_fx = temp_q1; + move16(); + } + ELSE + { + s_fx = W_add( s_fx, W_shr( W_deposit32_l( temp1 ), sub( temp_q1, s_q_fx ) ) ); + } + } + } + exp1 = W_norm( s_fx ); + s = W_extract_h( W_shl( s_fx, exp1 ) ); + s_q_fx = sub( add( s_q_fx, exp1 ), 32 ); + + rc_fx[i - 1] = L_shr( BASOP_Util_Divide3232_Scale_cadence( -s, err_fx, &temp_q2 ), 1 ); + move32(); + rc_q_fx[i - 1] = sub( add( sub( s_q_fx, err_q_fx ), sub( 31, temp_q2 ) ), 1 ); + move16(); + + IF( LT_16( rc_q_fx[i - 1], 31 ) ) + { + + IF( GT_32( abs( rc_fx[i - 1] ), L_shr( 2146302532, sub( 31, rc_q_fx[i - 1] ) ) ) ) // 2146302532 = 0.99945f in Q31 + { + flag = 1; /* Test for unstable filter. If unstable keep old A(z) */ + move16(); + } + } + ELSE + { + IF( GT_32( abs( L_shr( rc_fx[i - 1], sub( rc_q_fx[i - 1], 31 ) ) ), 2146302532 ) ) // 2146302532 = 0.00045f in Q31 + { + flag = 1; /* Test for unstable filter. If unstable keep old A(z) */ + move16(); + } + } + + FOR( j = 1; j <= i / 2; j++ ) + { + l = sub( i, j ); + exp1 = sub( norm_l( rc_fx[sub( i, 1 )] ), 1 ); + exp2 = sub( norm_l( a_fx[l] ), 1 ); + rc_fx[sub( i, 1 )] = L_shl( rc_fx[sub( i, 1 )], exp1 ); + move32(); + rc_q_fx[sub( i, 1 )] = add( rc_q_fx[sub( i, 1 )], exp1 ); + move16(); + a_fx[l] = L_shl( a_fx[l], exp2 ); + move32(); + a_q_fx[l] = add( a_q_fx[l], exp2 ); + move16(); + + exp2 = sub( norm_l( a_fx[j] ), 1 ); + a_fx[j] = L_shl( a_fx[j], exp2 ); + move32(); + a_q_fx[j] = add( a_q_fx[j], exp2 ); + move16(); + + temp2 = Mpy_32_32( rc_fx[sub( i, 1 )], a_fx[l] ); + temp_q2 = sub( add( rc_q_fx[sub( i, 1 )], a_q_fx[l] ), 31 ); + + IF( LT_16( temp_q2, a_q_fx[j] ) ) + { + at_fx = L_add( L_shr( a_fx[j], sub( a_q_fx[j], temp_q2 ) ), temp2 ); + temp_q1 = temp_q2; + move16(); + } + ELSE + { + at_fx = L_add( a_fx[j], L_shr( temp2, sub( temp_q2, a_q_fx[j] ) ) ); + temp_q1 = a_q_fx[j]; + move16(); + } + + temp2 = Mpy_32_32( rc_fx[sub( i, 1 )], a_fx[j] ); + temp_q2 = sub( add( rc_q_fx[sub( i, 1 )], a_q_fx[j] ), 31 ); + + IF( LT_16( temp_q2, a_q_fx[l] ) ) + { + a_fx[l] = L_add( L_shr( a_fx[l], sub( a_q_fx[l], temp_q2 ) ), temp2 ); + move32(); + a_q_fx[l] = temp_q2; + move16(); + } + ELSE + { + a_fx[l] = L_add( a_fx[l], L_shr( temp2, sub( temp_q2, a_q_fx[l] ) ) ); + move16(); + } + a_fx[j] = at_fx; + move32(); + a_q_fx[j] = temp_q1; + move16(); + } + a_fx[i] = rc_fx[sub( i, 1 )]; + move32(); + a_q_fx[i] = rc_q_fx[sub( i, 1 )]; + move16(); + + exp1 = sub( norm_l( rc_fx[sub( i, 1 )] ), 1 ); + exp2 = norm_l( s ); + temp1 = Mpy_32_32( L_shl( rc_fx[sub( i, 1 )], exp1 ), L_shl( s, exp2 ) ); + temp_q1 = sub( add( add( rc_q_fx[sub( i, 1 )], exp1 ), add( s_q_fx, exp2 ) ), 31 ); + + IF( LT_16( temp_q1, err_q_fx ) ) + { + err_fx = L_add( L_shr( err_fx, sub( err_q_fx, temp_q1 ) ), temp1 ); + err_q_fx = temp_q1; + move16(); + } + ELSE + { + err_fx = L_add( err_fx, L_shr( temp1, sub( temp_q1, err_q_fx ) ) ); + } + + IF( LE_32( err_fx, 0 ) ) + { + err_fx = 21474836; // 0.01 in Q31 + move32(); + err_q_fx = Q31; + move16(); + } + IF( epsP_fx != NULL ) + { + epsP_fx[i] = err_fx; + move32(); + epsP_q_fx[i] = err_q_fx; + move16(); + } + } + + return ( flag ); +} + +/*-------------------------------------------------------------------* + * a2rc_fx() + * + * Convert from LPC to reflection coeff + *-------------------------------------------------------------------*/ + +static Word16 d_a2rc_fx( + const Word32 *a_fx, /* i : LPC coefficients */ + Word16 *a_q_fx, + Word32 *refl_fx, /* o : Reflection co-efficients */ + const Word16 lpcorder /* i : LPC order */ +) +{ + Word16 m, j, n; + Word32 ff_fx[LFE_PLC_LPCORD]; + Word32 km_fx, denom_fx, temp1, temp2, temp; + Word16 ff_q_fx[LFE_PLC_LPCORD], temp_q1, temp_q2, denom_q_fx, km_q_fx, temp_q; + Word16 exp1, exp2; + + FOR( m = 0; m < lpcorder; m++ ) + { + ff_fx[m] = -a_fx[m]; + move32(); + ff_q_fx[m] = a_q_fx[m]; + move32(); + } + + /* Initialization */ + FOR( m = sub( lpcorder, 1 ); m >= 0; m-- ) + { + km_fx = ff_fx[m]; + move32(); + km_q_fx = ff_q_fx[m]; + move16(); + IF( GE_64( W_shr( abs( km_fx ), sub( ff_q_fx[m], Q30 ) ), W_deposit32_l( ONE_IN_Q30 ) ) ) + { + FOR( j = 0; j < lpcorder; j++ ) + { + refl_fx[j] = 0; + move32(); + } + return 0; + } + + refl_fx[m] = -km_fx; + move32(); + + exp1 = norm_l( km_fx ); + temp1 = Mpy_32_32( L_shl( km_fx, exp1 ), L_shl( km_fx, exp1 ) ); + temp_q1 = sub( add( add( km_q_fx, exp1 ), add( km_q_fx, exp1 ) ), 31 ); + temp1 = L_sub( ONE_IN_Q30, L_shr( temp1, sub( temp_q1, 30 ) ) ); + denom_fx = L_deposit_l( BASOP_Util_Divide3232_Scale( ONE_IN_Q30, temp1, &temp_q1 ) ); + denom_q_fx = sub( 15, temp_q1 ); + + FOR( j = 0; j < m / 2; j++ ) + { + n = sub( sub( m, 1 ), j ); + + exp1 = norm_l( denom_fx ); + exp2 = sub( norm_l( ff_fx[j] ), 1 ); + temp1 = Mpy_32_32( L_shl( denom_fx, exp1 ), L_shl( ff_fx[j], exp2 ) ); + temp_q1 = sub( add( add( denom_q_fx, exp1 ), add( ff_q_fx[j], exp2 ) ), 31 ); + + exp2 = sub( norm_l( ff_fx[n] ), 1 ); + temp2 = Mpy_32_32( L_shl( denom_fx, exp1 ), L_shl( ff_fx[n], exp2 ) ); + temp_q2 = sub( add( add( denom_q_fx, exp1 ), add( ff_q_fx[n], exp2 ) ), 31 ); + + exp1 = norm_l( km_fx ); + exp2 = sub( norm_l( temp2 ), 1 ); + temp = Mpy_32_32( L_shl( km_fx, exp1 ), L_shl( temp2, exp2 ) ); + temp_q = sub( add( add( km_q_fx, exp1 ), add( temp_q2, exp2 ) ), 31 ); + + IF( LT_16( temp_q, temp_q1 ) ) + { + ff_fx[j] = L_add( L_shr( temp1, sub( temp_q1, temp_q ) ), temp ); + move32(); + ff_q_fx[j] = temp_q; + move16(); + } + ELSE + { + ff_fx[j] = L_add( temp1, L_shr( temp, sub( temp_q, temp_q1 ) ) ); + move32(); + ff_q_fx[j] = temp_q1; + move16(); + } + + exp1 = norm_l( km_fx ); + exp2 = sub( norm_l( temp1 ), 1 ); + temp = Mpy_32_32( L_shl( km_fx, exp1 ), L_shl( temp1, exp2 ) ); + temp_q = sub( add( add( km_q_fx, exp1 ), add( temp_q1, exp2 ) ), 31 ); + + IF( LT_16( temp_q, temp_q2 ) ) + { + ff_fx[n] = L_add( L_shr( temp2, sub( temp_q2, temp_q ) ), temp ); + move32(); + ff_q_fx[n] = temp_q; + move16(); + } + ELSE + { + ff_fx[n] = L_add( temp2, L_shr( temp, sub( temp_q, temp_q2 ) ) ); + move32(); + ff_q_fx[n] = temp_q2; + move16(); + } + } + + IF( m & 1 ) + { + exp1 = norm_l( denom_fx ); + exp2 = sub( norm_l( ff_fx[j] ), 1 ); + temp1 = Mpy_32_32( L_shl( denom_fx, exp1 ), L_shl( ff_fx[j], exp2 ) ); + temp_q1 = sub( add( add( denom_q_fx, exp1 ), add( ff_q_fx[j], exp2 ) ), 31 ); + + exp1 = norm_l( km_fx ); + exp2 = sub( norm_l( temp1 ), 1 ); + temp = Mpy_32_32( L_shl( km_fx, exp1 ), L_shl( temp1, exp2 ) ); + temp_q = sub( add( add( km_q_fx, exp1 ), add( temp_q1, exp2 ) ), 31 ); + + IF( LT_16( temp_q, temp_q1 ) ) + { + ff_fx[j] = L_add( L_shr( temp1, sub( temp_q1, temp_q ) ), temp ); + move32(); + ff_q_fx[j] = temp_q; + move16(); + } + ELSE + { + ff_fx[j] = L_add( temp1, L_shr( temp, sub( temp_q, temp_q1 ) ) ); + move32(); + ff_q_fx[j] = temp_q1; + move16(); + } + } + } + + return 1; +} + +static void d_syn_filt_fx( + const Word32 *a_fx, /* i : LP filter coefficients */ + Word16 *a_q_fx, + const Word16 m, /* i : order of LP filter */ + const Word32 *x_fx, /* i : input signal */ + Word32 *y_fx, /* o : output signal */ + Word16 *y_q_fx, + const Word16 l, /* i : size of filtering */ + const Word32 *mem_fx, /* i : initial filter states */ + Word16 mem_q_fx ) +{ + Word16 i, j; + Word32 buf_fx[LFE_PLC_LPCORD + LFE_PLC_RECLEN]; /* temporary synthesis buffer */ + Word32 s_fx, *yy_fx, temp; + Word16 yy_q_fx[LFE_PLC_LPCORD + LFE_PLC_RECLEN], exp1, exp2, s_q_fx, temp_q; + + yy_fx = &buf_fx[0]; + + /*------------------------------------------------------------------* + * copy initial filter states into synthesis buffer and do synthesis + *------------------------------------------------------------------*/ + FOR( i = 0; i < m; i++ ) + { + *yy_fx++ = mem_fx[i]; + move32(); + yy_q_fx[i] = mem_q_fx; + move16(); + } + + /*-----------------------------------------------------------------------* + * Do the filtering + *-----------------------------------------------------------------------*/ + + FOR( i = 0; i < l; i++ ) + { + s_fx = x_fx[i]; + move32(); + s_q_fx = Q31; + move16(); + FOR( j = 1; j <= m; j++ ) + { + exp1 = sub( norm_l( a_fx[j] ), 1 ); + exp2 = sub( norm_l( yy_fx[i - j] ), 1 ); + IF( GT_16( j, i ) ) + { + temp_q = mem_q_fx; + move16(); + } + ELSE + { + temp_q = yy_q_fx[sub( i, j )]; + move16(); + } + temp = Mpy_32_32( L_shl( a_fx[j], exp1 ), L_shl( yy_fx[sub( i, j )], exp2 ) ); + temp_q = sub( add( add( a_q_fx[j], exp1 ), add( temp_q, exp2 ) ), 31 ); + + IF( LT_16( s_q_fx, temp_q ) ) + { + s_fx = L_sub( s_fx, L_shr( temp, sub( temp_q, s_q_fx ) ) ); + } + ELSE + { + s_fx = L_sub( L_shr( s_fx, sub( s_q_fx, temp_q ) ), temp ); + s_q_fx = temp_q; + move16(); + } + } + yy_fx[i] = s_fx; + move32(); + yy_q_fx[i] = s_q_fx; + move16(); + y_fx[i] = L_shr( s_fx, sub( s_q_fx, Q5 ) ); + move32(); + } + *y_q_fx = Q5; + move16(); + + return; +} + +/*-----------------------------------------------------------------------------------------* + * Function check_stab_fx() + * + * LPC filter stability check applying given sharpening value delta + *-----------------------------------------------------------------------------------------*/ + +static Word16 check_stab_fx( + Word32 *a_fx, + Word16 *a_q_fx, + Word32 delta_fx, + Word16 delta_q_fx ) +{ + Word16 i; + Word16 stable; + + Word32 amod_fx[LFE_PLC_LPCORD], refl_fx[LFE_PLC_LPCORD]; + Word16 fac_q_fx, fac1_q_fx, amod_q_fx[LFE_PLC_LPCORD]; + Word16 exp1, exp2; + Word32 fac_fx, fac1_fx; + + exp1 = norm_l( delta_fx ); + delta_fx = L_shl( delta_fx, exp1 ); + delta_q_fx = add( delta_q_fx, exp1 ); + + IF( LT_16( delta_q_fx, 29 ) ) + { + fac_fx = L_add( L_shr( ONE_IN_Q29, sub( 29, delta_q_fx ) ), delta_fx ); + fac_q_fx = delta_q_fx; + move16(); + } + ELSE + { + fac_fx = L_add( ONE_IN_Q29, L_shr( delta_fx, sub( delta_q_fx, 29 ) ) ); + fac_q_fx = Q29; + move16(); + } + fac1_fx = fac_fx; + move32(); + fac1_q_fx = fac_q_fx; + move16(); + + FOR( i = 0; i < LFE_PLC_LPCORD; i++ ) + { + exp1 = norm_l( a_fx[i] ); + exp2 = norm_l( fac_fx ); + amod_fx[i] = Mpy_32_32( L_shl( a_fx[i], exp1 ), L_shl( fac_fx, exp2 ) ); + move32(); + amod_q_fx[i] = sub( add( add( a_q_fx[i], exp1 ), add( fac_q_fx, exp2 ) ), 31 ); + move16(); + + exp1 = norm_l( fac_fx ); + exp2 = norm_l( fac1_fx ); + fac_fx = Mpy_32_32( L_shl( fac_fx, exp1 ), L_shl( fac1_fx, exp2 ) ); + fac_q_fx = sub( add( add( fac_q_fx, exp1 ), add( fac1_q_fx, exp2 ) ), 31 ); + } + stable = d_a2rc_fx( amod_fx, amod_q_fx, refl_fx, LFE_PLC_LPCORD ); + + return stable; +} + +/*-----------------------------------------------------------------------------------------* + * Function find_max_delta_fx() + * + * Find maximum LPC filter sharpening by iteration to get a filter that is almost instable + *-----------------------------------------------------------------------------------------*/ + +static Word32 find_max_delta_fx( + Word32 *a_fx, + Word16 *a_q_fx, + Word16 *delta_q_fx ) +{ + Word16 stable; + Word16 eps_q_fx, fac_q_fx, exp1, exp2; + Word32 delta_fx, fac_fx, eps_fx, temp; + + delta_fx = 0; + move32(); + eps_fx = 21474836; // 0.01 in Q31 + move32(); + fac_fx = 1073741824; // 2 in Q29 + move32(); + eps_q_fx = Q31; + move16(); + fac_q_fx = Q29; + move16(); + + stable = FALSE; + move16(); + + WHILE( check_stab_fx( a_fx, a_q_fx, eps_fx, eps_q_fx ) ) + { + exp1 = norm_l( eps_fx ); + exp2 = norm_l( fac_fx ); + eps_fx = Mpy_32_32( L_shl( eps_fx, exp1 ), L_shl( fac_fx, exp2 ) ); + eps_q_fx = sub( add( add( eps_q_fx, exp1 ), add( fac_q_fx, exp2 ) ), 31 ); + stable = TRUE; + move16(); + } + fac_fx = 1073741824; // 0.5 in Q31 + move32(); + fac_q_fx = Q31; + move16(); + + IF( stable ) + { + exp1 = norm_l( eps_fx ); + exp2 = norm_l( fac_fx ); + eps_fx = Mpy_32_32( L_shl( eps_fx, exp1 ), L_shl( fac_fx, exp2 ) ); + eps_q_fx = sub( add( add( eps_q_fx, exp1 ), add( fac_q_fx, exp2 ) ), 31 ); + } + + WHILE( !stable ) + { + exp1 = norm_l( eps_fx ); + exp2 = norm_l( fac_fx ); + eps_fx = Mpy_32_32( L_shl( eps_fx, exp1 ), L_shl( fac_fx, exp2 ) ); + eps_q_fx = sub( add( add( eps_q_fx, exp1 ), add( fac_q_fx, exp2 ) ), 31 ); + + stable = check_stab_fx( a_fx, a_q_fx, eps_fx, eps_q_fx ); + } + + /* must be stable with current eps */ + *delta_q_fx = sub( norm_l( eps_fx ), 1 ); + delta_fx = L_shl( eps_fx, *delta_q_fx ); + *delta_q_fx = add( eps_q_fx, *delta_q_fx ); + + exp1 = norm_l( eps_fx ); + exp2 = norm_l( fac_fx ); + eps_fx = Mpy_32_32( L_shl( eps_fx, exp1 ), L_shl( fac_fx, exp2 ) ); + eps_q_fx = sub( add( add( eps_q_fx, exp1 ), add( fac_q_fx, exp2 ) ), 31 ); + + WHILE( 1 ) + { + IF( LT_16( *delta_q_fx, eps_q_fx ) ) + { + delta_fx = L_add( delta_fx, L_shr( eps_fx, sub( eps_q_fx, *delta_q_fx ) ) ); + } + ELSE + { + delta_fx = L_add( L_shr( delta_fx, sub( *delta_q_fx, eps_q_fx ) ), eps_fx ); + *delta_q_fx = eps_q_fx; + move16(); + } + stable = check_stab_fx( a_fx, a_q_fx, delta_fx, *delta_q_fx ); + + IF( !stable ) + { + temp = abs( eps_fx ); + IF( GT_32( L_shr( temp, sub( eps_q_fx, 31 ) ), EPS_STOP_Q31 ) ) + { + exp1 = norm_l( -temp ); + exp2 = norm_l( fac_fx ); + eps_fx = Mpy_32_32( L_shl( -temp, exp1 ), L_shl( fac_fx, exp2 ) ); + eps_q_fx = sub( add( add( eps_q_fx, exp1 ), add( fac_q_fx, exp2 ) ), 31 ); + } + ELSE + { + eps_fx = -abs( eps_fx ); + } + } + ELSE + { + temp = abs( eps_fx ); + IF( LT_32( L_shr( temp, sub( eps_q_fx, 31 ) ), EPS_STOP_Q31 ) ) + { + BREAK; + } + + exp1 = norm_l( temp ); + exp1 = norm_l( fac_fx ); + eps_fx = Mpy_32_32( L_shl( temp, exp1 ), L_shl( fac_fx, exp2 ) ); + eps_q_fx = sub( add( add( eps_q_fx, exp1 ), add( fac_q_fx, exp2 ) ), 31 ); + } + } + + return delta_fx; +} + +/*-----------------------------------------------------------------------------------------* + * Function recover_samples_fx() + * + * recover lost samples by extrapolation of signal buffer + *-----------------------------------------------------------------------------------------*/ + +static void recover_samples_fx( + const Word16 bfi_count, + const Word32 *outbuf_fx, + Word16 outbuf_q_fx, + Word32 *rec_frame_fx, + Word16 *rec_frame_q_fx ) +{ + Word16 i; + Word32 d_outbuf_fx[LFE_PLC_BUFLEN], d_a_fx[LFE_PLC_LPCORD + 1], d_pee_fx[LFE_PLC_LPCORD + 1]; + Word16 d_r_q_fx[LFE_PLC_LPCORD + 1], d_a_q_fx[LFE_PLC_LPCORD + 1], d_pee_q_fx[LFE_PLC_LPCORD + 1]; + Word32 d_r_fx[LFE_PLC_LPCORD + 1], zeroes_fx[LFE_PLC_RECLEN]; + Word32 delta_fx, fac_fx, att_fx, temp; + Word16 delta_q_fx, fac_q_fx, att_q_fx, temp_q, exp1, exp2; + + Copy32( outbuf_fx, d_outbuf_fx, LFE_PLC_BUFLEN ); + + d_autocorr_fx( d_outbuf_fx, outbuf_q_fx, d_r_fx, d_r_q_fx, LFE_PLC_LPCORD, LFE_PLC_BUFLEN, d_hamm_lfe_plc_fx, 0, 1, 1 ); + + IF( LT_64( W_shr( d_r_fx[0], sub( d_r_q_fx[0], Q19 ) ), W_deposit32_l( Mpy_32_32( POW_THR_Q50, LFE_PLC_BUFLEN ) ) ) ) + { + set_zero_fx( rec_frame_fx, LFE_PLC_RECLEN ); + return; + } + + d_lev_dur_fx( d_a_fx, d_a_q_fx, d_r_fx, d_r_q_fx, LFE_PLC_LPCORD, d_pee_fx, d_pee_q_fx ); + + delta_fx = find_max_delta_fx( d_a_fx + 1, d_a_q_fx + 1, &delta_q_fx ); + + IF( LT_16( delta_q_fx, Q29 ) ) + { + fac_fx = L_add( L_shr( ONE_IN_Q29, sub( Q29, delta_q_fx ) ), delta_fx ); + fac_q_fx = delta_q_fx; + move16(); + } + ELSE + { + fac_fx = L_add( ONE_IN_Q29, L_shr( delta_fx, sub( delta_q_fx, Q29 ) ) ); + fac_q_fx = Q29; + move16(); + } + att_fx = ONE_IN_Q30; + move32(); + att_q_fx = Q30; + move16(); + + IF( GE_16( bfi_count, LFE_PLC_MUTE_THR ) ) + { + att_fx = LFE_PLC_BURST_ATT_Q31; + move32(); + fac_fx = Mpy_32_32( fac_fx, att_fx ); + fac_q_fx = sub( add( fac_q_fx, att_q_fx ), 31 ); + } + + FOR( i = 1; i <= LFE_PLC_LPCORD; i++ ) + { + d_a_fx[i] = Mpy_32_32( d_a_fx[i], fac_fx ); + move32(); + d_a_q_fx[i] = sub( add( d_a_q_fx[i], fac_q_fx ), 31 ); + move16(); + IF( LT_16( delta_q_fx, Q30 ) ) + { + temp = L_add( L_shr( ONE_IN_Q30, sub( Q30, delta_q_fx ) ), delta_fx ); + temp_q = delta_q_fx; + move16(); + } + ELSE + { + temp = L_add( ONE_IN_Q30, L_shr( delta_fx, sub( delta_q_fx, Q30 ) ) ); + temp_q = Q30; + move16(); + } + exp1 = norm_l( att_fx ); + exp2 = norm_l( temp ); + temp = Mpy_32_32( L_shl( att_fx, exp1 ), L_shl( temp, exp2 ) ); + temp_q = sub( add( add( att_q_fx, exp1 ), add( temp_q, exp2 ) ), 31 ); + + exp1 = norm_l( fac_fx ); + exp2 = norm_l( temp ); + fac_fx = Mpy_32_32( L_shl( fac_fx, exp1 ), L_shl( temp, exp2 ) ); + fac_q_fx = sub( add( add( fac_q_fx, exp1 ), add( temp_q, exp2 ) ), 31 ); + } + + set_zero_fx( zeroes_fx, LFE_PLC_RECLEN ); + + d_syn_filt_fx( d_a_fx, d_a_q_fx, LFE_PLC_LPCORD, zeroes_fx, rec_frame_fx, rec_frame_q_fx, LFE_PLC_RECLEN, outbuf_fx + LFE_PLC_BUFLEN - LFE_PLC_LPCORD, outbuf_q_fx ); + + return; +} + +/*-----------------------------------------------------------------------------------------* + * Function ivas_lfe_tdplc_fx() + * + * MDCT interface recover lost samples by extrapolation of signal buffer + *-----------------------------------------------------------------------------------------*/ + +void ivas_lfe_tdplc_fx( + LFE_DEC_HANDLE hLFE, /* i/o: LFE decoder handle */ + const Word32 *prevsynth, /* i : previous frame synthesis */ + Word32 *ytda, /* o : output time-domain buffer */ + const Word16 output_frame /* i : output frame length */ +) +{ + Word32 rec_frame_us_fx[LFE_PLC_RECLEN_48K], input_tda_fx[L_FRAME48k]; + Word32 rec_frame_fx[LFE_PLC_RECLEN], prevsynth_fx[LFE_PLC_BUFLEN]; + Word16 rec_frame_us_16_fx[LFE_PLC_RECLEN_48K], mem_fx[2 * LFE_PLC_FDEL / LFE_PLC_DSF], rec_frame_16_fx[LFE_PLC_RECLEN]; + Word16 prevsynth_16_fx[LFE_PLC_BUFLEN]; + const Word32 *pWindow_coeffs_fx; + Word32 output_Fs; + Word16 i, fade_len, full_len, dct_len, zero_pad_len, plc_fdel, rec_frame_len; + Word16 fdel_dsf_ratio, prevsynth_q_fx, rec_frame_q, temp, temp_q, idx, exp; + + output_Fs = L_mult0( output_frame, FRAMES_PER_SEC ); + fade_len = hLFE->pWindow_state->fade_len; + move16(); + full_len = hLFE->pWindow_state->full_len; + move16(); + dct_len = hLFE->pWindow_state->dct_len; + move16(); + zero_pad_len = hLFE->pWindow_state->zero_pad_len; + move16(); + pWindow_coeffs_fx = hLFE->pWindow_state->pWindow_coeffs_fx; + + temp = BASOP_Util_Divide3232_Scale( Mpy_32_32( L_shl( LFE_PLC_FDEL, 22 ), L_shl( output_Fs, 9 ) ), 48000, &temp_q ); + plc_fdel = shr( temp, sub( 15, temp_q ) ); + + temp = BASOP_Util_Divide3232_Scale( output_Fs, 48000, &temp_q ); + rec_frame_len = shl( mult( LFE_PLC_RECLEN_48K, temp ), temp_q ); + + Copy32( prevsynth, prevsynth_fx, LFE_PLC_BUFLEN ); + exp = L_norm_arr( prevsynth_fx, LFE_PLC_BUFLEN ); + scale_sig32( prevsynth_fx, LFE_PLC_BUFLEN, exp ); + prevsynth_q_fx = add( Q9, exp ); + move16(); + + recover_samples_fx( hLFE->bfi_count, prevsynth_fx, prevsynth_q_fx, rec_frame_fx, &rec_frame_q ); + + fdel_dsf_ratio = shl( div_l( LFE_PLC_FDEL, LFE_PLC_DSF ), 1 ); + set_s( mem_fx, 0, shl( fdel_dsf_ratio, 1 ) ); + + Copy_Scale_sig_32_16( prevsynth_fx, prevsynth_16_fx, LFE_PLC_BUFLEN, -16 ); // Q5 = Q21 - Q16 + Copy_Scale_sig_32_16( rec_frame_fx, rec_frame_16_fx, LFE_PLC_RECLEN, 0 ); // Q5 + + modify_Fs_fx( prevsynth_16_fx + LFE_PLC_BUFLEN - LFE_PLC_FDEL / LFE_PLC_DSF, LFE_PLC_FDEL / LFE_PLC_DSF, LFE_PLC_FS, rec_frame_us_16_fx, 48000, mem_fx, 0 ); + modify_Fs_fx( rec_frame_16_fx, LFE_PLC_RECLEN, LFE_PLC_FS, rec_frame_us_16_fx, 48000, mem_fx, 0 ); + /*samples are generated with 48k sampling rate + and then converted to required sampling rate by simple decimation + as signal is already bandlimited*/ + + /*decimation to correct sampling rate*/ + IF( NE_32( output_Fs, 48000 ) ) + { + FOR( i = 0; i < rec_frame_len; i++ ) + { + idx = BASOP_Util_Divide3232_Scale( Mpy_32_32( L_shl( i, 16 ), L_shl( 44100, 15 ) ), output_Fs, &temp_q ); + idx = shr( idx, add( sub( 15, temp_q ), 1 ) ); + rec_frame_us_16_fx[i] = rec_frame_us_16_fx[idx]; + move16(); + } + } + + Copy_Scale_sig_16_32( rec_frame_us_16_fx, rec_frame_us_fx, LFE_PLC_RECLEN_48K, 5 ); // Q10 = rec_frame_q + 5 + + FOR( i = 0; i < 2; i++ ) + { + ivas_dct_windowing_fx( fade_len, full_len, dct_len, zero_pad_len, pWindow_coeffs_fx, output_frame, input_tda_fx, rec_frame_us_fx + plc_fdel, rec_frame_us_fx + add( add( plc_fdel, fade_len ), i_mult( i, dct_len ) ) ); + ivas_tda_fx( input_tda_fx, ytda + i * dct_len, dct_len ); + } + + return; +} +#endif \ No newline at end of file