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