diff --git a/Workspace_msvc/lib_dec.vcxproj b/Workspace_msvc/lib_dec.vcxproj index 04b61751f69cd4a23646ee380127a863447f39a2..8aeb0435cf299e0af585bf7f3bb30c71930745b5 100644 --- a/Workspace_msvc/lib_dec.vcxproj +++ b/Workspace_msvc/lib_dec.vcxproj @@ -321,6 +321,7 @@ + @@ -331,7 +332,9 @@ + + diff --git a/lib_com/basop_util.c b/lib_com/basop_util.c index 538c620cf347ea87d32bb48b8cc8437e0ce9298b..90b3e6a09bc7520dad794ca4adbb4f1989838d8a 100644 --- a/lib_com/basop_util.c +++ b/lib_com/basop_util.c @@ -516,6 +516,10 @@ Word32 Sqrt32( /*!< output mantissa */ { Word16 preShift, e; + if (mantissa < 0) + { + mantissa = mantissa; + } assert(mantissa >= 0); /* normalize */ @@ -1237,6 +1241,35 @@ Word16 getCosWord16(Word16 theta) return result; } +Word16 getSinWord16(Word16 theta) +{ + Word16 sine; + Word32 theta_new = L_sub(EVS_PI_BY_2_FX, theta); + Word16 l_theta; + IF(GT_32(theta_new, EVS_PI_FX)) + { + l_theta = extract_l(L_sub(L_sub(theta_new, EVS_PI_FX), EVS_PI_FX )); + } + ELSE IF(LT_32(theta_new, -EVS_PI_FX)) + { + l_theta = extract_l(L_add(L_add(theta_new, EVS_PI_FX), EVS_PI_FX)); + } + ELSE + { + l_theta = extract_l(theta_new); + } + sine = getCosWord16(l_theta); + IF (EQ_16(sine, ONE_IN_Q14)) + { + sine = MAX_16; + } + ELSE + { + sine = shl(sine, 1); + } + return sine; +} + Word16 getCosWord16R2( Word16 theta ) { diff --git a/lib_com/basop_util.h b/lib_com/basop_util.h index f392a888f2623c94a85207ed56c5923a747d35d0..61b170af39e05cf657c5cfc8a228b35d6e2edad3 100644 --- a/lib_com/basop_util.h +++ b/lib_com/basop_util.h @@ -456,6 +456,7 @@ Word32 L_mult0_3216(Word32 x, /*!< : Multiplier */ /* Calculate sin/cos. Angle in 2Q13 format, result has exponent = 1 */ Word16 getCosWord16(Word16 theta); +Word16 getSinWord16(Word16 theta); Word32 getCosWord32(Word32 theta); /** * \brief calculate cosine of angle. Tuned for ISF domain. diff --git a/lib_com/cnst.h b/lib_com/cnst.h index 2d831cbc39812c1f16a7861580507c2ddd5c5cc5..1717c8d7d70318912ceb4cc9663a527fcf075901 100644 --- a/lib_com/cnst.h +++ b/lib_com/cnst.h @@ -211,6 +211,9 @@ enum{ #define INV_LOG_2 1.442695040888963f /* 1/log(2) */ #define INV_SQRT_2 0.70710676908493f /* 1/sqrt(2) */ #define INV_SQRT_2_Q15 23170 /* 1/sqrt(2) in Q15 */ +#ifdef IVAS_FLOAT_FIXED +#define INV_SQRT_2_FX (Word16)(0x5A82) /* 1/sqrt(2) */ +#endif #define MAX_V_MULT_MAT 100 /* maximum array length for the function v_mult_mat() */ @@ -546,6 +549,10 @@ enum *----------------------------------------------------------------------------------*/ #define FRAMES_PER_SEC 50 +#ifdef IVAS_FLOAT_FIXED +#define ONE_BY_FRAMES_PER_SEC ((Word32)(0x028F5C29)) +#define FRAMES_PER_SEC_BY_2 (FRAMES_PER_SEC >> 1) +#endif #define INV_FRAME_PER_SEC_Q15 656 #define INV_FR_P_S_MX_PRM_SPL_SBFR_Q15 164 #define FRAME_SIZE_NS 20000000L @@ -1669,6 +1676,10 @@ enum #define OUTMAX_INV 0.000030517578125f /* 1/2^15 */ #define OUTMAX_INV_FX 65536 /* 1/2^15 (Q31) */ +#ifdef IVAS_FLOAT_FIXED +#define ONE_BY_NS2A_8K_ST_DFT32MS_OVL_NS (Word16)(0x051E) +#define OUTMAX_INV_FX_16 (Word16)(0x0001) /* 1/2^15 */ +#endif #define OUTMAX_SQ 1073741824.f /* 2^30 */ #define OUTMAX_SQ_INV 0.00000000093132257461547852f /* 1/2^30 */ @@ -1970,6 +1981,9 @@ typedef enum _DCTTYPE #define EPSILON 0.000000000000001f #define EPSILON_FX 0 +#ifdef IVAS_FLOAT_FIXED +#define EPSILON_FIX (1) +#endif #define MAX_SEGMENT_LENGTH 480 #define NUM_TIME_SWITCHING_BLOCKS 4 @@ -2928,6 +2942,9 @@ enum #define EVS_PI 3.14159265358979323846264338327950288f #define EVS_PI_FX 25736 /* pi in Q13 */ +#define EVS_2PI_FX 51472 /* 2 * pi in Q13 */ +#define EVS_PI_BY_2_FX (Word16)(0x3244) +//#define EVS_PI_FX (Word16)(0x6488) #define LG10 24660 /* 10*log10(2) in Q13 */ diff --git a/lib_com/fd_cng_com.c b/lib_com/fd_cng_com.c index cdb33684a1645ce2aa9ca1dfd116b994f5c8eb94..f584ad7aa6eda68749e0b0d984af57a59ef8438c 100644 --- a/lib_com/fd_cng_com.c +++ b/lib_com/fd_cng_com.c @@ -1213,6 +1213,28 @@ Word32 rand_gauss_fx( return temp; } #endif +#ifdef IVAS_FLOAT_FIXED +/*------------------------------------------------------------------- + * rand_gauss_fix() + * + * Random generator with Gaussian distribution with mean 0 and std 1 + *-------------------------------------------------------------------*/ + +Word16 rand_gauss_fix( + Word16 *x, + Word16 *seed ) +{ + Word32 temp; + + temp = shr(own_random( seed ), Q2); + temp = L_add(temp, shr(own_random( seed ), Q2)); + temp = L_add(temp, shr(own_random( seed ), Q2)); + + *x = (Word16)temp; + + return (Word16)temp; +} +#endif /*------------------------------------------------------------------- * lpc_from_spectrum_flt() diff --git a/lib_com/fft_fx.c b/lib_com/fft_fx.c index f8fb4c139b644cedfbc80c92067e857823269fec..a6dd4eef319d6105b9e60dee572df8689a14fa25 100644 --- a/lib_com/fft_fx.c +++ b/lib_com/fft_fx.c @@ -5348,8 +5348,8 @@ void rfft_fx( SWITCH( sizeOfFft2 ) { case 80: - s1 = 409; - s2 = -409; + s1 = 410; + s2 = -410; BREAK; case 128: s1 = 256; diff --git a/lib_com/ivas_cnst.h b/lib_com/ivas_cnst.h index 12bbf80360060a36a95f5136a51122adb7489daf..5da108b96a6bed7ca60f267e16837329152b3205 100644 --- a/lib_com/ivas_cnst.h +++ b/lib_com/ivas_cnst.h @@ -633,6 +633,9 @@ typedef enum #define SBA_DIRAC_NRG_SMOOTH_LONG 10 #define SBA_DIRAC_NRG_SMOOTH_SHORT 3 +#define SBA_DIRAC_NRG_SMOOTH_SHORT_BY_LONG_FX ((Word16)0x2666) +#define SBA_DIRAC_NRG_SMOOTH_LONG_BY_LONG_SHORT_FX ((Word32)0x0000B6D8) + /* PLC for DFT Stereo residual */ #define STEREO_DFT_RES_N_PEAKS_MAX 15 /*Maximum number of peaks within residual signal in each frame (res_cod_band_max == 6 in 48kHz)*/ diff --git a/lib_com/ivas_prot.h b/lib_com/ivas_prot.h index 826fbb1ae32a69f35d9ff55efc838849fb68cc89..12e75971c7099dcecf5e2a8ce2013188edaf542c 100644 --- a/lib_com/ivas_prot.h +++ b/lib_com/ivas_prot.h @@ -3019,6 +3019,14 @@ int16_t check_bounds_s( const int16_t high /* i : High limit */ ); +#ifdef IVAS_FLOAT_FIXED +Word32 check_bounds_l( + const Word32 value, /* i : Input value */ + const Word32 low, /* i : Low limit */ + const Word32 high /* i : High limit */ +); +#endif + ivas_error stereo_memory_enc( CPE_ENC_HANDLE hCPE, /* i : CPE encoder structure */ const int32_t input_Fs, /* i : input sampling rate */ diff --git a/lib_com/ivas_prot_fx.h b/lib_com/ivas_prot_fx.h index b18dcbdd2eccb37db120e43dcf022a5cbf2c135c..330809a16c8e1901945074a3b8c7df214f401025 100644 --- a/lib_com/ivas_prot_fx.h +++ b/lib_com/ivas_prot_fx.h @@ -388,6 +388,51 @@ Word16 get_igf_startline( const Word16 L_frameTCX /* i : full band frame length */ ); +#ifdef IVAS_FLOAT_FIXED +void stereo_dft_dec_reset_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft /* i/o: decoder DFT stereo handle */ +); + +void stereo_dft_dec_update_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word16 output_frame, /* i : output frame length */ + const Word16 sba_dirac_stereo_flag /* i : signal stereo output for SBA DirAC */ +); +void stereo_dft_res_ecu_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: Decoder DFT stereo handle */ + Word32 *pDFT_RES, /* i/o: residual signal */ + Word32 *const DFT_PRED_RES, /* i/o: residual prediction signal */ + const Word16 k, /* i : Subframe index */ + const Word16 output_frame, /* i : Output frame length */ + const Word16 prev_bfi, /* i : Previous BFI */ + const Word32 dmx_nrg, /* i : Down-mix energy */ + Word16 *num_plocs, /* i/o: Number of peak locations */ + Word16 *plocs, /* i/o: Peak locations (bin) */ + Word32 *plocsi, /* i/o: Peak locations (fractional) */ + Word32 *input_mem /* o : Residual DFT buffer input mem */ +); +void stereo_dft_res_subst_spec_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: Decoder DFT stereo handle */ + Word32 *pDFT_RES, /* i/o: residual signal */ + const Word32 *const DFT_PRED_RES, /* i : residual prediction signal */ + const Word16 time_offs, /* i : Time offset for phase adjustment*/ + const Word16 L_res, /* i : bandwidth of residual signal */ + const Word16 L_ana, /* i : Length of FFT analysis */ + const Word16 k, /* i : Subframe index */ + Word16 *num_plocs, /* i/o: Number of peak locations */ + Word16 *plocs, /* i/o: Peak locations (bin) */ + Word32 *plocsi, /* i/o: Peak locations (fractional) */ + const Word16 analysis_flag /* i : Flag for running peak analysis */ +); +void stereo_dft_res_ecu_burst_att_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: Decoder DFT stereo handle */ + Word32 *pDFT_RES, /* i/o: residual signal /att. residual */ + const Word32 dmx_nrg, /* i : dmx energy of current frame */ + const Word16 L_res, /* i : Bandwidth of residual */ + const Word16 L_ana /* i : Length of FFT analysis */ +); +#endif + void stereo_dft_dec_analyze_fx( CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ const Word32 *input_fx, /* i : input signal */ @@ -408,6 +453,12 @@ void filter_with_allpass_fx( basic_allpass_t *ap /* i/o: basic allpass structure */ ); +Word32 stereo_dft_dmx_swb_nrg_fx( + const Word32 *dmx_k0, /* i : first subframe spectrum */ + const Word32 *dmx_k1, /* i : second subframe spectrum */ + const int16_t frame_length /* i : frame lanegth */ +); + void stereo_dft_dec_core_switching_fx( CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ Word32 output_fx[], /* i/o: synthesis @internal Fs */ @@ -899,6 +950,44 @@ void ivas_mono_downmix_render_passive_fx( Word32 *output_f_fx[], /* i/o: synthesized core-coder transport channels/mono output */ const Word16 output_frame /* i : output frame length */ ); +void ivas_sba_dirac_stereo_smooth_parameters_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + ivas_spar_md_dec_state_t *hMdDec, /* i/o: SPAR MD handle for upmixing */ + const Word16 cross_fade_start_offset, /* i : SPAR mixer delay compensation */ + const Word32 output_Fs, /* i : Fs for delay calculation */ + const Word16 num_md_sub_frames /* i : number of subframes in mixing matrix */ +); + +void stereo_dft_dec_synthesize_fx( + CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ + Word32 DFT[CPE_CHANNELS][STEREO_DFT_BUF_MAX], /* i : DFT buffers */ + const Word16 chan, /* i : channel number */ + Word32 output[L_FRAME48k], /* o : output synthesis signal */ + const Word16 output_frame /* i : output frame length */ +); + +void stereo_dft_dec_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + Decoder_State *st0, /* i/o: decoder state structure */ + Word32 DFT[CPE_CHANNELS][STEREO_DFT_BUF_MAX], /* i/o: DFT buffers */ + Word32 *input_mem, /* i/o: mem of buffer DFT analysis */ + STEREO_CNG_DEC_HANDLE hStereoCng, /* i/o: Stereo CNG data structure */ + const Word16 sba_dirac_stereo_flag, /* i : signal stereo output for SBA DirAC */ + const Word16 sba_mono_flag, /* i : signal mono output for SBA DirAC */ + ivas_spar_md_dec_state_t *hMdDec, /* i : SPAR MD handle for upmixing */ + const Word16 cross_fade_start_offset, /* i : SPAR mixer delay compensation */ + const Word32 output_Fs, /* i : Fs for delay calculation */ + const Word16 nchan_transport, /* i : number of transpor channels */ + const Word16 num_md_sub_frames /* i : number of MD subframes */ +); + +void synchro_synthesis_fx( + const Word32 ivas_total_brate, /* i : IVAS total bitrate */ + CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ + Word32 *output[CPE_CHANNELS], /* i/o: output synthesis signal */ + const Word16 output_frame, /* i : Number of samples */ + const Word16 sba_dirac_stereo_flag /* i : signal stereo output for SBA DirAC */ +); void ivas_ls_setup_conversion_fx( Decoder_Struct *st_ivas, /* i : IVAS decoder structure */ @@ -1153,5 +1242,11 @@ void stereo_icBWE_dec_fx( const Word16 output_frame, /* i : frame length */ Word16 *Q_syn ); +void ivas_sba_dirac_stereo_dec_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + Word32 *output[CPE_CHANNELS], /* i/o: output synthesis signal */ + const Word16 output_frame, /* i : output frame length per channel */ + const Word16 mcmasa /* i : McMASA flag */ +); #endif diff --git a/lib_com/ivas_rom_com_fx.c b/lib_com/ivas_rom_com_fx.c index aca7348381578b7c49e774ed932d29b6c315490b..e10ce9db2a42dc1c97dbca5a247c2e362ecc3057 100644 --- a/lib_com/ivas_rom_com_fx.c +++ b/lib_com/ivas_rom_com_fx.c @@ -309,6 +309,179 @@ const Word16 gridEq_Table[NO_THETA16_MAX] = { 91, 85, 81, 75, 69, 64, 59, 53, 48, 43, 37, 32, 26, 21, 15, 10, 1 }; +const Word16 dft_res_cod_alpha_fx[STEREO_DFT_BAND_MAX] = +{ + SHC(0x6666), SHC(0x6666), SHC(0x4000), SHC(0x4000), SHC(0x2666), SHC(0x2666), SHC(0x199A), SHC(0x199A) +}; + +const Word32 dft_res_gains_q_fx[][2] = { + /* quantization points for joint quantization of prediction gain and residual energy */ + + /* column 1 (|ILD| = 0): */ + { (Word32)( 0x00000000 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x00000000 ), (Word32)( 0x0ef94420 ) }, + { (Word32)( 0x00000000 ), (Word32)( 0x1d0e0a80 ) }, + { (Word32)( 0x00000000 ), (Word32)( 0x2b9bd400 ) }, + { (Word32)( 0x00000000 ), (Word32)( 0x3b765780 ) }, + { (Word32)( 0x00000000 ), (Word32)( 0x4d733a80 ) }, + { (Word32)( 0x00000000 ), (Word32)( 0x635c2900 ) }, + { (Word32)( 0x00000000 ), (Word32)( 0x7fffffff ) }, + + + /* column 2 (|ILD| = 2): */ + { (Word32)( 0x0eabf770 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x0edeb100 ), (Word32)( 0x0ec636b0 ) }, + { (Word32)( 0x0f6ad710 ), (Word32)( 0x1ca758a0 ) }, + { (Word32)( 0x10598e20 ), (Word32)( 0x2af85940 ) }, + { (Word32)( 0x11c9a340 ), (Word32)( 0x3a83dbc0 ) }, + { (Word32)( 0x13f290a0 ), (Word32)( 0x4c110a00 ) }, + { (Word32)( 0x1753e700 ), (Word32)( 0x6148cb80 ) }, + { (Word32)( 0x1cf68be0 ), (Word32)( 0x7cae2100 ) }, + + /* column 3 (|ILD| = 4): */ + { (Word32)( 0x1cf68be0 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x1d56c0e0 ), (Word32)( 0x0e327670 ) }, + { (Word32)( 0x1e600b00 ), (Word32)( 0x1b7ea1c0 ) }, + { (Word32)( 0x20224680 ), (Word32)( 0x2921ab40 ) }, + { (Word32)( 0x22d41b80 ), (Word32)( 0x37cd1c80 ) }, + { (Word32)( 0x26d6c300 ), (Word32)( 0x4821ea00 ) }, + { (Word32)( 0x2d06ab00 ), (Word32)( 0x5b738e80 ) }, + { (Word32)( 0x371ad200 ), (Word32)( 0x73880100 ) }, + + /* column 4 (|ILD| = 6): */ + { (Word32)( 0x2a881e40 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x2b0c77c0 ), (Word32)( 0x0d4ce3e0 ) }, + { (Word32)( 0x2c785b40 ), (Word32)( 0x19b35b00 ) }, + { (Word32)( 0x2ede2ac0 ), (Word32)( 0x264d8fc0 ) }, + { (Word32)( 0x3281c300 ), (Word32)( 0x33aa8200 ) }, + { (Word32)( 0x37d88c00 ), (Word32)( 0x4238d200 ) }, + { (Word32)( 0x3fe87900 ), (Word32)( 0x52e04c00 ) }, + { (Word32)( 0x4c9afe00 ), (Word32)( 0x668bb080 ) }, + + /* column 5 (|ILD| = 8): */ + { (Word32)( 0x371ad200 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x37b7ae40 ), (Word32)( 0x0c2aed10 ) }, + { (Word32)( 0x396555c0 ), (Word32)( 0x17722e20 ) }, + { (Word32)( 0x3c34a880 ), (Word32)( 0x22c73ac0 ) }, + { (Word32)( 0x406b8b80 ), (Word32)( 0x2e942d40 ) }, + { (Word32)( 0x467f0200 ), (Word32)( 0x3b162b00 ) }, + { (Word32)( 0x4f700480 ), (Word32)( 0x48d04600 ) }, + { (Word32)( 0x5cfa3780 ), (Word32)( 0x57f90500 ) }, + + /* column 6 (|ILD| = 10): */ + { (Word32)( 0x427ec780 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x43283900 ), (Word32)( 0x0ae47560 ) }, + { (Word32)( 0x44f66200 ), (Word32)( 0x14ec3980 ) }, + { (Word32)( 0x47f59480 ), (Word32)( 0x1edf6980 ) }, + { (Word32)( 0x4c655a00 ), (Word32)( 0x29068980 ) }, + { (Word32)( 0x52ac0800 ), (Word32)( 0x3376a300 ) }, + { (Word32)( 0x5ba86100 ), (Word32)( 0x3e65f940 ) }, + { (Word32)( 0x68ba3000 ), (Word32)( 0x49984a00 ) }, + + + /* column 7 (|ILD| = 13): */ + { (Word32)( 0x512c1700 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x51d52c00 ), (Word32)( 0x08e72540 ) }, + { (Word32)( 0x539f3400 ), (Word32)( 0x11048160 ) }, + { (Word32)( 0x568dc100 ), (Word32)( 0x18e88e00 ) }, + { (Word32)( 0x5aceff00 ), (Word32)( 0x20b5d480 ) }, + { (Word32)( 0x60a8b900 ), (Word32)( 0x285c4640 ) }, + { (Word32)( 0x68b5bb00 ), (Word32)( 0x2fd0a680 ) }, + { (Word32)( 0x73c83200 ), (Word32)( 0x369374c0 ) }, + + /* column 8 (|ILD| = 16): */ + { (Word32)( 0x5cfa3780 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x5d92fb00 ), (Word32)( 0x0705b7d0 ) }, + { (Word32)( 0x5f2e2f80 ), (Word32)( 0x0d5c7470 ) }, + { (Word32)( 0x61c7ef00 ), (Word32)( 0x136909a0 ) }, + { (Word32)( 0x657c8900 ), (Word32)( 0x19376500 ) }, + { (Word32)( 0x6a742980 ), (Word32)( 0x1ea95000 ) }, + { (Word32)( 0x710eb280 ), (Word32)( 0x239c9d40 ) }, + { (Word32)( 0x79ba2380 ), (Word32)( 0x27944240 ) }, + + + /* column 9 (|ILD| = 19): */ + { (Word32)( 0x662c9080 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x66ad4f80 ), (Word32)( 0x0562c778 ) }, + { (Word32)( 0x6805ff00 ), (Word32)( 0x0a34e330 ) }, + { (Word32)( 0x6a2e3c80 ), (Word32)( 0x0ebb8800 ) }, + { (Word32)( 0x6d350080 ), (Word32)( 0x12f75540 ) }, + { (Word32)( 0x712ddc00 ), (Word32)( 0x16c8ffc0 ) }, + { (Word32)( 0x76508b00 ), (Word32)( 0x1a0c7c00 ) }, + { (Word32)( 0x7cd13980 ), (Word32)( 0x1c5dd900 ) }, + + /* column 10 (|ILD| = 22): */ + { (Word32)( 0x6d295e80 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x6d909f00 ), (Word32)( 0x040afa30 ) }, + { (Word32)( 0x6ea3ce80 ), (Word32)( 0x07a30120 ) }, + { (Word32)( 0x70590800 ), (Word32)( 0x0af74470 ) }, + { (Word32)( 0x72b6c780 ), (Word32)( 0x0e03d570 ) }, + { (Word32)( 0x75c4a800 ), (Word32)( 0x10adbc60 ) }, + { (Word32)( 0x79a1fd00 ), (Word32)( 0x12d6a9c0 ) }, + { (Word32)( 0x7e651700 ), (Word32)( 0x14351580 ) }, + + + /* column 11 (|ILD| = 25): */ + { (Word32)( 0x725edd00 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x72aec080 ), (Word32)( 0x02fc829c ) }, + { (Word32)( 0x7382fd80 ), (Word32)( 0x05a06a70 ) }, + { (Word32)( 0x74d1f200 ), (Word32)( 0x080bfe40 ) }, + { (Word32)( 0x769d9500 ), (Word32)( 0x0a3a1900 ) }, + { (Word32)( 0x78e74f00 ), (Word32)( 0x0c1565c0 ) }, + { (Word32)( 0x7bc08f80 ), (Word32)( 0x0d86b160 ) }, + { (Word32)( 0x7f316600 ), (Word32)( 0x0e59c060 ) }, + + /* column 12 (|ILD| = 30): */ + { (Word32)( 0x78271780 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x78588a00 ), (Word32)( 0x01c22ab2 ) }, + { (Word32)( 0x78db4880 ), (Word32)( 0x034da4d0 ) }, + { (Word32)( 0x79a80d00 ), (Word32)( 0x04b3c3e8 ) }, + { (Word32)( 0x7abdfd00 ), (Word32)( 0x05f02c50 ) }, + { (Word32)( 0x7c1b1980 ), (Word32)( 0x06f5c290 ) }, + { (Word32)( 0x7dc60000 ), (Word32)( 0x07b6bb10 ) }, + { (Word32)( 0x7fbe8780 ), (Word32)( 0x08165900 ) }, + + /* column 13 (|ILD| = 35): */ + { (Word32)( 0x7b86f480 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x7ba44880 ), (Word32)( 0x0103ea70 ) }, + { (Word32)( 0x7bf1b680 ), (Word32)( 0x01e75bc4 ) }, + { (Word32)( 0x7c6a6600 ), (Word32)( 0x02b3cc4c ) }, + { (Word32)( 0x7d0d1f80 ), (Word32)( 0x036659d0 ) }, + { (Word32)( 0x7dd7d380 ), (Word32)( 0x03f748a0 ) }, + { (Word32)( 0x7ecd1000 ), (Word32)( 0x045ecc40 ) }, + { (Word32)( 0x7feb4a80 ), (Word32)( 0x048d0890 ) }, + + /* column 14 (|ILD| = 40): */ + { (Word32)( 0x7d772100 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x7d882280 ), (Word32)( 0x00945f9e ) }, + { (Word32)( 0x7db4f600 ), (Word32)( 0x0115e7c8 ) }, + { (Word32)( 0x7dfaa880 ), (Word32)( 0x0189d6ae ) }, + { (Word32)( 0x7e583e80 ), (Word32)( 0x01ee6752 ) }, + { (Word32)( 0x7ecc3e00 ), (Word32)( 0x023f24d8 ) }, + { (Word32)( 0x7f57c500 ), (Word32)( 0x0277b394 ) }, + { (Word32)( 0x7ff97280 ), (Word32)( 0x028f4b60 ) }, + + /* column 15 (|ILD| = 45): */ + { (Word32)( 0x7e918600 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x7e9b4100 ), (Word32)( 0x005425f2 ) }, + { (Word32)( 0x7eb4e100 ), (Word32)( 0x009d840a ) }, + { (Word32)( 0x7edca900 ), (Word32)( 0x00df04de ) }, + { (Word32)( 0x7f11f100 ), (Word32)( 0x0117939a ) }, + { (Word32)( 0x7f53d680 ), (Word32)( 0x0144c37e ) }, + { (Word32)( 0x7fa2cf00 ), (Word32)( 0x0164063a ) }, + { (Word32)( 0x7ffdef80 ), (Word32)( 0x0170824a ) }, + + /* column 16 (|ILD| = 50): */ + { (Word32)( 0x7f316600 ), (Word32)( 0x00000000 ) }, + { (Word32)( 0x7f36ef80 ), (Word32)( 0x002f8bde ) }, + { (Word32)( 0x7f457c00 ), (Word32)( 0x0058f712 ) }, + { (Word32)( 0x7f5c0780 ), (Word32)( 0x007de508 ) }, + { (Word32)( 0x7f7a3580 ), (Word32)( 0x009db65f ) }, + { (Word32)( 0x7f9f7700 ), (Word32)( 0x00b70ac4 ) }, + { (Word32)( 0x7fcc0780 ), (Word32)( 0x00c8711d ) }, + { (Word32)( 0x7fff5800 ), (Word32)( 0x00cf398f ) }, + +}; const Word16 McMASA_LFEGain_vectors_fx_q13[64] = { 3112, 2703, 1556, 1638, -1310, -1802, -2867, -2785, 4096, 4096, 4096, 4096, -6553, -3276, 8355, 819, @@ -373,3 +546,83 @@ const Word16 pow_10_q11[128] = { }; /* clang-format on */ +const Word16 ivas_tan_panning_gain_dirac_tbl_fx[601] = { + SHC( 0x8000 ), SHC( 0x8001 ), SHC( 0x8002 ), SHC( 0x8003 ), SHC( 0x8005 ), SHC( 0x8007 ), SHC( 0x800a ), SHC( 0x800e ), + SHC( 0x8012 ), SHC( 0x8016 ), SHC( 0x801c ), SHC( 0x8021 ), SHC( 0x8028 ), SHC( 0x802f ), SHC( 0x8036 ), SHC( 0x803e ), + SHC( 0x8047 ), SHC( 0x8050 ), SHC( 0x805a ), SHC( 0x8064 ), SHC( 0x806f ), SHC( 0x807b ), SHC( 0x8087 ), SHC( 0x8094 ), + SHC( 0x80a1 ), SHC( 0x80af ), SHC( 0x80be ), SHC( 0x80cd ), SHC( 0x80dd ), SHC( 0x80ee ), SHC( 0x80ff ), SHC( 0x8110 ), + SHC( 0x8123 ), SHC( 0x8136 ), SHC( 0x814a ), SHC( 0x815e ), SHC( 0x8173 ), SHC( 0x8188 ), SHC( 0x819f ), SHC( 0x81b6 ), + SHC( 0x81cd ), SHC( 0x81e5 ), SHC( 0x81fe ), SHC( 0x8218 ), SHC( 0x8232 ), SHC( 0x824d ), SHC( 0x8269 ), SHC( 0x8285 ), + SHC( 0x82a2 ), SHC( 0x82c0 ), SHC( 0x82de ), SHC( 0x82fd ), SHC( 0x831d ), SHC( 0x833d ), SHC( 0x835f ), SHC( 0x8380 ), + SHC( 0x83a3 ), SHC( 0x83c6 ), SHC( 0x83ea ), SHC( 0x840f ), SHC( 0x8435 ), SHC( 0x845b ), SHC( 0x8482 ), SHC( 0x84a9 ), + SHC( 0x84d2 ), SHC( 0x84fb ), SHC( 0x8525 ), SHC( 0x854f ), SHC( 0x857b ), SHC( 0x85a7 ), SHC( 0x85d4 ), SHC( 0x8601 ), + SHC( 0x8630 ), SHC( 0x865f ), SHC( 0x868f ), SHC( 0x86c0 ), SHC( 0x86f1 ), SHC( 0x8723 ), SHC( 0x8756 ), SHC( 0x878a ), + SHC( 0x87bf ), SHC( 0x87f4 ), SHC( 0x882a ), SHC( 0x8861 ), SHC( 0x8899 ), SHC( 0x88d2 ), SHC( 0x890b ), SHC( 0x8945 ), + SHC( 0x8980 ), SHC( 0x89bc ), SHC( 0x89f9 ), SHC( 0x8a36 ), SHC( 0x8a74 ), SHC( 0x8ab3 ), SHC( 0x8af3 ), SHC( 0x8b34 ), + SHC( 0x8b75 ), SHC( 0x8bb8 ), SHC( 0x8bfb ), SHC( 0x8c3f ), SHC( 0x8c83 ), SHC( 0x8cc9 ), SHC( 0x8d10 ), SHC( 0x8d57 ), + SHC( 0x8d9f ), SHC( 0x8de8 ), SHC( 0x8e32 ), SHC( 0x8e7d ), SHC( 0x8ec8 ), SHC( 0x8f15 ), SHC( 0x8f62 ), SHC( 0x8fb0 ), + SHC( 0x8fff ), SHC( 0x904f ), SHC( 0x90a0 ), SHC( 0x90f1 ), SHC( 0x9143 ), SHC( 0x9197 ), SHC( 0x91eb ), SHC( 0x9240 ), + SHC( 0x9296 ), SHC( 0x92ed ), SHC( 0x9344 ), SHC( 0x939d ), SHC( 0x93f6 ), SHC( 0x9450 ), SHC( 0x94ab ), SHC( 0x9507 ), + SHC( 0x9564 ), SHC( 0x95c2 ), SHC( 0x9621 ), SHC( 0x9680 ), SHC( 0x96e1 ), SHC( 0x9742 ), SHC( 0x97a4 ), SHC( 0x9807 ), + SHC( 0x986b ), SHC( 0x98d0 ), SHC( 0x9936 ), SHC( 0x999c ), SHC( 0x9a04 ), SHC( 0x9a6c ), SHC( 0x9ad5 ), SHC( 0x9b40 ), + SHC( 0x9bab ), SHC( 0x9c16 ), SHC( 0x9c83 ), SHC( 0x9cf1 ), SHC( 0x9d60 ), SHC( 0x9dcf ), SHC( 0x9e3f ), SHC( 0x9eb1 ), + SHC( 0x9f23 ), SHC( 0x9f96 ), SHC( 0xa00a ), SHC( 0xa07e ), SHC( 0xa0f4 ), SHC( 0xa16a ), SHC( 0xa1e2 ), SHC( 0xa25a ), + SHC( 0xa2d3 ), SHC( 0xa34d ), SHC( 0xa3c8 ), SHC( 0xa444 ), SHC( 0xa4c1 ), SHC( 0xa53e ), SHC( 0xa5bd ), SHC( 0xa63c ), + SHC( 0xa6bc ), SHC( 0xa73d ), SHC( 0xa7bf ), SHC( 0xa842 ), SHC( 0xa8c5 ), SHC( 0xa94a ), SHC( 0xa9cf ), SHC( 0xaa55 ), + SHC( 0xaadc ), SHC( 0xab64 ), SHC( 0xabed ), SHC( 0xac76 ), SHC( 0xad01 ), SHC( 0xad8c ), SHC( 0xae18 ), SHC( 0xaea5 ), + SHC( 0xaf33 ), SHC( 0xafc1 ), SHC( 0xb051 ), SHC( 0xb0e1 ), SHC( 0xb172 ), SHC( 0xb204 ), SHC( 0xb296 ), SHC( 0xb32a ), + SHC( 0xb3be ), SHC( 0xb453 ), SHC( 0xb4e9 ), SHC( 0xb580 ), SHC( 0xb617 ), SHC( 0xb6b0 ), SHC( 0xb749 ), SHC( 0xb7e2 ), + SHC( 0xb87d ), SHC( 0xb918 ), SHC( 0xb9b4 ), SHC( 0xba51 ), SHC( 0xbaef ), SHC( 0xbb8d ), SHC( 0xbc2c ), SHC( 0xbccc ), + SHC( 0xbd6d ), SHC( 0xbe0e ), SHC( 0xbeb0 ), SHC( 0xbf53 ), SHC( 0xbff7 ), SHC( 0xc09b ), SHC( 0xc140 ), SHC( 0xc1e5 ), + SHC( 0xc28c ), SHC( 0xc333 ), SHC( 0xc3da ), SHC( 0xc483 ), SHC( 0xc52c ), SHC( 0xc5d6 ), SHC( 0xc680 ), SHC( 0xc72b ), + SHC( 0xc7d7 ), SHC( 0xc883 ), SHC( 0xc930 ), SHC( 0xc9de ), SHC( 0xca8c ), SHC( 0xcb3b ), SHC( 0xcbea ), SHC( 0xcc9a ), + SHC( 0xcd4b ), SHC( 0xcdfc ), SHC( 0xceae ), SHC( 0xcf60 ), SHC( 0xd013 ), SHC( 0xd0c7 ), SHC( 0xd17b ), SHC( 0xd22f ), + SHC( 0xd2e5 ), SHC( 0xd39a ), SHC( 0xd451 ), SHC( 0xd507 ), SHC( 0xd5bf ), SHC( 0xd676 ), SHC( 0xd72f ), SHC( 0xd7e7 ), + SHC( 0xd8a1 ), SHC( 0xd95a ), SHC( 0xda14 ), SHC( 0xdacf ), SHC( 0xdb8a ), SHC( 0xdc46 ), SHC( 0xdd02 ), SHC( 0xddbe ), + SHC( 0xde7b ), SHC( 0xdf38 ), SHC( 0xdff5 ), SHC( 0xe0b3 ), SHC( 0xe172 ), SHC( 0xe230 ), SHC( 0xe2f0 ), SHC( 0xe3af ), + SHC( 0xe46f ), SHC( 0xe52f ), SHC( 0xe5ef ), SHC( 0xe6b0 ), SHC( 0xe771 ), SHC( 0xe833 ), SHC( 0xe8f4 ), SHC( 0xe9b6 ), + SHC( 0xea78 ), SHC( 0xeb3b ), SHC( 0xebfe ), SHC( 0xecc1 ), SHC( 0xed84 ), SHC( 0xee47 ), SHC( 0xef0b ), SHC( 0xefcf ), + SHC( 0xf093 ), SHC( 0xf157 ), SHC( 0xf21c ), SHC( 0xf2e0 ), SHC( 0xf3a5 ), SHC( 0xf46a ), SHC( 0xf52f ), SHC( 0xf5f5 ), + SHC( 0xf6ba ), SHC( 0xf77f ), SHC( 0xf845 ), SHC( 0xf90b ), SHC( 0xf9d0 ), SHC( 0xfa96 ), SHC( 0xfb5c ), SHC( 0xfc22 ), + SHC( 0xfce8 ), SHC( 0xfdae ), SHC( 0xfe74 ), SHC( 0xff3a ), SHC( 0x0000 ), SHC( 0x00c6 ), SHC( 0x018c ), SHC( 0x0252 ), + SHC( 0x0318 ), SHC( 0x03de ), SHC( 0x04a4 ), SHC( 0x056a ), SHC( 0x0630 ), SHC( 0x06f5 ), SHC( 0x07bb ), SHC( 0x0881 ), + SHC( 0x0946 ), SHC( 0x0a0b ), SHC( 0x0ad1 ), SHC( 0x0b96 ), SHC( 0x0c5b ), SHC( 0x0d20 ), SHC( 0x0de4 ), SHC( 0x0ea9 ), + SHC( 0x0f6d ), SHC( 0x1031 ), SHC( 0x10f5 ), SHC( 0x11b9 ), SHC( 0x127c ), SHC( 0x133f ), SHC( 0x1402 ), SHC( 0x14c5 ), + SHC( 0x1588 ), SHC( 0x164a ), SHC( 0x170c ), SHC( 0x17cd ), SHC( 0x188f ), SHC( 0x1950 ), SHC( 0x1a11 ), SHC( 0x1ad1 ), + SHC( 0x1b91 ), SHC( 0x1c51 ), SHC( 0x1d10 ), SHC( 0x1dd0 ), SHC( 0x1e8e ), SHC( 0x1f4d ), SHC( 0x200b ), SHC( 0x20c8 ), + SHC( 0x2185 ), SHC( 0x2242 ), SHC( 0x22fe ), SHC( 0x23ba ), SHC( 0x2476 ), SHC( 0x2531 ), SHC( 0x25ec ), SHC( 0x26a6 ), + SHC( 0x275f ), SHC( 0x2819 ), SHC( 0x28d1 ), SHC( 0x298a ), SHC( 0x2a41 ), SHC( 0x2af9 ), SHC( 0x2baf ), SHC( 0x2c66 ), + SHC( 0x2d1b ), SHC( 0x2dd1 ), SHC( 0x2e85 ), SHC( 0x2f39 ), SHC( 0x2fed ), SHC( 0x30a0 ), SHC( 0x3152 ), SHC( 0x3204 ), + SHC( 0x32b5 ), SHC( 0x3366 ), SHC( 0x3416 ), SHC( 0x34c5 ), SHC( 0x3574 ), SHC( 0x3622 ), SHC( 0x36d0 ), SHC( 0x377d ), + SHC( 0x3829 ), SHC( 0x38d5 ), SHC( 0x3980 ), SHC( 0x3a2a ), SHC( 0x3ad4 ), SHC( 0x3b7d ), SHC( 0x3c26 ), SHC( 0x3ccd ), + SHC( 0x3d74 ), SHC( 0x3e1b ), SHC( 0x3ec0 ), SHC( 0x3f65 ), SHC( 0x4009 ), SHC( 0x40ad ), SHC( 0x4150 ), SHC( 0x41f2 ), + SHC( 0x4293 ), SHC( 0x4334 ), SHC( 0x43d4 ), SHC( 0x4473 ), SHC( 0x4511 ), SHC( 0x45af ), SHC( 0x464c ), SHC( 0x46e8 ), + SHC( 0x4783 ), SHC( 0x481e ), SHC( 0x48b7 ), SHC( 0x4950 ), SHC( 0x49e9 ), SHC( 0x4a80 ), SHC( 0x4b17 ), SHC( 0x4bad ), + SHC( 0x4c42 ), SHC( 0x4cd6 ), SHC( 0x4d6a ), SHC( 0x4dfc ), SHC( 0x4e8e ), SHC( 0x4f1f ), SHC( 0x4faf ), SHC( 0x503f ), + SHC( 0x50cd ), SHC( 0x515b ), SHC( 0x51e8 ), SHC( 0x5274 ), SHC( 0x52ff ), SHC( 0x538a ), SHC( 0x5413 ), SHC( 0x549c ), + SHC( 0x5524 ), SHC( 0x55ab ), SHC( 0x5631 ), SHC( 0x56b6 ), SHC( 0x573b ), SHC( 0x57be ), SHC( 0x5841 ), SHC( 0x58c3 ), + SHC( 0x5944 ), SHC( 0x59c4 ), SHC( 0x5a43 ), SHC( 0x5ac2 ), SHC( 0x5b3f ), SHC( 0x5bbc ), SHC( 0x5c38 ), SHC( 0x5cb3 ), + SHC( 0x5d2d ), SHC( 0x5da6 ), SHC( 0x5e1e ), SHC( 0x5e96 ), SHC( 0x5f0c ), SHC( 0x5f82 ), SHC( 0x5ff6 ), SHC( 0x606a ), + SHC( 0x60dd ), SHC( 0x614f ), SHC( 0x61c1 ), SHC( 0x6231 ), SHC( 0x62a0 ), SHC( 0x630f ), SHC( 0x637d ), SHC( 0x63ea ), + SHC( 0x6455 ), SHC( 0x64c0 ), SHC( 0x652b ), SHC( 0x6594 ), SHC( 0x65fc ), SHC( 0x6664 ), SHC( 0x66ca ), SHC( 0x6730 ), + SHC( 0x6795 ), SHC( 0x67f9 ), SHC( 0x685c ), SHC( 0x68be ), SHC( 0x691f ), SHC( 0x6980 ), SHC( 0x69df ), SHC( 0x6a3e ), + SHC( 0x6a9c ), SHC( 0x6af9 ), SHC( 0x6b55 ), SHC( 0x6bb0 ), SHC( 0x6c0a ), SHC( 0x6c63 ), SHC( 0x6cbc ), SHC( 0x6d13 ), + SHC( 0x6d6a ), SHC( 0x6dc0 ), SHC( 0x6e15 ), SHC( 0x6e69 ), SHC( 0x6ebd ), SHC( 0x6f0f ), SHC( 0x6f60 ), SHC( 0x6fb1 ), + SHC( 0x7001 ), SHC( 0x7050 ), SHC( 0x709e ), SHC( 0x70eb ), SHC( 0x7138 ), SHC( 0x7183 ), SHC( 0x71ce ), SHC( 0x7218 ), + SHC( 0x7261 ), SHC( 0x72a9 ), SHC( 0x72f0 ), SHC( 0x7337 ), SHC( 0x737d ), SHC( 0x73c1 ), SHC( 0x7405 ), SHC( 0x7448 ), + SHC( 0x748b ), SHC( 0x74cc ), SHC( 0x750d ), SHC( 0x754d ), SHC( 0x758c ), SHC( 0x75ca ), SHC( 0x7607 ), SHC( 0x7644 ), + SHC( 0x7680 ), SHC( 0x76bb ), SHC( 0x76f5 ), SHC( 0x772e ), SHC( 0x7767 ), SHC( 0x779f ), SHC( 0x77d6 ), SHC( 0x780c ), + SHC( 0x7841 ), SHC( 0x7876 ), SHC( 0x78aa ), SHC( 0x78dd ), SHC( 0x790f ), SHC( 0x7940 ), SHC( 0x7971 ), SHC( 0x79a1 ), + SHC( 0x79d0 ), SHC( 0x79ff ), SHC( 0x7a2c ), SHC( 0x7a59 ), SHC( 0x7a85 ), SHC( 0x7ab1 ), SHC( 0x7adb ), SHC( 0x7b05 ), + SHC( 0x7b2e ), SHC( 0x7b57 ), SHC( 0x7b7e ), SHC( 0x7ba5 ), SHC( 0x7bcb ), SHC( 0x7bf1 ), SHC( 0x7c16 ), SHC( 0x7c3a ), + SHC( 0x7c5d ), SHC( 0x7c80 ), SHC( 0x7ca1 ), SHC( 0x7cc3 ), SHC( 0x7ce3 ), SHC( 0x7d03 ), SHC( 0x7d22 ), SHC( 0x7d40 ), + SHC( 0x7d5e ), SHC( 0x7d7b ), SHC( 0x7d97 ), SHC( 0x7db3 ), SHC( 0x7dce ), SHC( 0x7de8 ), SHC( 0x7e02 ), SHC( 0x7e1b ), + SHC( 0x7e33 ), SHC( 0x7e4a ), SHC( 0x7e61 ), SHC( 0x7e78 ), SHC( 0x7e8d ), SHC( 0x7ea2 ), SHC( 0x7eb6 ), SHC( 0x7eca ), + SHC( 0x7edd ), SHC( 0x7ef0 ), SHC( 0x7f01 ), SHC( 0x7f12 ), SHC( 0x7f23 ), SHC( 0x7f33 ), SHC( 0x7f42 ), SHC( 0x7f51 ), + SHC( 0x7f5f ), SHC( 0x7f6c ), SHC( 0x7f79 ), SHC( 0x7f85 ), SHC( 0x7f91 ), SHC( 0x7f9c ), SHC( 0x7fa6 ), SHC( 0x7fb0 ), + SHC( 0x7fb9 ), SHC( 0x7fc2 ), SHC( 0x7fca ), SHC( 0x7fd1 ), SHC( 0x7fd8 ), SHC( 0x7fdf ), SHC( 0x7fe4 ), SHC( 0x7fea ), + SHC( 0x7fee ), SHC( 0x7ff2 ), SHC( 0x7ff6 ), SHC( 0x7ff9 ), SHC( 0x7ffb ), SHC( 0x7ffd ), SHC( 0x7ffe ), SHC( 0x7fff ), + SHC( 0x7fff ), +}; + +/* clang-format on */ diff --git a/lib_com/ivas_rom_com_fx.h b/lib_com/ivas_rom_com_fx.h index 567c057e096d71913766592c28602577019fc0cf..165e148fe5ac9b496210dd0464779da16801abcd 100644 --- a/lib_com/ivas_rom_com_fx.h +++ b/lib_com/ivas_rom_com_fx.h @@ -49,6 +49,8 @@ extern const Word16 ivas_cos_twiddle_160_fx[ IVAS_160_PT_LEN >> 1 ]; extern const Word16 ivas_sin_twiddle_80_fx[ IVAS_80_PT_LEN >> 1 ]; extern const Word16 ivas_cos_twiddle_80_fx[ IVAS_80_PT_LEN >> 1 ]; extern const Word16 nf_tw_smoothing_coeffs_fx[N_LTP_GAIN_MEMS]; +extern const Word32 dft_res_gains_q_fx[][2]; +extern const Word16 dft_res_cod_alpha_fx[STEREO_DFT_BAND_MAX]; extern const Word16 dft_trigo_12k8_fx[STEREO_DFT_N_12k8_ENC / 4 + 1]; extern const Word16 dft_trigo_32k_fx[STEREO_DFT_N_32k_ENC / 4 + 1]; extern const Word16 dft_trigo_48k_fx[STEREO_DFT_N_MAX_ENC / 4 + 1]; @@ -77,4 +79,7 @@ extern const Word32 ls_azimuth_CICP19_fx[11]; extern const Word32 ls_elevation_CICP19_fx[11]; extern const Word16 pow_10_q11[128]; -#endif \ No newline at end of file +extern const Word16 ivas_sin_az_fx[ 361 ]; +extern const Word16 ivas_sine_panning_tbl_fx[601]; +extern const Word16 ivas_tan_panning_gain_dirac_tbl_fx[601]; +#endif diff --git a/lib_com/ivas_tools.c b/lib_com/ivas_tools.c index b03cb1331f3e3db9b07f18002e7032fe88c2ac7c..aa27862010e6f153bb7cb19e50890285d8788f57 100644 --- a/lib_com/ivas_tools.c +++ b/lib_com/ivas_tools.c @@ -595,6 +595,26 @@ int16_t check_bounds_s( return value_adj; } +/*-------------------------------------------------------------------* + * check_bounds_l() + * + * Ensure the input value is within the given limits + *-------------------------------------------------------------------*/ + +/*! r: Adjusted value */ +Word32 check_bounds_l( + const Word32 value, /* i : Input value */ + const Word32 low, /* i : Low limit */ + const Word32 high /* i : High limit */ +) +{ + Word32 value_adj; + + value_adj = min( max( value, low ), high ); + + return value_adj; +} + /****************************************************************************/ /* matrix functions */ diff --git a/lib_com/prot_fx2.h b/lib_com/prot_fx2.h index a1a1888baec4d201072ff3b6e9c9fa2598cc49e4..36daae347c7cd1b666ea85a5654e66774231055c 100644 --- a/lib_com/prot_fx2.h +++ b/lib_com/prot_fx2.h @@ -2358,9 +2358,9 @@ void calc_normal_length_fx( Word16 Q_syn ); -Word32 calc_tilt_bwe_fx( /* o : Tilt in Q24 */ - const Word16 *sp0, /* i : i signal */ - const Word16 exp, /* i : Exp of inp signal */ +Word32 ivas_calc_tilt_bwe_fx( /* o : Tilt in Q24 */ + const Word32 *sp, /* i : i signal */ + const Word16 exp_sp, /* i : Exp of inp signal */ const Word16 N /* i : signal length */ ); @@ -4605,9 +4605,23 @@ void mhvals( Word16* m /*, float * h*/ ); +Word32 sign_l( + const Word32 x /* i : input value of x */ +); + +void ivas_updt_dec_common_fx( + Decoder_State *st_fx, /* i/o: decoder state structure */ + Word16 hq_core_type_fx, /* i : HQ core type */ + const Word16 concealWholeFrameTmp, /* i : concealWholeFrameTmp flag */ + const Word32 *synth, /* i : decoded synthesis */ + const Word16 Qpostd /* i : Synthesis Q value */ +); + /* Random generator with Gaussian distribution with mean 0 and std 1 */ Word32 rand_gauss(Word16 *seed); +Word16 rand_gauss_fix(Word16 *x, Word16 *seed); + void lpc_from_spectrum( HANDLE_FD_CNG_COM hFdCngCom, const Word16 start, /*i : start band*/ @@ -8283,6 +8297,13 @@ void v_add_fx( const int16_t N /* i : Vector length */ ); +void v_shr( + const Word32 x[], /* i : Input vector */ + const Word16 shift, /* i : Constant */ + Word32 y[], /* o : Output vector that contains x >> shift */ + const Word16 N /* i : Vector length */ +); + void cldfbAnalysis_ts_fx( const Word32 *timeIn_fx, /* i : time buffer */ Word32 realBuffer_fx[CLDFB_NO_CHANNELS_MAX], /* o : real value buffer */ diff --git a/lib_com/swb_bwe_com_fx.c b/lib_com/swb_bwe_com_fx.c index 0727281c4d9f5f1551306386de44ffaae5d2d506..95c496818dc7f65591c90cbbfdec011580985bbb 100644 --- a/lib_com/swb_bwe_com_fx.c +++ b/lib_com/swb_bwe_com_fx.c @@ -716,6 +716,121 @@ Word32 calc_tilt_bwe_fx( /* o : Tilt in Q24 */ return L_temp; } +#ifdef IVAS_FLOAT_FIXED +Word32 ivas_calc_tilt_bwe_fx( /* o : Tilt in Q24 */ + const Word32 *sp, /* i : input signal */ + const Word16 exp_sp, /* i : Exp of inp signal */ + const Word16 N /* i : signal length */ +) +{ + Word16 i, j; + Word32 L_ener, L_ener_tot, L_temp; + Word32 tmp1, tmp2; + const Word32 *ptr; + Word16 exp2, tmp_exp; +#ifdef BASOP_NOGLOB_DECLARE_LOCAL + Flag Overflow = 0; +#endif + + BASOP_SATURATE_WARNING_OFF_EVS + + /* this is required for adaptative precision energy summation loop, do not remove */ + Overflow = 0; + move16(); + exp2 = 0; + move16(); + + ptr = sp; + move16(); + L_ener_tot = L_deposit_l(1); + + /* Divide Frame Length by 32 */ + FOR(j = shr(N, 5); j > 0; j--) + { +#ifdef BASOP_NOGLOB /* Critical Overflow and all those below*/ + tmp1 = mult_ro(*ptr++, 8192, &Overflow); /* Divide by 4 */ +#else + tmp1 = mult_r(*ptr++, 8192); /* Divide by 4 */ +#endif + L_ener = L_mult0(tmp1, tmp1); + /* With the shift by 4 and the L_mult0, no overflow possible for 32 samples */ + FOR(i = 1; i < 32; i++) + { + tmp1 = L_mls_o(*ptr++, 8192, &Overflow); /* Divide by 4 */ + L_ener = Madd_32_32(L_ener, tmp1, tmp1); + } +#ifdef BASOP_NOGLOB /* Critical Overflow */ + L_ener = L_shr_o(L_ener, exp2, &Overflow); + L_temp = L_add_o(L_ener_tot, L_ener, &Overflow); +#else + L_ener = L_shr(L_ener, exp2); + L_temp = L_add(L_ener_tot, L_ener); +#endif + IF(Overflow != 0) + { + L_ener_tot = L_shr(L_ener_tot, 1); + L_ener = L_shr(L_ener, 1); + exp2 = add(exp2, 1); + /* this is required, do not remove */ + Overflow = 0; + move16(); + } +#ifdef BASOP_NOGLOB /* Critical Overflow */ + L_ener_tot = L_add_o(L_ener_tot, L_ener, &Overflow); +#else + L_ener_tot = L_add(L_ener_tot, L_ener); +#endif + } +#ifdef BASOP_NOGLOB + L_ener = (L_abs(L_sub_o(sp[1], sp[0], &Overflow))); +#else + L_ener = L_deposit_l(abs_s(sub(sp[1], sp[0]))); +#endif + FOR(i = 2; i < N; i++) + { + /* Eq to (sp[i] - sp[i-1]) * (sp[i-1] - sp[i-2]) < 0 */ +#ifdef BASOP_NOGLOB + tmp1 = L_sub_o(sp[i], sp[i - 1], &Overflow); + tmp2 = L_sub_o(sp[i - 1], sp[i - 2], &Overflow); +#else + tmp1 = sub(sp[i], sp[i - 1]); + tmp2 = sub(sp[i - 1], sp[i - 2]); +#endif + tmp2 = mult(tmp1, tmp2); + tmp1 = abs_s(tmp1); + /* to Get either 0 or -1 in 'tmp2' */ + tmp2 = shr(tmp2, 15); + /* this allows this code */ + L_ener = L_msu0(L_ener, tmp2, tmp1); + /* instead of this one */ + /* test(); */ + /* if (tmp2 < 0) */ + /* { */ + /* L_ener = L_mac0(L_ener, 1, tmp1); */ + /* } */ + /* it saves one op */ + } + + tmp_exp = norm_l(L_ener_tot); + L_temp = L_shl(L_ener_tot, tmp_exp); + tmp1 = sub(add(31 + 4, exp2), add(tmp_exp, shl(exp_sp, 1))); + L_temp = Isqrt_lc(L_temp, &tmp_exp); + + /* *tilt_flt = (float)(r1/sqrt(r0)); */ + exp2 = norm_l(L_ener); + L_temp = Mult_32_16(L_temp, round_fx(L_shl(L_ener, exp2))); + exp2 = sub(exp2, tmp_exp); + exp2 = add(exp2, exp_sp); + + /* Put in Q24 */ + L_temp = L_shr(L_temp, sub(exp2, 24)); + + BASOP_SATURATE_WARNING_ON_EVS + + return L_temp; +} +#endif + /*-------------------------------------------------------------------* * calc_norm_envelop() * diff --git a/lib_com/tools_fx.c b/lib_com/tools_fx.c index 2093c794190e43fd79151b515f2610ae1d0dc3df..dd3ab398033b41196d635c66b6b5d2a40be1ecd6 100644 --- a/lib_com/tools_fx.c +++ b/lib_com/tools_fx.c @@ -3485,6 +3485,23 @@ void v_add_fx( return; } + +void v_shr( + const Word32 x[], /* i : Input vector */ + const Word16 shift, /* i : Constant */ + Word32 y[], /* o : Output vector that contains x >> shift */ + const Word16 N /* i : Vector length */ +) +{ + Word16 i; + + for ( i = 0; i < N; i++ ) + { + y[i] = L_shr(x[i], shift); + } + + return; +} /*-------------------------------------------------------------------* * delay_signal() * @@ -3507,3 +3524,23 @@ void delay_signal32( return; } + +/*--------------------------------------------------------------------- + * sign() + * + *---------------------------------------------------------------------*/ + +/*! r: sign of x (+1/-1) */ +Word32 sign_l( + const Word32 x /* i : input value of x */ +) +{ + IF ( LT_32(x , 0) ) + { + return MIN_32; + } + ELSE + { + return MAX_32; + } +} \ No newline at end of file diff --git a/lib_dec/ivas_corecoder_dec_reconfig.c b/lib_dec/ivas_corecoder_dec_reconfig.c index e6b27f44cf7a26640cfa5da35ec6d1642cce1539..8de531e5b775f0db87d831cd1cbe3c9e54fc018e 100644 --- a/lib_dec/ivas_corecoder_dec_reconfig.c +++ b/lib_dec/ivas_corecoder_dec_reconfig.c @@ -112,6 +112,13 @@ ivas_error ivas_corecoder_dec_reconfig( free( st_ivas->hSCE[0]->save_hb_synth ); st_ivas->hSCE[0]->save_hb_synth = NULL; +#ifdef IVAS_FLOAT_FIXED + free( st_ivas->hSCE[0]->save_synth_fx ); + st_ivas->hSCE[0]->save_synth_fx = NULL; + + free( st_ivas->hSCE[0]->save_hb_synth_fx ); + st_ivas->hSCE[0]->save_hb_synth_fx = NULL; +#endif } } @@ -339,6 +346,13 @@ ivas_error ivas_corecoder_dec_reconfig( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for stereo output\n" ) ); } set_zero( st_ivas->hSCE[0]->save_synth, output_frame ); +#ifdef IVAS_FLOAT_FIXED + if ( ( st_ivas->hSCE[0]->save_synth_fx = (Word32 *) malloc( sizeof( *(st_ivas->hSCE[0]->save_synth_fx)) * output_frame ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for stereo output\n" ) ); + } + set_l( st_ivas->hSCE[0]->save_synth_fx, 0, output_frame ); +#endif } if ( st_ivas->hSCE[0]->save_hb_synth == NULL ) @@ -348,6 +362,13 @@ ivas_error ivas_corecoder_dec_reconfig( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate HB memory for stereo output\n" ) ); } set_zero( st_ivas->hSCE[0]->save_hb_synth, output_frame ); +#ifdef IVAS_FLOAT_FIXED + if ( ( st_ivas->hSCE[0]->save_hb_synth_fx = (Word32 *) malloc( sizeof(*(st_ivas->hSCE[0]->save_hb_synth_fx)) * output_frame ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate HB memory for stereo output\n" ) ); + } + set_l( st_ivas->hSCE[0]->save_hb_synth_fx, 0, output_frame ); +#endif } } diff --git a/lib_dec/ivas_cpe_dec.c b/lib_dec/ivas_cpe_dec.c index 33694d018058b8fb8d40e80eb0259b8636330a44..3e337fa43b636ccd7cf904186ae141fa93230739 100644 --- a/lib_dec/ivas_cpe_dec.c +++ b/lib_dec/ivas_cpe_dec.c @@ -241,6 +241,9 @@ ivas_error ivas_cpe_dec( { /* Update DFT Stereo memories */ stereo_dft_dec_update( hCPE->hStereoDft, output_frame, 0 ); +#ifdef IVAS_FLOAT_FIXED + stereo_dft_dec_update_fx( hCPE->hStereoDft, output_frame, 0 ); +#endif if ( st_ivas->ivas_format == MASA_FORMAT && ivas_total_brate <= IVAS_SID_5k2 ) { @@ -489,6 +492,7 @@ ivas_error ivas_cpe_dec( } else { + assert(0); stereo_dft_dec( hCPE->hStereoDft, sts[0], DFT, hCPE->input_mem[1], hCPE->hStereoCng, 0, 0, 0, 0, 0, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); } diff --git a/lib_dec/ivas_cpe_dec_fx.c b/lib_dec/ivas_cpe_dec_fx.c index 6bd6c2730afcb6155ffcf108c29d8b8dbd1ae231..cc4da5182085b599680e55832dbe7a678e61bda5 100644 --- a/lib_dec/ivas_cpe_dec_fx.c +++ b/lib_dec/ivas_cpe_dec_fx.c @@ -233,6 +233,9 @@ ivas_error ivas_cpe_dec_fx( { /* Update DFT Stereo memories */ stereo_dft_dec_update( hCPE->hStereoDft, output_frame, 0 ); +#ifdef IVAS_FLOAT_FIXED + stereo_dft_dec_update_fx( hCPE->hStereoDft, output_frame, 0 ); +#endif IF( EQ_16( (Word16) st_ivas->ivas_format, MASA_FORMAT ) && LE_32( ivas_total_brate, IVAS_SID_5k2 ) ) { @@ -453,6 +456,7 @@ ivas_error ivas_cpe_dec_fx( IF( EQ_16( hCPE->element_mode, IVAS_CPE_DFT ) && !( EQ_16( hCPE->nchan_out, 1 ) && EQ_16( hCPE->hStereoDft->hConfig->res_cod_mode, STEREO_DFT_RES_COD_OFF ) ) ) { float DFT[CPE_CHANNELS][STEREO_DFT_BUF_MAX]; + Word32 DFT_fx[CPE_CHANNELS][STEREO_DFT_BUF_MAX]; set_f( DFT[0], 0.0f, STEREO_DFT_BUF_MAX ); set_f( DFT[1], 0.0f, STEREO_DFT_BUF_MAX ); @@ -481,13 +485,133 @@ ivas_error ivas_cpe_dec_fx( } ELSE { - stereo_dft_dec( hCPE->hStereoDft, sts[0], DFT, hCPE->input_mem[1], hCPE->hStereoCng, 0, 0, 0, 0, 0, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + float l_hb_nrg = 0.0, l_hb_nrg_subr = 0.0; + static int frame_counter = 0; + if (frame_counter >= 461) + frame_counter = frame_counter; + float max_val = 0.0; + int i_max_val = 0, i_max_val_psd; + { + for (int ii = 0; ii < sizeof(sts[0]->hFdCngDec->smoothed_psd) / sizeof(sts[0]->hFdCngDec->smoothed_psd[0]); ii++) + { + if (max_val < fabs(sts[0]->hFdCngDec->smoothed_psd[ii])) + { + max_val = (float)fabs(sts[0]->hFdCngDec->smoothed_psd[ii]); + } + } + i_max_val_psd = (int)max_val; + sts[0]->hFdCngDec->q_smoothed_psd = norm_l(i_max_val_psd) - Q9; + max_val = 0.0; + for (int ii = 0; ii < sizeof(DFT) / sizeof(DFT[0]); ii++) + { + for (int jj = 0; jj < sizeof(DFT[0]) / sizeof(DFT[0][0]); jj++) + { + if (max_val < fabs(DFT[ii][jj])) + { + max_val = (float)fabs(DFT[ii][jj]); + } + } + } + i_max_val = (int)max_val; + hCPE->hStereoDft->q_dft = norm_l(i_max_val) - 6; + IF (hCPE->hStereoDft->q_dft > Q15) + { + hCPE->hStereoDft->q_dft = Q15; + } + IF (EQ_16(hCPE->hStereoDft->first_frame, 1)) + { + hCPE->hStereoDft->q_smoothed_nrg = hCPE->hStereoDft->q_dft; + hCPE->hStereoDft->q_past_dft = hCPE->hStereoDft->q_dft; + hCPE->hStereoDft->first_frame = 0; + } + + sts[0]->stab_fac_fx = (Word16)floatToFixed(sts[0]->stab_fac, 15); + sts[0]->hFdCngDec->cna_rescale_fact_fx = (Word16)floatToFixed(sts[0]->hFdCngDec->cna_rescale_fact, 15); + sts[0]->hFdCngDec->cna_act_fact_fx = (Word16)floatToFixed(sts[0]->hFdCngDec->cna_act_fact, 15); + floatToFixed_arrL(&hCPE->hStereoDft->res_gains_ind[0][0], &hCPE->hStereoDft->res_gains_ind_fx[0][0], Q26, sizeof(hCPE->hStereoDft->res_gains_ind_fx) / sizeof(hCPE->hStereoDft->res_gains_ind_fx[0][0])); + floatToFixed_arrL(&hCPE->hStereoDft->res_pred_gain[0], &hCPE->hStereoDft->res_pred_gain_fx[0], Q31, sizeof(hCPE->hStereoDft->res_pred_gain_fx)/ sizeof(hCPE->hStereoDft->res_pred_gain_fx[0])); + floatToFixed_arrL(&hCPE->hStereoDft->itd[0], &hCPE->hStereoDft->itd_fx[0], Q15, sizeof(hCPE->hStereoDft->itd_fx) / sizeof(hCPE->hStereoDft->itd_fx[0])); + floatToFixed_arrL(&sts[0]->hFdCngDec->smoothed_psd[0], &sts[0]->hFdCngDec->smoothed_psd_fx[0], sts[0]->hFdCngDec->q_smoothed_psd, sizeof(sts[0]->hFdCngDec->smoothed_psd_fx) / sizeof(sts[0]->hFdCngDec->smoothed_psd_fx[0])); + floatToFixed_arrL(&DFT[0][0], &DFT_fx[0][0], hCPE->hStereoDft->q_dft , sizeof(DFT) / sizeof(DFT[0][0])); + floatToFixed_arrL(&hCPE->hStereoDft->res_cod_mem[0], &hCPE->hStereoDft->res_cod_mem_fx[0], hCPE->hStereoDft->q_dft, sizeof(hCPE->hStereoDft->res_cod_mem_fx) / sizeof(hCPE->hStereoDft->res_cod_mem_fx[0])); + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_subr_fx) / sizeof(hCPE->hStereoDft->hb_nrg_subr_fx[0]); ii++) + { + if (l_hb_nrg_subr < hCPE->hStereoDft->hb_nrg_subr[ii]) + { + l_hb_nrg_subr = hCPE->hStereoDft->hb_nrg_subr[ii]; + } + } + hCPE->hStereoDft->q_hb_nrg_subr = 0; + if (l_hb_nrg_subr > (float)MAX_32) + { + int quotient = (int) ceil(l_hb_nrg_subr / (float)MAX_32); + hCPE->hStereoDft->q_hb_nrg_subr = Q31 - norm_l(quotient); + } + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_subr_fx) / sizeof(hCPE->hStereoDft->hb_nrg_subr_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg_subr_fx[ii] = (Word32)(hCPE->hStereoDft->hb_nrg_subr[ii] / ((float)(1 << hCPE->hStereoDft->q_hb_nrg_subr))); + } + + + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_fx) / sizeof(hCPE->hStereoDft->hb_nrg_fx[0]); ii++) + { + if (l_hb_nrg < hCPE->hStereoDft->hb_nrg[ii]) + { + l_hb_nrg = hCPE->hStereoDft->hb_nrg[ii]; + } + } + hCPE->hStereoDft->q_hb_nrg = 0; + if (l_hb_nrg > (float)MAX_32) + { + int quotient = (int) ceil(l_hb_nrg / (float)MAX_32); + hCPE->hStereoDft->q_hb_nrg = Q31 - norm_l(quotient); + } + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_fx) / sizeof(hCPE->hStereoDft->hb_nrg_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg_fx[ii] = (Word32)(hCPE->hStereoDft->hb_nrg[ii] / ((float)(1 << hCPE->hStereoDft->q_hb_nrg))); + } + + floatToFixed_arrL(&hCPE->hStereoDft->side_gain[0], &hCPE->hStereoDft->side_gain_fx[0], Q31,sizeof(hCPE->hStereoDft->side_gain_fx) / sizeof(hCPE->hStereoDft->side_gain_fx[0])); + floatToFixed_arrL(&hCPE->hStereoDft->gipd[0], &hCPE->hStereoDft->gipd_fx[0], Q13, sizeof(hCPE->hStereoDft->gipd_fx) / sizeof(hCPE->hStereoDft->gipd_fx[0])); + floatToFixed_arr(&hCPE->hStereoDft->g_state[0], &hCPE->hStereoDft->g_state_fx[0], Q15, sizeof(hCPE->hStereoDft->g_state_fx) / sizeof(hCPE->hStereoDft->g_state_fx[0])); + floatToFixed_arr(&sts[0]->hFdCngDec->cna_cm[0], &sts[0]->hFdCngDec->cna_cm_fx[0], Q15, sizeof(sts[0]->hFdCngDec->cna_cm_fx) / sizeof(sts[0]->hFdCngDec->cna_cm_fx[0])); + floatToFixed_arr(&hCPE->hStereoCng->cm[0], &hCPE->hStereoCng->cm_fx[0], Q15, sizeof(hCPE->hStereoCng->cm_fx) / sizeof(hCPE->hStereoCng->cm_fx[0])); + floatToFixed_arr(&sts[0]->hFdCngDec->cna_g_state[0], &sts[0]->hFdCngDec->cna_g_state_fx[0], Q15, sizeof(sts[0]->hFdCngDec->cna_g_state_fx) / sizeof(sts[0]->hFdCngDec->cna_g_state_fx[0])); + } + stereo_dft_dec_fx( hCPE->hStereoDft, sts[0], DFT_fx, hCPE->input_mem_fx[1], hCPE->hStereoCng, 0, 0, 0, 0, 0, 0, MAX_PARAM_SPATIAL_SUBFRAMES ); + { + sts[0]->hFdCngDec->cna_rescale_fact = fixedToFloat(sts[0]->hFdCngDec->cna_rescale_fact_fx, 15); + sts[0]->hFdCngDec->cna_act_fact = fixedToFloat(sts[0]->hFdCngDec->cna_act_fact_fx, 15); + fixedToFloat_arrL(&hCPE->hStereoDft->res_gains_ind_fx[0][0], &hCPE->hStereoDft->res_gains_ind[0][0], Q26, sizeof(hCPE->hStereoDft->res_gains_ind_fx) / sizeof(hCPE->hStereoDft->res_gains_ind_fx[0][0])); + fixedToFloat_arrL(&hCPE->hStereoDft->res_pred_gain_fx[0], &hCPE->hStereoDft->res_pred_gain[0], Q31, sizeof(hCPE->hStereoDft->res_pred_gain_fx)/ sizeof(hCPE->hStereoDft->res_pred_gain_fx[0])); + fixedToFloat_arrL(&hCPE->hStereoDft->itd_fx[0], &hCPE->hStereoDft->itd[0], Q15, sizeof(hCPE->hStereoDft->itd_fx) / sizeof(hCPE->hStereoDft->itd_fx[0])); + fixedToFloat_arrL(&sts[0]->hFdCngDec->smoothed_psd_fx[0], &sts[0]->hFdCngDec->smoothed_psd[0], sts[0]->hFdCngDec->q_smoothed_psd, sizeof(sts[0]->hFdCngDec->smoothed_psd_fx) / sizeof(sts[0]->hFdCngDec->smoothed_psd_fx[0])); + fixedToFloat_arrL(&DFT_fx[0][0], &DFT[0][0], hCPE->hStereoDft->q_dft , sizeof(DFT) / sizeof(DFT[0][0])); + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_subr_fx) / sizeof(hCPE->hStereoDft->hb_nrg_subr_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg_subr[0] = ((float)hCPE->hStereoDft->hb_nrg_subr_fx[0] * ((float)(1 << hCPE->hStereoDft->q_hb_nrg_subr))); + } + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_fx) / sizeof(hCPE->hStereoDft->hb_nrg_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg[ii] = ((float)hCPE->hStereoDft->hb_nrg_fx[ii] * ((float)(1 << hCPE->hStereoDft->q_hb_nrg))); + } + fixedToFloat_arrL(&hCPE->hStereoDft->side_gain_fx[0], &hCPE->hStereoDft->side_gain[0], Q31,sizeof(hCPE->hStereoDft->side_gain_fx) / sizeof(hCPE->hStereoDft->side_gain_fx[0])); + fixedToFloat_arrL(&hCPE->hStereoDft->gipd_fx[0], &hCPE->hStereoDft->gipd[0], Q13, sizeof(hCPE->hStereoDft->gipd_fx) / sizeof(hCPE->hStereoDft->gipd_fx[0])); + fixedToFloat_arr(&hCPE->hStereoDft->g_state_fx[0], &hCPE->hStereoDft->g_state[0], Q15, sizeof(hCPE->hStereoDft->g_state_fx) / sizeof(hCPE->hStereoDft->g_state_fx[0])); + fixedToFloat_arr(&sts[0]->hFdCngDec->cna_cm_fx[0], &sts[0]->hFdCngDec->cna_cm[0], Q15, sizeof(sts[0]->hFdCngDec->cna_cm_fx) / sizeof(sts[0]->hFdCngDec->cna_cm_fx[0])); + fixedToFloat_arr(&hCPE->hStereoCng->cm_fx[0], &hCPE->hStereoCng->cm[0], Q15, sizeof(hCPE->hStereoCng->cm_fx) / sizeof(hCPE->hStereoCng->cm_fx[0])); + fixedToFloat_arr(&sts[0]->hFdCngDec->cna_g_state_fx[0], &sts[0]->hFdCngDec->cna_g_state[0], Q15, sizeof(sts[0]->hFdCngDec->cna_g_state_fx) / sizeof(sts[0]->hFdCngDec->cna_g_state_fx[0])); + fixedToFloat_arrL(&hCPE->hStereoDft->td_gain_fx[0], &hCPE->hStereoDft->td_gain[0], Q15, sizeof(hCPE->hStereoDft->td_gain_fx) / sizeof(hCPE->hStereoDft->td_gain_fx[0])); + fixedToFloat_arrL(&hCPE->hStereoDft->res_cod_mem_fx[0], &hCPE->hStereoDft->res_cod_mem[0], hCPE->hStereoDft->q_dft, sizeof(hCPE->hStereoDft->res_cod_mem_fx) / sizeof(hCPE->hStereoDft->res_cod_mem_fx[0])); + } + frame_counter++; + //printf("frame_counter = [%d]\n", frame_counter); } /* synthesis iFFT */ FOR( n = 0; n < hCPE->nchan_out; n++ ) { - stereo_dft_dec_synthesize( hCPE, DFT, n, output_flt[n], output_frame ); + stereo_dft_dec_synthesize( hCPE, &DFT[0], n, output_flt[n], output_frame ); } } ELSE IF( EQ_16( hCPE->element_mode, IVAS_CPE_TD ) ) diff --git a/lib_dec/ivas_jbm_dec.c b/lib_dec/ivas_jbm_dec.c index 8726f63d4e1ad5d93e42e67772f08a84cb946a8d..551e55fde5214fa7deee00d2f71c74239c34e4b7 100644 --- a/lib_dec/ivas_jbm_dec.c +++ b/lib_dec/ivas_jbm_dec.c @@ -80,6 +80,9 @@ ivas_error ivas_jbm_dec_tc( int16_t n, output_frame, nchan_out; Decoder_State *st; /* used for bitstream handling */ float *p_output[MAX_TRANSPORT_CHANNELS]; /* 'float' buffer for output synthesis */ +#ifdef IVAS_FLOAT_FIXED + Word32 *p_output_fix[MAX_TRANSPORT_CHANNELS]; /* 'float' buffer for output synthesis */ +#endif int16_t nchan_remapped; int16_t nb_bits_metadata[MAX_SCE + 1]; int32_t output_Fs, ivas_total_brate; @@ -108,6 +111,13 @@ ivas_error ivas_jbm_dec_tc( { set_zero( p_output[n], L_FRAME48k ); } +#ifdef IVAS_FLOAT_FIXED + p_output_fix[n] = st_ivas->p_output_fx[n]; + if ( p_output_fix[n] != NULL ) + { + set_l( p_output_fix[n], 0, L_FRAME48k ); + } +#endif } if ( !st_ivas->hDecoderConfig->Opt_tsm ) @@ -132,6 +142,13 @@ ivas_error ivas_jbm_dec_tc( { set_f( p_output[n], 0.0f, output_frame ); } +#ifdef IVAS_FLOAT_FIXED + /* zero output when first frame(s) is lost */ + for ( n = 0; n < nchan_out; n++ ) + { + set_l( p_output_fix[n], 0, output_frame ); + } +#endif } else if ( st_ivas->ivas_format == STEREO_FORMAT ) { @@ -640,7 +657,169 @@ ivas_error ivas_jbm_dec_tc( ivas_spar_dec_gen_umx_mat( st_ivas->hSpar->hMdDec, st_ivas->nchan_transport, IVAS_MAX_NUM_BANDS, st_ivas->bfi, ivas_get_spar_dec_md_num_subframes( st_ivas->sba_order, ivas_total_brate, st_ivas->last_active_ivas_total_brate ) ); } +#ifndef IVAS_FLOAT_FIXED_ ivas_sba_dirac_stereo_dec( st_ivas, p_output, output_frame, st_ivas->ivas_format == MC_FORMAT ); +#else + { + float l_hb_nrg = 0.0, l_hb_nrg_subr = 0.0; + static int frame_counter = 0; + if (frame_counter >= 200) + frame_counter = frame_counter; + float max_val = 0.0; + int i_max_val_psd, i_max_val_op; + CPE_DEC_HANDLE hCPE = st_ivas->hCPE[0]; + SCE_DEC_HANDLE hSCE = st_ivas->hSCE[0]; + for (int ii = 0; ii < sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd) / sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd[0]); ii++) + { + if (max_val < fabs(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd[ii])) + { + max_val = (float)fabs(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd[ii]); + } + } + i_max_val_psd = (int)max_val; + for (int ii = 0; ii < 2; ii++) + { + for (int jj = 0; jj < (48000 / FRAMES_PER_SEC); jj++) + { + if (max_val < fabs(p_output[ii][jj])) + { + max_val = (float)fabs(p_output[ii][jj]); + } + } + } + i_max_val_op = (int)max_val; + hCPE->hStereoDft->q_dft = norm_l(i_max_val_op) - Q10; + st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->q_smoothed_psd = norm_l(i_max_val_psd) - Q9; + IF (EQ_16(hCPE->hStereoDft->first_frame, 1)) + { + hCPE->hStereoDft->q_smoothed_nrg = hCPE->hStereoDft->q_dft; + hCPE->hStereoDft->first_frame = 0; + } + + st_ivas->hCPE[0]->hCoreCoder[0]->stab_fac_fx = (Word16)floatToFixed(st_ivas->hCPE[0]->hCoreCoder[0]->stab_fac, 15); + st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_rescale_fact_fx = (Word16)floatToFixed(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_rescale_fact, 15); + st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_act_fact_fx = (Word16)floatToFixed(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_act_fact, 15); + floatToFixed_arrL(&hCPE->hStereoDft->res_gains_ind[0][0], &hCPE->hStereoDft->res_gains_ind_fx[0][0], Q26, sizeof(hCPE->hStereoDft->res_gains_ind_fx) / sizeof(hCPE->hStereoDft->res_gains_ind_fx[0][0])); + floatToFixed_arrL(&hCPE->hStereoDft->res_pred_gain[0], &hCPE->hStereoDft->res_pred_gain_fx[0], Q31, sizeof(hCPE->hStereoDft->res_pred_gain_fx)/ sizeof(hCPE->hStereoDft->res_pred_gain_fx[0])); + floatToFixed_arrL(&hCPE->hStereoDft->itd[0], &hCPE->hStereoDft->itd_fx[0], Q1, sizeof(hCPE->hStereoDft->itd_fx) / sizeof(hCPE->hStereoDft->itd_fx[0])); + floatToFixed_arrL(&st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd[0], &st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd_fx[0], st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->q_smoothed_psd, sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd_fx) / sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd_fx[0])); + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_subr_fx) / sizeof(hCPE->hStereoDft->hb_nrg_subr_fx[0]); ii++) + { + if (l_hb_nrg_subr < hCPE->hStereoDft->hb_nrg_subr[ii]) + { + l_hb_nrg_subr = hCPE->hStereoDft->hb_nrg_subr[ii]; + } + } + hCPE->hStereoDft->q_hb_nrg_subr = 0; + if (l_hb_nrg_subr > (float)MAX_32) + { + int quotient = (int) ceil(l_hb_nrg_subr / (float)MAX_32); + hCPE->hStereoDft->q_hb_nrg_subr = Q31 - norm_l(quotient); + } + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_subr_fx) / sizeof(hCPE->hStereoDft->hb_nrg_subr_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg_subr_fx[ii] = (Word32)(hCPE->hStereoDft->hb_nrg_subr[ii] / ((float)(1 << hCPE->hStereoDft->q_hb_nrg_subr))); + } + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_fx) / sizeof(hCPE->hStereoDft->hb_nrg_fx[0]); ii++) + { + if (l_hb_nrg < hCPE->hStereoDft->hb_nrg[ii]) + { + l_hb_nrg = hCPE->hStereoDft->hb_nrg[ii]; + } + } + hCPE->hStereoDft->q_hb_nrg = 0; + if (l_hb_nrg > (float)MAX_32) + { + int quotient = (int) ceil(l_hb_nrg / (float)MAX_32); + hCPE->hStereoDft->q_hb_nrg = Q31 - norm_l(quotient); + } + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_fx) / sizeof(hCPE->hStereoDft->hb_nrg_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg_fx[ii] = (Word32)(hCPE->hStereoDft->hb_nrg[ii] / ((float)(1 << hCPE->hStereoDft->q_hb_nrg))); + } + + floatToFixed_arrL(&hCPE->hStereoDft->side_gain[0], &hCPE->hStereoDft->side_gain_fx[0], Q31,sizeof(hCPE->hStereoDft->side_gain_fx) / sizeof(hCPE->hStereoDft->side_gain_fx[0])); + floatToFixed_arrL(&hCPE->hStereoDft->gipd[0], &hCPE->hStereoDft->gipd_fx[0], Q13, sizeof(hCPE->hStereoDft->gipd_fx) / sizeof(hCPE->hStereoDft->gipd_fx[0])); + floatToFixed_arr(&hCPE->hStereoDft->g_state[0], &hCPE->hStereoDft->g_state_fx[0], Q15, sizeof(hCPE->hStereoDft->g_state_fx) / sizeof(hCPE->hStereoDft->g_state_fx[0])); + floatToFixed_arr(&st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm[0], &st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm_fx[0], Q15, sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm_fx) / sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm_fx[0])); + IF (hCPE->hStereoCng != NULL) + { + floatToFixed_arr(&hCPE->hStereoCng->cm[0], &hCPE->hStereoCng->cm_fx[0], Q15, sizeof(hCPE->hStereoCng->cm_fx) / sizeof(hCPE->hStereoCng->cm_fx[0])); + } + floatToFixed_arr(&st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state[0], &st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state_fx[0], Q15, sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state_fx) / sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state_fx[0])); + for (int ii = 0; ii < 2; ii++) + { + floatToFixed_arrL(&p_output[ii][0], &p_output_fix[ii][0], hCPE->hStereoDft->q_dft , (48000 / FRAMES_PER_SEC)); + } + + Word16 q = 11; + IF( hCPE->hCoreCoder[0] != NULL ) + floatToFixed_arrL(&hCPE->hCoreCoder[0]->hHQ_core->old_outLB[0], &hCPE->hCoreCoder[0]->hHQ_core->old_outLB_fx[0], q, L_FRAME32k); + IF( (hCPE->hCoreCoder[0] != NULL) && (hCPE->hCoreCoder[0]->p_bpf_noise_buf_32 != NULL) ) + floatToFixed_arrL(&hCPE->hCoreCoder[0]->p_bpf_noise_buf_float[0], &hCPE->hCoreCoder[0]->p_bpf_noise_buf_32[0], q, L_FRAME16k); + floatToFixed_arrL(&hCPE->input_mem_BPF[0][0], &hCPE->input_mem_BPF_fx[0][0], q, STEREO_DFT32MS_OVL_16k); + floatToFixed_arrL(&hCPE->input_mem[0][0], &hCPE->input_mem_fx[0][0], q, NS2SA( hCPE->hCoreCoder[0]->output_Fs, STEREO_DFT32MS_OVL_NS )); + floatToFixed_arrL(&hCPE->input_mem_LB[0][0], &hCPE->input_mem_LB_fx[0][0], q, STEREO_DFT32MS_OVL_16k); + floatToFixed_arrL(&hCPE->input_mem[1][0], &hCPE->input_mem_fx[1][0], q, NS2SA( hCPE->hCoreCoder[0]->output_Fs, STEREO_DFT32MS_OVL_NS )); + floatToFixed_arrL(&hCPE->input_mem_LB[1][0], &hCPE->input_mem_LB_fx[1][0], q, STEREO_DFT32MS_OVL_16k); + IF( hCPE->hStereoDft != NULL ) + floatToFixed_arrL(&hCPE->hStereoDft->ap_delay_mem[0], &hCPE->hStereoDft->ap_delay_mem_fx[0], q, NS2SA( 16000, DELAY_BWE_TOTAL_NS )); + floatToFixed_arrL(&hSCE->save_synth[0], &hSCE->save_synth_fx[0], q, (Word16)(hCPE->hCoreCoder[0]->output_Fs / FRAMES_PER_SEC)); + floatToFixed_arrL(&hSCE->save_hb_synth[0], &hSCE->save_hb_synth_fx[0], q, (Word16)(hCPE->hCoreCoder[0]->output_Fs / FRAMES_PER_SEC)); + IF( hCPE->hCoreCoder[0] != NULL ) + floatToFixed_arrL(&hCPE->hCoreCoder[0]->hHQ_core->old_out[0], &hCPE->hCoreCoder[0]->hHQ_core->oldOut_fx[0], q, L_FRAME48k); + IF( hCPE->hStereoDft != NULL ) + floatToFixed_arrL(&hCPE->hStereoDft->buff_LBTCX_mem[0], &hCPE->hStereoDft->buff_LBTCX_mem_fx[0], q, NS2SA( 16000, STEREO_DFT32MS_OVL_NS )); + + ivas_sba_dirac_stereo_dec_fx( st_ivas, p_output_fix, output_frame, st_ivas->ivas_format == MC_FORMAT ); + + st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_rescale_fact = fixedToFloat(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_rescale_fact_fx, 15); + st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_act_fact = fixedToFloat(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_act_fact_fx, 15); + fixedToFloat_arrL(&hCPE->hStereoDft->res_gains_ind_fx[0][0], &hCPE->hStereoDft->res_gains_ind[0][0], Q26, sizeof(hCPE->hStereoDft->res_gains_ind_fx) / sizeof(hCPE->hStereoDft->res_gains_ind_fx[0][0])); + fixedToFloat_arrL(&hCPE->hStereoDft->res_pred_gain_fx[0], &hCPE->hStereoDft->res_pred_gain[0], Q31, sizeof(hCPE->hStereoDft->res_pred_gain_fx)/ sizeof(hCPE->hStereoDft->res_pred_gain_fx[0])); + fixedToFloat_arrL(&hCPE->hStereoDft->itd_fx[0], &hCPE->hStereoDft->itd[0], Q1, sizeof(hCPE->hStereoDft->itd_fx) / sizeof(hCPE->hStereoDft->itd_fx[0])); + fixedToFloat_arrL(&st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd_fx[0], &st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd[0], st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->q_smoothed_psd, sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd_fx) / sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->smoothed_psd_fx[0])); + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_subr_fx) / sizeof(hCPE->hStereoDft->hb_nrg_subr_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg_subr[0] = ((float)hCPE->hStereoDft->hb_nrg_subr_fx[0] * ((float)(1 << hCPE->hStereoDft->q_hb_nrg_subr))); + } + for (int ii = 0; ii < sizeof(hCPE->hStereoDft->hb_nrg_fx) / sizeof(hCPE->hStereoDft->hb_nrg_fx[0]); ii++) + { + hCPE->hStereoDft->hb_nrg[ii] = ((float)hCPE->hStereoDft->hb_nrg_fx[ii] * ((float)(1 << hCPE->hStereoDft->q_hb_nrg))); + } + fixedToFloat_arrL(&hCPE->hStereoDft->side_gain_fx[0], &hCPE->hStereoDft->side_gain[0], Q31,sizeof(hCPE->hStereoDft->side_gain_fx) / sizeof(hCPE->hStereoDft->side_gain_fx[0])); + fixedToFloat_arrL(&hCPE->hStereoDft->gipd_fx[0], &hCPE->hStereoDft->gipd[0], Q13, sizeof(hCPE->hStereoDft->gipd_fx) / sizeof(hCPE->hStereoDft->gipd_fx[0])); + fixedToFloat_arr(&hCPE->hStereoDft->g_state_fx[0], &hCPE->hStereoDft->g_state[0], Q15, sizeof(hCPE->hStereoDft->g_state_fx) / sizeof(hCPE->hStereoDft->g_state_fx[0])); + fixedToFloat_arr(&st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm_fx[0], &st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm[0], Q15, sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm_fx) / sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_cm_fx[0])); + IF (hCPE->hStereoCng != NULL) + { + fixedToFloat_arr(&hCPE->hStereoCng->cm_fx[0], &hCPE->hStereoCng->cm[0], Q15, sizeof(hCPE->hStereoCng->cm_fx) / sizeof(hCPE->hStereoCng->cm_fx[0])); + } + fixedToFloat_arr(&st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state_fx[0], &st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state[0], Q15, sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state_fx) / sizeof(st_ivas->hCPE[0]->hCoreCoder[0]->hFdCngDec->cna_g_state_fx[0])); + fixedToFloat_arrL(&hCPE->hStereoDft->td_gain_fx[0], &hCPE->hStereoDft->td_gain[0], Q15, sizeof(hCPE->hStereoDft->td_gain_fx) / sizeof(hCPE->hStereoDft->td_gain_fx[0])); + for (int ii = 0; ii < 2; ii++) + { + fixedToFloat_arrL(&p_output_fix[ii][0], &p_output[ii][0], hCPE->hStereoDft->q_dft, (48000 / FRAMES_PER_SEC)); + } + IF( hCPE->hCoreCoder[0] != NULL ) + fixedToFloat_arrL(&hCPE->hCoreCoder[0]->hHQ_core->old_outLB_fx[0], &hCPE->hCoreCoder[0]->hHQ_core->old_outLB[0], q, L_FRAME32k); + IF( (hCPE->hCoreCoder[0] != NULL) && (hCPE->hCoreCoder[0]->p_bpf_noise_buf_32 != NULL) ) + fixedToFloat_arrL(&hCPE->hCoreCoder[0]->p_bpf_noise_buf_32[0], &hCPE->hCoreCoder[0]->p_bpf_noise_buf_float[0], q, L_FRAME16k); + fixedToFloat_arrL(&hCPE->input_mem_BPF_fx[0][0], &hCPE->input_mem_BPF[0][0], q, STEREO_DFT32MS_OVL_16k); + fixedToFloat_arrL(&hCPE->input_mem_fx[0][0], &hCPE->input_mem[0][0], q, NS2SA( hCPE->hCoreCoder[0]->output_Fs, STEREO_DFT32MS_OVL_NS )); + fixedToFloat_arrL(&hCPE->input_mem_LB_fx[0][0], &hCPE->input_mem_LB[0][0], q, STEREO_DFT32MS_OVL_16k); + fixedToFloat_arrL(&hCPE->input_mem_fx[1][0], &hCPE->input_mem[1][0], q, NS2SA( hCPE->hCoreCoder[0]->output_Fs, STEREO_DFT32MS_OVL_NS )); + fixedToFloat_arrL(&hCPE->input_mem_LB_fx[1][0], &hCPE->input_mem_LB[1][0], q, STEREO_DFT32MS_OVL_16k); + IF( hCPE->hStereoDft != NULL ) + fixedToFloat_arrL(&hCPE->hStereoDft->ap_delay_mem_fx[0], &hCPE->hStereoDft->ap_delay_mem[0], q, NS2SA( 16000, DELAY_BWE_TOTAL_NS )); + fixedToFloat_arrL(&hSCE->save_synth_fx[0], &hSCE->save_synth[0], q, (Word16)(hCPE->hCoreCoder[0]->output_Fs / FRAMES_PER_SEC)); + fixedToFloat_arrL(&hSCE->save_hb_synth_fx[0], &hSCE->save_hb_synth[0], q, (Word16)(hCPE->hCoreCoder[0]->output_Fs / FRAMES_PER_SEC)); + IF( hCPE->hCoreCoder[0] != NULL ) + fixedToFloat_arrL(&hCPE->hCoreCoder[0]->hHQ_core->oldOut_fx[0], &hCPE->hCoreCoder[0]->hHQ_core->old_out[0], q, L_FRAME48k); + IF( hCPE->hStereoDft != NULL ) + fixedToFloat_arrL(&hCPE->hStereoDft->buff_LBTCX_mem_fx[0], &hCPE->hStereoDft->buff_LBTCX_mem[0], q, NS2SA( 16000, STEREO_DFT32MS_OVL_NS )); + } +#endif } else if ( st_ivas->ivas_format == MASA_FORMAT && ivas_total_brate < MASA_STEREO_MIN_BITRATE && ( ivas_total_brate > IVAS_SID_5k2 || ( ivas_total_brate <= IVAS_SID_5k2 && st_ivas->nCPE > 0 && st_ivas->hCPE[0]->nchan_out == 1 ) ) ) { diff --git a/lib_dec/ivas_post_proc.c b/lib_dec/ivas_post_proc.c index cae6e5488253b7cb8dafc9af22dcb4d672d91ccb..ef2e1f5a28f3222bc5f5580442acc23cf88bf371 100644 --- a/lib_dec/ivas_post_proc.c +++ b/lib_dec/ivas_post_proc.c @@ -250,12 +250,12 @@ void ivas_post_proc_fx( #endif // IVAS_FLOAT_FIXED +#ifdef IVAS_FLOAT_FIXED /*------------------------------------------------------------------------- - * stereo_dft_dec_core_switching() + * stereo_dft_dec_core_switching_fx() * * core switching in DFT stereo *-------------------------------------------------------------------------*/ -#ifdef IVAS_FLOAT_FIXED void stereo_dft_dec_core_switching_fx( CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ Word32 output_fx[], /* i/o: synthesis @internal Fs */ diff --git a/lib_dec/ivas_rom_dec.c b/lib_dec/ivas_rom_dec.c index 9ad8ead53d1f6f91490c7a3dd52469fa2fe21084..01f446dfba8236263a61ad43fbb318bfb5084c2a 100644 --- a/lib_dec/ivas_rom_dec.c +++ b/lib_dec/ivas_rom_dec.c @@ -94,6 +94,45 @@ const float dft_ap_gains[5][3] = }; #ifdef IVAS_FLOAT_FIXED +const Word16 dft_alpha_s_fx[STEREO_DFT_BAND_MAX] = +{ + (Word16)(0x599A), (Word16)(0x3333), (Word16)(0x2000), (Word16)(0x199A), + (Word16)(0x1334), (Word16)(0x0CCD), (Word16)(0x0CCD), (Word16)(0x0CCD), + (Word16)(0x0CCD), (Word16)(0x0CCD), (Word16)(0x0CCD), (Word16)(0x0CCD), + (Word16)(0x0CCD) +}; + +const Word16 dft_alpha_w_fx[STEREO_DFT_BAND_MAX] = +{ + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666) +}; + +const Word16 dft_alpha_s2_fx[STEREO_DFT_BAND_MAX] = +{ + (Word16)(0x599A), (Word16)(0x4CCD), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666) +}; +const Word16 dft_alpha_s_b2_fx[STEREO_DFT_BAND_MAX] = +{ + (Word16)(0x599A), (Word16)(0x2666), (Word16)(0x1334), (Word16) 0x0CCD, + (Word16)(0x0CCD), (Word16)(0x0CCD), (Word16)(0x0CCD) +}; + +const Word16 dft_alpha_w_b2_fx[STEREO_DFT_BAND_MAX] = +{ + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666) +}; +const Word16 dft_alpha_s2_b2_fx[STEREO_DFT_BAND_MAX] = +{ + (Word16)(0x599A), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666), + (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666) +}; const Word32 dft_bpf_weights_fx[] = { 1073784832, 1068033792, 1050938752, 1022962432, 984855360, 937628928, 882514816, 820918592, 754369152, @@ -126,6 +165,15 @@ const float dft_res_pred_weights[][STEREO_DFT_BAND_MAX] = { 1.f, .5f, .4f, .4f } }; +#ifdef IVAS_FLOAT_FIXED +const Word16 dft_res_pred_weights_fx[][STEREO_DFT_BAND_MAX] = +{ + { MAX_16, ONE_IN_Q14 + ONE_IN_Q13, ONE_IN_Q14, (Word16)(0x3333), (Word16)(0x3333) }, + { MAX_16, MAX_16, MAX_16, MAX_16, 0}, + { MAX_16, ONE_IN_Q14, (Word16)(0x3333), (Word16)(0x3333) } +}; +#endif + const float dft_win232ms_8k[75] = { @@ -342,6 +390,34 @@ const float min_smooth_gains2[SBA_DIRAC_STEREO_NUM_BANDS] = 0.5f, 0.5f, 0.5, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.3f, 0.3f, 0.3f }; +#ifdef IVAS_FLOAT_FIXED +const Word16 max_smooth_gains1_fx[SBA_DIRAC_STEREO_NUM_BANDS] = +{ + (Word16)(0x7D71), (Word16)(0x7C29), (Word16)(0x799A), (Word16)(0x7333), + (Word16)(0x7333), (Word16)(0x7333), (Word16)(0x7333), (Word16)(0x7333), + (Word16)(0x7333), (Word16)(0x7333), (Word16)(0x7333), (Word16)(0x7333) +}; + +const Word16 min_smooth_gains1_fx[SBA_DIRAC_STEREO_NUM_BANDS] = +{ + (Word16)(0x0000), (Word16)(0x0000), (Word16)(0x6000), (Word16)(0x6000), + (Word16)(0x0000), (Word16)(0x0000), (Word16)(0x0000), (Word16)(0x0000), + (Word16)(0x0000), (Word16)(0x0000), (Word16)(0x0000), (Word16)(0x0000) +}; +const Word16 max_smooth_gains2_fx[SBA_DIRAC_STEREO_NUM_BANDS] = +{ + (Word16)(0x6000), (Word16)(0x6000), (Word16)(0x6000), (Word16)(0x6000), + (Word16)(0x6000), (Word16)(0x6000), (Word16)(0x6000), (Word16)(0x6000), + (Word16)(0x6000), (Word16)(0x7333), (Word16)(0x7333), (Word16)(0x7333)}; + +const Word16 min_smooth_gains2_fx[SBA_DIRAC_STEREO_NUM_BANDS] = +{ + (Word16)(0x4000), (Word16)(0x4000), (Word16)(0x4000), (Word16)(0x4000), + (Word16)(0x4000), (Word16)(0x4000), (Word16)(0x4000), (Word16)(0x4000), + (Word16)(0x4000), (Word16)(0x2666), (Word16)(0x2666), (Word16)(0x2666) +}; +#endif + /*------------------------------------------------------------------------- * ECLVQ Stereo ROM tables *------------------------------------------------------------------------*/ diff --git a/lib_dec/ivas_rom_dec.h b/lib_dec/ivas_rom_dec.h index 32b7c95911d1bc6f30b9e76f1f6281e7dc0d047b..165b7f3eec653a935206a8f624192360fd6525db 100644 --- a/lib_dec/ivas_rom_dec.h +++ b/lib_dec/ivas_rom_dec.h @@ -49,6 +49,12 @@ extern const float dft_alpha_s_b2[STEREO_DFT_BAND_MAX]; extern const float dft_alpha_s2_b2[STEREO_DFT_BAND_MAX]; extern const float dft_bpf_weights[]; #ifdef IVAS_FLOAT_FIXED +extern const Word16 dft_alpha_s_fx[STEREO_DFT_BAND_MAX]; +extern const Word16 dft_alpha_w_fx[STEREO_DFT_BAND_MAX]; +extern const Word16 dft_alpha_s2_fx[STEREO_DFT_BAND_MAX]; +extern const Word16 dft_alpha_s_b2_fx[STEREO_DFT_BAND_MAX]; +extern const Word16 dft_alpha_w_b2_fx[STEREO_DFT_BAND_MAX]; +extern const Word16 dft_alpha_s2_b2_fx[STEREO_DFT_BAND_MAX]; extern const Word32 dft_bpf_weights_fx[]; extern const Word32 dft_ap_gains_fx[5][3]; #endif @@ -74,6 +80,8 @@ extern const Word16 dft_win232ms_12k8_fx[120]; extern const Word16 dft_win232ms_16k_fx[150]; extern const Word16 dft_win232ms_32k_fx[300]; extern const Word16 dft_win232ms_48k_fx[450]; +extern const Word16 dft_res_pred_weights_fx[][STEREO_DFT_BAND_MAX]; +extern const Word16 dft_win_8k_fx[70]; #endif extern const float dft_win_8k[70]; @@ -85,6 +93,12 @@ extern const float max_smooth_gains1[SBA_DIRAC_STEREO_NUM_BANDS]; extern const float min_smooth_gains2[SBA_DIRAC_STEREO_NUM_BANDS]; extern const float max_smooth_gains2[SBA_DIRAC_STEREO_NUM_BANDS]; +#ifdef IVAS_FLOAT_FIXED +extern const Word16 min_smooth_gains1_fx[SBA_DIRAC_STEREO_NUM_BANDS]; +extern const Word16 max_smooth_gains1_fx[SBA_DIRAC_STEREO_NUM_BANDS]; +extern const Word16 min_smooth_gains2_fx[SBA_DIRAC_STEREO_NUM_BANDS]; +extern const Word16 max_smooth_gains2_fx[SBA_DIRAC_STEREO_NUM_BANDS]; +#endif /*----------------------------------------------------------------------------------* * ECLVQ Stereo ROM tables diff --git a/lib_dec/ivas_sba_dirac_stereo_dec.c b/lib_dec/ivas_sba_dirac_stereo_dec.c index 1a67a1aecb82d61f764e843b4cde593b4af3ebae..f8bdb85ec9b4b801acdceafd0b92192e7553a05b 100644 --- a/lib_dec/ivas_sba_dirac_stereo_dec.c +++ b/lib_dec/ivas_sba_dirac_stereo_dec.c @@ -43,6 +43,7 @@ #include "wmc_auto.h" +#ifndef IVAS_FLOAT_FIXED /*-------------------------------------------------------------------* * ivas_get_sba_dirac_stereo_flag() * @@ -114,6 +115,7 @@ void ivas_sba_dirac_stereo_config( return; } +#endif /*-------------------------------------------------------------------* @@ -848,6 +850,9 @@ void ivas_sba_dirac_stereo_dec( ivas_sba_dirac_stereo_config( hStereoDft->hConfig ); hStereoDft->nbands = ivas_sba_dirac_stereo_band_config( hStereoDft->band_limits, st_ivas->hDecoderConfig->output_Fs, hStereoDft->NFFT, ( ( st_ivas->ivas_format == SBA_FORMAT || st_ivas->ivas_format == SBA_ISM_FORMAT ) && !mcmasa ) ); stereo_dft_dec_update( hStereoDft, output_frame, 1 /*st_ivas->sba_dirac_stereo_flag*/ ); +#ifdef IVAS_FLOAT_FIXED + stereo_dft_dec_update_fx( hCPE->hStereoDft, output_frame, 0 ); +#endif if ( st_ivas->nchan_transport > 1 ) { stereo_dft_dec_analyze( hCPE, output[0], DFT, 0, output_frame, output_frame, DFT_STEREO_DEC_ANA_FB, 0, 0 ); diff --git a/lib_dec/ivas_sba_dirac_stereo_dec_fx.c b/lib_dec/ivas_sba_dirac_stereo_dec_fx.c new file mode 100644 index 0000000000000000000000000000000000000000..887fd3a277502e2e9b0eebc62ac444e30b5e1981 --- /dev/null +++ b/lib_dec/ivas_sba_dirac_stereo_dec_fx.c @@ -0,0 +1,1229 @@ +/****************************************************************************************************** + + (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 +#include "options.h" +#include "cnst.h" +#include "ivas_cnst.h" +#include "prot_fx2.h" +#include "ivas_prot.h" +#include "ivas_prot_fx.h" +#include "ivas_rom_com.h" +#include "ivas_rom_com_fx.h" +#include "ivas_rom_dec.h" +#include "wmc_auto.h" + +#ifdef IVAS_FLOAT_FIXED +#define SIN_NEG_30_DEGREES_Q15 ((Word16)0xC000) +#define SIN_30_DEGREES_Q15 ((Word16)0x4000) + +/*-------------------------------------------------------------------* + * ivas_get_sba_dirac_stereo_flag() + * + * Set sba_dirac_stereo_flag + *-------------------------------------------------------------------*/ + +Word16 ivas_get_sba_dirac_stereo_flag( + Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */ +) +{ + Word16 sba_dirac_stereo_flag; + AUDIO_CONFIG output_config; + + sba_dirac_stereo_flag = 0; + move16(); + output_config = st_ivas->hDecoderConfig->output_config; + move16(); + + IF ( EQ_16(st_ivas->ivas_format, SBA_FORMAT) || (EQ_16( st_ivas->ivas_format, MC_FORMAT) && EQ_16(st_ivas->mc_mode, MC_MODE_MCMASA )) ) + { + IF ( EQ_16(st_ivas->ivas_format, SBA_FORMAT )) + { + IF ( EQ_16(output_config, IVAS_AUDIO_CONFIG_STEREO) || ( EQ_16(output_config, IVAS_AUDIO_CONFIG_MONO) && EQ_16(st_ivas->nchan_transport, 1) ) ) + { + sba_dirac_stereo_flag = 1; + move16(); + } + } + ELSE + { + IF ( EQ_16(st_ivas->nchan_transport, 1) && EQ_16(output_config, IVAS_AUDIO_CONFIG_STEREO) ) + { + sba_dirac_stereo_flag = 1; + move16(); + } + } + } + ELSE IF ( EQ_16(st_ivas->ivas_format, SBA_ISM_FORMAT) ) + { + IF ( EQ_16(output_config, IVAS_AUDIO_CONFIG_STEREO) ) + { + sba_dirac_stereo_flag = 1; + move16(); + } + } + + return sba_dirac_stereo_flag; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_config() + * + * DFT Stereo Configuration for SBA DirAC stereo output + *-------------------------------------------------------------------*/ + +void ivas_sba_dirac_stereo_config( + STEREO_DFT_CONFIG_DATA_HANDLE hConfig /* o : DFT stereo configuration */ +) +{ + IF ( hConfig != NULL ) + { + hConfig->dmx_active = STEREO_DFT_DMX_ACTIVE; + move16(); + hConfig->band_res = STEREO_DFT_BAND_RES_HIGH; + move16(); + hConfig->prm_res = 2; + move16(); + + hConfig->res_pred_mode = STEREO_DFT_RESPRED_ESF; + move16(); + + hConfig->res_cod_mode = STEREO_DFT_RES_COD_OFF; + move16(); + hConfig->ada_wb_res_cod_mode = 0; + move16(); + + hConfig->hybrid_itd_flag = 0; + move16(); + } + + return; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_band_config() + * + * Band Configuration for SBA DirAC stereo output + *-------------------------------------------------------------------*/ + +static Word16 ivas_sba_dirac_stereo_band_config( + Word16 *band_limits, /* o : DFT band limits */ + const Word32 output_Fs, /* i : output sampling rate */ + const Word16 NFFT, /* i : analysis/synthesis window length */ + const Word16 spar_flag /* i : SPAR or DirAC band grouping */ +) +{ + Word16 i; + Word16 bins_per_cldfb_band; + Word16 nbands, num_cldfb_bands; + + nbands = SBA_DIRAC_STEREO_NUM_BANDS; + move16(); + + IF ( spar_flag ) + { + nbands = IVAS_MAX_NUM_BANDS; + move16(); + } + ELSE + { + nbands = 5; + move16(); + } + + SWITCH (output_Fs) + { + case 8000: + num_cldfb_bands = 10; + move16(); + BREAK; + case 16000: + num_cldfb_bands = 20; + move16(); + BREAK; + case 32000: + num_cldfb_bands = 40; + move16(); + BREAK; + case 48000: + num_cldfb_bands = 60; + move16(); + BREAK; + default: + num_cldfb_bands = 60; + move16(); + assert(0); + } + + bins_per_cldfb_band = (NFFT / ( 2 * num_cldfb_bands )); + move16(); + band_limits[0] = 1; + move16(); + FOR ( i = 1; i < nbands; i++ ) + { + IF ( spar_flag ) + { + band_limits[i] = i_mult(DirAC_band_grouping_12[i], bins_per_cldfb_band); + move16(); + } + ELSE + { + band_limits[i] = i_mult(DirAC_band_grouping_5[i], bins_per_cldfb_band); + move16(); + } + IF ( GE_16(band_limits[i], shr(NFFT, 1) ) ) + { + nbands = i; + move16(); + BREAK; + } + } + band_limits[nbands] = shr(NFFT, 1); + move16(); + + return nbands; +} + +static Word16 get_panning_tangent_gain( + const Word16 sinAngleMapped) +{ + Word16 tbl_len = sizeof(ivas_sine_panning_tbl_fx) / sizeof(ivas_sine_panning_tbl_fx[0]); move16(); + Word16 idx = shr(tbl_len, 1); move16(); + const Word16 *ptr_sin = &ivas_sine_panning_tbl_fx[0]; + const Word16 *ptr_tan = &ivas_tan_panning_gain_dirac_tbl_fx[0]; + Word16 lim_l = 0; + move16(); + Word16 lim_r = tbl_len; + move16(); + WHILE (1) + { + idx = shr( add( lim_l, lim_r ), 1 ); + IF (GE_16(idx, tbl_len)) + { + return ptr_tan[tbl_len - 1]; + } + ELSE IF (LE_16(idx, 0)) + { + return ptr_tan[0]; + } + ELSE IF ( LE_16(sinAngleMapped, ptr_sin[idx + 1]) && GE_16(sinAngleMapped, ptr_sin[idx])) + { + IF (EQ_16(sinAngleMapped, ptr_sin[idx + 1])) + { + return ptr_tan[idx + 1]; + } + ELSE IF(EQ_16(sinAngleMapped, ptr_sin[idx])) + { + return ptr_tan[idx]; + } + ELSE + { + Word16 mid = add(shr( ptr_sin[idx], 1 ), shr(ptr_sin[idx + 1], 1)); + move16(); + IF( LE_16( sinAngleMapped, mid ) ) + { + return ptr_tan[idx]; + } + ELSE + { + return ptr_tan[idx + 1]; + } + } + } + ELSE IF (GT_16( sinAngleMapped, ptr_sin[idx] )) + { + lim_l = add( idx, 1 ); + move16(); + } + ELSE IF (LT_16(sinAngleMapped, ptr_sin[idx])) + { + lim_r = sub( idx, 1 ); + move16(); + } + } +} + +static Word16 get_panning( + const Word16 aziDeg, + const Word16 eleDeg ) +{ + Word16 panning = 0; move16(); + Word16 azAddEl = aziDeg + eleDeg; move16(); + Word16 azSubEl = aziDeg - eleDeg; move16(); + const Word16 *ptr_sin_az = &ivas_sin_az_fx[180]; + while (azAddEl > 180) + { + azAddEl = azAddEl - 360; + move16(); + } + while (azAddEl < -180) + { + azAddEl = azAddEl + 360; + move16(); + } + while (azSubEl > 180) + { + azSubEl = azSubEl - 360; + move16(); + } + while (azSubEl < -180) + { + azSubEl = azSubEl + 360; + move16(); + } + /*sin(az)cos(el) = 0.5 * (sin(az + el) + sin(az - el)) */ + Word16 sin_az_cos_el = add(shr(ptr_sin_az[azAddEl], 1), shr(ptr_sin_az[azSubEl], 1)); + move16(); + IF (GE_32(sin_az_cos_el, SIN_30_DEGREES_Q15)) + { /* Left side */ + panning = (Word16)0x7fff; + move16(); + } + ELSE IF (LE_32(sin_az_cos_el, SIN_NEG_30_DEGREES_Q15)) + { /* Right side */ + panning = (Word16)0x8000; + move16(); + } + ELSE + { /* Tangent panning law */ + panning = get_panning_tangent_gain(sin_az_cos_el); + } + return panning; +} + + +/*-------------------------------------------------------------------* + * map_params_dirac_to_stereo() + * + * Compute DFT Stereo parameters from DirAC parameters + *-------------------------------------------------------------------*/ + +static void map_params_dirac_to_stereo( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const IVAS_QMETADATA_HANDLE hQMetaData, /* i : frame of MASA q_metadata */ + Word32 synth[], /* i : decoded downmix signal */ + Word32 DFT[STEREO_DFT_BUF_MAX], /* i/o: DFT buffer */ + const UWord8 b_wide_panning, /* i : flag indicating wider panning */ + const Word16 L_frame, /* i : core signal length */ + const Word16 mcmasa, /* i : McMASA flag */ + Word16 q_dft +) +{ + Word16 i, b, k; + Word16 k_offset; + Word16 nbands, nBlocks; + Word16 block; + Word16 block_len; + Word16 azimuth[MAX_PARAM_SPATIAL_SUBFRAMES][SBA_DIRAC_STEREO_NUM_BANDS]; + Word16 elevation[MAX_PARAM_SPATIAL_SUBFRAMES][SBA_DIRAC_STEREO_NUM_BANDS]; + Word32 diffuseness[SBA_DIRAC_STEREO_NUM_BANDS]; + Word32 block_nrg[MAX_PARAM_SPATIAL_SUBFRAMES]; + Word32 nrg_norm1, nrg_norm2; + Word32 *pSynth; + Word32 surrCoh[SBA_DIRAC_STEREO_NUM_BANDS]; + Word32 *pDFT; + Word32 subframe_band_nrg[NB_DIV][SBA_DIRAC_STEREO_NUM_BANDS]; + Word16 q_nrg; + Word32 smooth_long_avg[NB_DIV][SBA_DIRAC_STEREO_NUM_BANDS]; + Word32 smooth_short_avg[NB_DIV][SBA_DIRAC_STEREO_NUM_BANDS]; + Word32 *side_gain, *res_pred_gain; + IVAS_QDIRECTION *q_direction; + Word16 q_div, q_sqrt; + const Word16 *ptr_sin_az = &ivas_sin_az_fx[180]; + const Word16 *ptr_cos_el = &ivas_sin_az_fx[270]; + + nBlocks = MAX_PARAM_SPATIAL_SUBFRAMES; + move16(); + nbands = hStereoDft->nbands; + move16(); + k_offset = STEREO_DFT_OFFSET; + move16(); + side_gain = hStereoDft->side_gain_fx + i_mult(k_offset, STEREO_DFT_BAND_MAX); + res_pred_gain = hStereoDft->res_pred_gain_fx + i_mult(k_offset, STEREO_DFT_BAND_MAX); + q_direction = &( hQMetaData->q_direction[0] ); + + /* gain smoothing factor */ + pDFT = DFT; + q_nrg = q_dft; + move16(); + FOR ( k = 0; k < NB_DIV; k++ ) + { + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + /* calculate band-wise subframe energies */ + subframe_band_nrg[k][b] = 0; + move32(); + FOR ( i = hStereoDft->band_limits[b]; i < hStereoDft->band_limits[b + 1]; i++ ) + { + subframe_band_nrg[k][b] = L_add(subframe_band_nrg[k][b], + Madd_32_32(Mpy_32_32(pDFT[2 * i], pDFT[2 * i]), + pDFT[2 * i + 1], pDFT[2 * i + 1])); + move32(); + } + subframe_band_nrg[k][b] = Sqrt32( subframe_band_nrg[k][b], &q_nrg ); + move32(); + hStereoDft->smooth_buf_fx[b][NB_DIV - 1 - k] = subframe_band_nrg[k][b]; + move32(); + + /* calculate short and long energy averages */ + smooth_short_avg[k][b] = EPSILON_FIX; + move32(); + FOR ( i = sub(NB_DIV - 1, k); i < add(SBA_DIRAC_NRG_SMOOTH_SHORT + NB_DIV - 1, k); i++ ) + { + smooth_short_avg[k][b] = L_add(smooth_short_avg[k][b], hStereoDft->smooth_buf_fx[b][i]); + move32(); + } + + smooth_long_avg[k][b] = smooth_short_avg[k][b]; + move32(); + FOR ( i = sub(NB_DIV - 1 + SBA_DIRAC_NRG_SMOOTH_SHORT, k) ; i < sub(SBA_DIRAC_NRG_SMOOTH_LONG + NB_DIV - 1, k); i++ ) + { + smooth_long_avg[k][b] = L_add(smooth_long_avg[k][b], hStereoDft->smooth_buf_fx[b][i]); + move32(); + } + smooth_short_avg[k][b] = Mpy_32_16_1(smooth_short_avg[k][b], (Word16)0x2AAB); /* 1/ 3 in Q15*/ + move32(); + smooth_long_avg[k][b] = Mpy_32_16_1(smooth_long_avg[k][b], (Word16)0x0CCD); /* 1/ 10 in Q15*/ + move32(); + + /* calculate smoothing factor based on energy averages */ + /* reduce factor for higher short-term energy */ + hStereoDft->smooth_fac_fx[k][b] = extract_l(s_min( MAX_16, BASOP_Util_Divide3232_Scale(smooth_long_avg[k][b] , smooth_short_avg[k][b], &q_div) )); + move32(); + IF (GT_16(q_div, 0)) + { + assert(0); + } + ELSE + { + hStereoDft->smooth_fac_fx[k][b] = shl(hStereoDft->smooth_fac_fx[k][b], q_div); + q_div = 0; + } + /* map factor to range [0;1] */ + hStereoDft->smooth_fac_fx[k][b] = extract_l(Mpy_32_16_1(SBA_DIRAC_NRG_SMOOTH_LONG_BY_LONG_SHORT_FX, s_max( 0, sub(hStereoDft->smooth_fac_fx[k][b] , SBA_DIRAC_NRG_SMOOTH_SHORT_BY_LONG_FX)))); + move16(); + /* compress factor (higher compression in lowest bands) */ + IF ( LT_16(b, 2) ) + { + hStereoDft->smooth_fac_fx[k][b] = Sqrt16(Sqrt16( hStereoDft->smooth_fac_fx[k][b], &q_sqrt), &q_sqrt); + move16(); + } + ELSE + { + hStereoDft->smooth_fac_fx[k][b] = Sqrt16( hStereoDft->smooth_fac_fx[k][b], &q_sqrt ); + move16(); + } + + /* apply upper bounds depending on band */ + hStereoDft->smooth_fac_fx[0][b] = s_max( hStereoDft->min_smooth_gains_fx[b], s_min( hStereoDft->max_smooth_gains_fx[b], hStereoDft->smooth_fac_fx[0][b] ) ); + move16(); + hStereoDft->smooth_fac_fx[1][b] = s_max( hStereoDft->min_smooth_gains_fx[b], s_min( hStereoDft->max_smooth_gains_fx[b], hStereoDft->smooth_fac_fx[1][b] ) ); + move16(); + } + pDFT += STEREO_DFT32MS_N_MAX; + } + + IF ( mcmasa ) + { + /* calculate block energies for side gain weighting (combine angles of 2 DirAC blocks to side gain for 1 DFT Stereo subframe; 4 blocks and 2 subframes overall) */ + pSynth = synth; + block_len = L_frame / nBlocks; + FOR ( block = 0; block < nBlocks; block++ ) + { + block_nrg[block] = 0; + FOR ( i = 0; i < block_len; i++ ) + { + block_nrg[block] = Madd_32_32(block_nrg[block], pSynth[i] , pSynth[i]); + move32(); + } + block_nrg[block] = Sqrt32( block_nrg[block], 0); + move32(); + pSynth += block_len; + } + nrg_norm1 = L_deposit_l(BASOP_Util_Divide3232_Scale(MAX_32, L_add(block_nrg[0] , L_add(block_nrg[1] , EPSILON_FIX) ), &q_div)); + IF (NE_16(q_div, 0)) + { + assert(0); + } + nrg_norm2 = L_deposit_l(BASOP_Util_Divide3232_Scale(MAX_32, L_add(block_nrg[2] , L_add(block_nrg[3] , EPSILON_FIX) ), &q_div)); + IF (NE_16(q_div, 0)) + { + assert(0); + } + + /* extract DirAC parameters from metadata */ + FOR ( b = 0; b < nbands; b++ ) + { + diffuseness[b] = L_sub(MAX_32 , q_direction->band_data[b].energy_ratio_fx[0]); + move32(); + IF ( hQMetaData->surcoh_band_data != NULL ) + { + surrCoh[b] = L_shr(Mpy_32_16_1(hQMetaData->surcoh_band_data[b].surround_coherence[0], (Word16)0x0101), 1); + move32(); + } + ELSE + { + surrCoh[b] = 0; + move32(); + } + + FOR ( block = 0; block < nBlocks; block++ ) + { + Word16 block_metadata; + + IF ( hQMetaData->useLowerRes ) + { + block_metadata = 0; + move16(); + } + ELSE + { + block_metadata = block; + move16(); + } + IF ( LT_32(q_direction->band_data[b].azimuth_fx[block_metadata], 0) ) + { + q_direction->band_data[b].azimuth_fx[block_metadata] = L_add(360, q_direction->band_data[b].azimuth_fx[block_metadata]); + move16(); + } + azimuth[block][b] = (Word16)q_direction->band_data[b].azimuth_fx[block_metadata]; + move16(); + elevation[block][b] = (Word16)q_direction->band_data[b].elevation_fx[block_metadata]; + move16(); + } + } + + /* map angles (azi, ele), surround coherence, and diffuseness to DFT Stereo side and prediction gains */ + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + /* combine angles of first 2 blocks to side gain of first subframe */ + side_gain[b] = 0; + move32(); + FOR ( block = 0; block < nBlocks / 2; block++ ) + { + IF ( EQ_16(b_wide_panning, 1) ) + { + /* panning between left and ride, saturate at the stereo ls positions (+/- 30deg azi) */ + side_gain[b] = Madd_32_32(side_gain[b], nrg_norm1, Mpy_32_16_1(block_nrg[block] , get_panning( azimuth[block][b], elevation[block][b]) )); + move32(); + } + ELSE + { + side_gain[b] = Madd_32_32(side_gain[b], nrg_norm1, Mpy_32_16_1(block_nrg[block] , mult(ptr_sin_az[azimuth[block][b]] , ptr_cos_el[elevation[block][b]]))); + move32(); + } + } + + /* combine angles of last 2 blocks to side gain of second subframe */ + side_gain[b + STEREO_DFT_BAND_MAX] = 0; + move32(); + FOR ( block = nBlocks / 2; block < nBlocks; block++ ) + { + IF ( EQ_16(b_wide_panning, 1) ) + { + /* panning between left and ride, saturate at the stereo ls positions (+/- 30deg azi) */ + side_gain[b + STEREO_DFT_BAND_MAX] = Madd_32_32(side_gain[b + STEREO_DFT_BAND_MAX], nrg_norm2 , Mpy_32_16_1(block_nrg[block] , get_panning( azimuth[block][b], elevation[block][b]))); + move32(); + } + ELSE + { + side_gain[b + STEREO_DFT_BAND_MAX] = Madd_32_32(side_gain[b + STEREO_DFT_BAND_MAX], nrg_norm2 , Mpy_32_16_1(block_nrg[block] , mult( ptr_sin_az[azimuth[block][b]] , ptr_cos_el[elevation[block][b]]))); + move32(); + } + } + + side_gain[b] = Mpy_32_32(side_gain[b], Sqrt32(L_sub((Word32)0x7FFFFFFF, diffuseness[b]), &q_sqrt)); + move32(); + IF (NE_16(q_sqrt, 0)) + { + assert(0); + } + side_gain[b + STEREO_DFT_BAND_MAX] = Mpy_32_32(side_gain[b + STEREO_DFT_BAND_MAX], Sqrt32(L_sub((Word32)0x7FFFFFFF, diffuseness[b]), &q_sqrt)); + move32(); + IF (NE_16(q_sqrt, 0)) + { + assert(0); + } + res_pred_gain[b] = Mpy_32_32(diffuseness[b], L_sub((Word32)0x7FFFFFFF, surrCoh[b] )); + move32(); + res_pred_gain[b + STEREO_DFT_BAND_MAX] = Mpy_32_32(diffuseness[b], L_sub((Word32)0x7FFFFFFF, surrCoh[b]) ); + move32(); + } + } + + hStereoDft->frame_nodata = 0; + move16(); + hStereoDft->frame_sid_nodata = 0; + move16(); + hStereoDft->frame_sid = 0; + move16(); + + return; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_compute_td_stefi_nrgs() + * + * Compute energies for TD stereo filling + *-------------------------------------------------------------------*/ + +static void ivas_sba_dirac_stereo_compute_td_stefi_nrgs( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word32 hb_synth[L_FRAME48k], /* i : HB signal */ + const Word16 core, /* i : core decision */ + const Word16 output_frame, /* i : output frame length per channel */ + const Word16 fd_cng_flag /* i : FD-CNG indicator */ +) +{ + Word16 i; + Word32 hb_nrg = EPSILON_FIX; move32(); + Word32 hb_nrg2 = EPSILON_FIX; move32(); + + IF ( ( EQ_16(core, ACELP_CORE) && EQ_16(fd_cng_flag, 0) ) || EQ_16(hStereoDft->core_hist[1], ACELP_CORE) ) + { + FOR ( i = 0; i < shr(output_frame, 2); i++ ) + { + hb_nrg2 = Madd_32_32(hb_nrg2, hb_synth[i], hb_synth[i]); + } + + hStereoDft->hb_nrg_subr_fx[0] = hb_nrg2; + move32(); + hb_nrg = L_add(hb_nrg, hb_nrg2); + hb_nrg2 = EPSILON_FIX; + move32(); + + FOR ( ; i < output_frame; i++ ) + { + hb_nrg2 = Madd_32_32(hb_nrg2, hb_synth[i], hb_synth[i]); + } + + hStereoDft->hb_nrg_subr_fx[1] = hb_nrg2; + move32(); + hb_nrg = L_add(hb_nrg, hb_nrg2); + + Copy32( hb_synth, hStereoDft->hb_stefi_sig_fx + hStereoDft->hb_stefi_delay, output_frame ); + } + ELSE + { + set_val_Word32( hStereoDft->hb_stefi_sig_fx + hStereoDft->hb_stefi_delay, 0, output_frame); + } + hStereoDft->hb_nrg_subr_fx[0] = (hStereoDft->hb_nrg_subr_fx[0] * shr(hStereoDft->NFFT, 1)); + move32(); + hStereoDft->hb_nrg_subr_fx[1] = (hStereoDft->hb_nrg_subr_fx[1] * shr(hStereoDft->NFFT, 1)); + move32(); + IF (LE_32(hStereoDft->hb_nrg_subr_fx[0] , 0) || LE_32(hStereoDft->hb_nrg_subr_fx[1] , 0)) + { + assert(0); + } + hStereoDft->hb_nrg_fx[0] = hb_nrg; + move32(); + hStereoDft->td_gain_fx[0] = 0; + move32(); + hStereoDft->core_hist[0] = ( fd_cng_flag ) ? TCX_20_CORE : core; /* full signal available for DTX with FD-CNG, thus apply stereo filling on full spectrum like in TCX */ + move16(); + return; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_compute_hb_gain() + * + * Compute HB gains + *-------------------------------------------------------------------*/ + +static void ivas_sba_dirac_stereo_compute_hb_gain( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + Word32 hb_gain[NB_DIV] /* o : side gains for HB signal */ +) +{ + Word16 k_offset; + + k_offset = STEREO_DFT_OFFSET; + move16(); + + /* last band covers whole HB range, no averaging needed */ + hb_gain[0] = hStereoDft->side_gain_fx[k_offset * STEREO_DFT_BAND_MAX + hStereoDft->nbands - 1]; + move32(); + hb_gain[1] = hStereoDft->side_gain_fx[( k_offset + 1 ) * STEREO_DFT_BAND_MAX + hStereoDft->nbands - 1]; + move32(); + + return; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_upmix_hb() + * + * Apply panning to HB signal + *-------------------------------------------------------------------*/ + +static void ivas_sba_dirac_stereo_upmix_hb( + Word32 hb_stereo_synth[CPE_CHANNELS][L_FRAME48k], /* i/o: stereo HB synthesis signal */ + Word32 hb_synth[L_FRAME48k], /* i : HB signal */ + Word32 hb_gain[NB_DIV], /* i : side gains for HB signal */ + const Word16 output_frame, /* i : output frame length per channel */ + const Word16 mcmasa, /* i : McMASA flag */ + const Word16 sba_mono_flag, /* i : flag for mono output */ + const Word16 bwidth, /* i : bandwidth of signal */ + const STEREO_DFT_DEC_DATA_HANDLE hStereoDft /* i : Stereo DFT handle for mixing matrix */ +) +{ + Word16 i; + Word32 gp, gm; + Word32 gain_fac; + + IF ( EQ_16(mcmasa, 0) ) + { + gain_fac = ( bwidth == FB ) ? (Word32)0x20000000 : (Word32)0x2A3D70A4; /* last matrix element not used for SWB, divide by 3 instead of 4*/ + IF ( sba_mono_flag ) + { + gp = L_add(hStereoDft->mixer_mat_smooth_fx[0][0][8], + L_add(hStereoDft->mixer_mat_smooth_fx[0][0][9], + hStereoDft->mixer_mat_smooth_fx[0][0][10])); + IF ( EQ_16(bwidth, FB) ) + { + gp = L_add(gp, hStereoDft->mixer_mat_smooth_fx[0][0][11]); + } + FOR ( i = 0; i < shr(output_frame, 1); i++ ) + { + hb_stereo_synth[0][i] = Mpy_32_32(hb_synth[i] , Mpy_32_32( gain_fac , gp)); + move32(); + } + gp = L_add(hStereoDft->mixer_mat_smooth_fx[0][0][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][0][9 + IVAS_MAX_NUM_BANDS], + hStereoDft->mixer_mat_smooth_fx[0][0][10 + IVAS_MAX_NUM_BANDS])); + IF ( EQ_16(bwidth, FB) ) + { + gp = L_add(gp, hStereoDft->mixer_mat_smooth_fx[0][0][11 + IVAS_MAX_NUM_BANDS]); + } + FOR ( i = shr(output_frame , 1); i < output_frame; i++ ) + { + hb_stereo_synth[0][i] = Mpy_32_32(Mpy_32_32(hb_synth[i] , gain_fac), gp); + } + } + ELSE + { + gp = L_add(hStereoDft->mixer_mat_smooth_fx[0][0][8] , + L_add(hStereoDft->mixer_mat_smooth_fx[1][0][8] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][0][9] , + L_add(hStereoDft->mixer_mat_smooth_fx[1][0][9] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][0][10] , + hStereoDft->mixer_mat_smooth_fx[1][0][10]))))); + IF ( EQ_32(bwidth , FB) ) + { + gp = L_add(gp, L_add(hStereoDft->mixer_mat_smooth_fx[0][0][11] , hStereoDft->mixer_mat_smooth_fx[1][0][11])); + } + + gm = L_add(L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][8] , hStereoDft->mixer_mat_smooth_fx[1][0][8]) , + L_add(L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][9] , hStereoDft->mixer_mat_smooth_fx[1][0][9]) , + L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][10] , hStereoDft->mixer_mat_smooth_fx[1][0][10]))); + IF ( EQ_32(bwidth , FB) ) + { + gm = L_add(gm, L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][11] , hStereoDft->mixer_mat_smooth_fx[1][0][11])); + } + + FOR ( i = 0; i < output_frame / 2; i++ ) + { + hb_stereo_synth[0][i] = L_shr(Mpy_32_32(Mpy_32_32(hb_synth[i] , gain_fac) , gp), 1); + move32(); + hb_stereo_synth[1][i] = L_shr(Mpy_32_32(Mpy_32_32(hb_synth[i] , gain_fac) , gm), 1); + move32(); + } + + gp = L_add(hStereoDft->mixer_mat_smooth_fx[0][0][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][0][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][0][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][0][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][0][10 + IVAS_MAX_NUM_BANDS], + hStereoDft->mixer_mat_smooth_fx[1][0][10 + IVAS_MAX_NUM_BANDS]))))); + IF ( EQ_32(bwidth , FB) ) + { + gp = L_add(gp, L_add(hStereoDft->mixer_mat_smooth_fx[0][0][11 + IVAS_MAX_NUM_BANDS] , hStereoDft->mixer_mat_smooth_fx[1][0][11 + IVAS_MAX_NUM_BANDS])); + } + + gm = L_add(L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][8 + IVAS_MAX_NUM_BANDS] , hStereoDft->mixer_mat_smooth_fx[1][0][8 + IVAS_MAX_NUM_BANDS]), + L_add(L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][9 + IVAS_MAX_NUM_BANDS] , hStereoDft->mixer_mat_smooth_fx[1][0][9 + IVAS_MAX_NUM_BANDS]), + L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][10 + IVAS_MAX_NUM_BANDS] , hStereoDft->mixer_mat_smooth_fx[1][0][10 + IVAS_MAX_NUM_BANDS]))); + IF ( EQ_32(bwidth , FB) ) + { + gm = L_add(gm, L_sub(hStereoDft->mixer_mat_smooth_fx[0][0][11 + IVAS_MAX_NUM_BANDS] , hStereoDft->mixer_mat_smooth_fx[1][0][11 + IVAS_MAX_NUM_BANDS])); + } + + FOR ( i = shr(output_frame , 1); i < output_frame; i++ ) + { + hb_stereo_synth[0][i] = L_shr(Mpy_32_32(hb_synth[i] , Mpy_32_32(gain_fac , gp)), 1); + move32(); + hb_stereo_synth[1][i] = L_shr(Mpy_32_32(hb_synth[i] , Mpy_32_32(gain_fac , gm)), 1); + move32(); + } + } + } + ELSE + { + FOR ( i = 0; i < L_shr(output_frame , 1); i++ ) + { + hb_stereo_synth[0][i] = L_add(L_shr(hb_synth[i], 1) , L_shr(Mpy_32_32(hb_gain[0] , hb_synth[i]), 1)); + move32(); + hb_stereo_synth[1][i] = L_sub(L_shr(hb_synth[i], 1) , L_shr(Mpy_32_32(hb_gain[0] , hb_synth[i]), 1)); + move32(); + } + + FOR ( i = shr(output_frame, 1); i < output_frame; i++ ) + { + hb_stereo_synth[0][i] = L_add(L_shr(hb_synth[i], 1) , L_shr(Mpy_32_32(hb_gain[1] , hb_synth[i]), 1)); + move32(); + hb_stereo_synth[1][i] = L_sub(L_shr(hb_synth[i], 1) , L_shr(Mpy_32_32(hb_gain[1] , hb_synth[i]), 1)); + move32(); + } + } + + return; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_apply_td_stefi() + * + * Apply TD stereo filling for ACELP HB + *-------------------------------------------------------------------*/ + +static void ivas_sba_dirac_stereo_apply_td_stefi( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + Word32 *output[CPE_CHANNELS], /* i/o: output synthesis signal */ + const Word16 output_frame, /* i : output frame length per channel */ + const Word16 spar_flag /* i : SPAR flag */ +) +{ + Word16 i; + Word16 dftOvlLen; + Word16 win_in, win_out; + Word32 tmp; + const Word16 *win_dft; + + IF ( spar_flag ) + { + win_dft = hStereoDft->win32ms_fx; + dftOvlLen = hStereoDft->dft32ms_ovl; + + Word32 g_W_1, g_Y_1; + Word32 g_W_2, g_Y_2; + Word32 g_L, g_R; + Word32 stefi_L, stefi_R; + + g_W_1 = L_add(hStereoDft->mixer_mat_smooth_fx[0][1][8], + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][8] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][3][8] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][1][9] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][9], + L_add(hStereoDft->mixer_mat_smooth_fx[0][3][9], + L_add( hStereoDft->mixer_mat_smooth_fx[0][1][10], + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][10], + hStereoDft->mixer_mat_smooth_fx[0][3][10]) + ))))))); + + g_Y_1 = L_add( hStereoDft->mixer_mat_smooth_fx[1][1][8], + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][8], + L_add(hStereoDft->mixer_mat_smooth_fx[1][3][8], + L_add( hStereoDft->mixer_mat_smooth_fx[1][1][9], + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][9], + L_add(hStereoDft->mixer_mat_smooth_fx[1][3][9], + L_add(hStereoDft->mixer_mat_smooth_fx[1][1][10], + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][10], + hStereoDft->mixer_mat_smooth_fx[1][3][10]) + ))))))); + + g_W_2 = L_add(hStereoDft->mixer_mat_smooth_fx[0][1][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][3][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][1][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][3][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][1][10 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][10 + IVAS_MAX_NUM_BANDS], + hStereoDft->mixer_mat_smooth_fx[0][3][10 + IVAS_MAX_NUM_BANDS]) + ))))))); + + g_Y_2 = L_add(hStereoDft->mixer_mat_smooth_fx[1][1][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][3][8 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][1][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][3][9 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][1][10 + IVAS_MAX_NUM_BANDS], + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][10 + IVAS_MAX_NUM_BANDS], + hStereoDft->mixer_mat_smooth_fx[1][3][10 + IVAS_MAX_NUM_BANDS]) + ))))))); + + g_L = Mpy_32_16_1(L_sub( L_add(g_W_1 , g_W_2) , L_add(g_Y_1 , g_Y_2) ), 0x147B); /* 0x147B = 0.16 in Q15 */ + g_R = Mpy_32_16_1(L_add( L_add(g_W_1 , g_W_2) , L_add(g_Y_1 , g_Y_2) ), 0x147B); /* 0x147B = 0.16 in Q15 */ + + FOR ( i = 0; i < dftOvlLen; i++ ) + { + win_in = mult_r(win_dft[STEREO_DFT32MS_STEP * i], win_dft[STEREO_DFT32MS_STEP * i]); + win_out = sub(MAX_16, win_in); + + stefi_L = L_shr(Mpy_32_32( Madd_32_16(Mpy_32_32(win_out , hStereoDft->g_L_prev_fx) , g_L , win_in ) , hStereoDft->hb_stefi_sig_fx[i]), 1); + stefi_R = L_shr(Mpy_32_32( Madd_32_16(Mpy_32_32(win_out , hStereoDft->g_R_prev_fx) , g_R , win_in ) , hStereoDft->hb_stefi_sig_fx[i]), 1); + + output[0][i] = L_add(output[0][i], stefi_L); + move32(); + output[1][i] = L_add(output[1][i], stefi_R); + move32(); + } + FOR ( i = dftOvlLen; i < output_frame; i++ ) + { + + stefi_L = L_shr(Mpy_32_32(g_L , hStereoDft->hb_stefi_sig_fx[i]), 1); + stefi_R = L_shr(Mpy_32_32(g_R , hStereoDft->hb_stefi_sig_fx[i]), 1); + + output[0][i] = L_add(output[0][i], stefi_L); + move32(); + output[1][i] = L_add(output[1][i], stefi_R); + move32(); + } + hStereoDft->g_L_prev_fx = g_L; + move32(); + hStereoDft->g_R_prev_fx = g_R; + move32(); + } + ELSE IF ( L_max( hStereoDft->td_gain_fx[0], hStereoDft->td_gain_fx[1] ) > 0 ) + { + win_dft = hStereoDft->win32ms_fx; + dftOvlLen = hStereoDft->dft32ms_ovl; + + FOR ( i = 0; i < dftOvlLen; i++ ) + { + win_in = mult(win_dft[STEREO_DFT32MS_STEP * i] , win_dft[STEREO_DFT32MS_STEP * i]); + win_out = sub(MAX_16 , win_in); + tmp = L_shr(Mpy_32_32(Madd_32_16(Mpy_32_16_1(hStereoDft->td_gain_fx[0], win_in) , hStereoDft->td_gain_fx[1] , win_out) , hStereoDft->hb_stefi_sig_fx[i]), 1); + + output[0][i] = L_add(output[0][i], tmp); + move32(); + output[1][i] = L_sub(output[1][i], tmp); + move32(); + } + FOR ( i = dftOvlLen; i < output_frame; i++ ) + { + tmp = L_shr(hStereoDft->td_gain_fx[0] * hStereoDft->hb_stefi_sig_fx[i], 1); + output[0][i] = L_add(output[0][i], tmp); + move32(); + output[1][i] = L_sub(output[1][i], tmp); + move32(); + } + } + + return; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_smooth_parameters_fx() + * + * Smooth DFT Stereo parameters + *-------------------------------------------------------------------*/ + +void ivas_sba_dirac_stereo_smooth_parameters_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + ivas_spar_md_dec_state_t *hMdDec, /* i/o: SPAR MD handle for upmixing */ + const Word16 cross_fade_start_offset, /* i : SPAR mixer delay compensation */ + const Word32 output_Fs, /* i : Fs for delay calculation */ + const Word16 num_md_sub_frames /* i : number of subframes in mixing matrix */ +) +{ + Word16 i, j, k, i_sf; + Word16 b; + Word16 k_offset; + Word32 *side_gain, *prev_side_gain; + Word32 *res_pred_gain, *prev_res_pred_gain; + + k_offset = STEREO_DFT_OFFSET; + move16(); + prev_side_gain = hStereoDft->side_gain_fx; + side_gain = hStereoDft->side_gain_fx + k_offset * STEREO_DFT_BAND_MAX; + prev_res_pred_gain = hStereoDft->res_pred_gain_fx; + res_pred_gain = hStereoDft->res_pred_gain_fx + k_offset * STEREO_DFT_BAND_MAX; + + IF ( !hMdDec ) + { + /* Smoothing of side and prediction gains between ftrames */ + FOR ( b = hStereoDft->res_pred_band_min; b < hStereoDft->nbands; b++ ) + { + IF ( hStereoDft->attackPresent ) + { + res_pred_gain[b] = Mpy_32_16_1(res_pred_gain[b], (Word16)0x6666); + move32(); + res_pred_gain[b + STEREO_DFT_BAND_MAX] = Mpy_32_16_1(res_pred_gain[b + STEREO_DFT_BAND_MAX], (Word16)0x6666); + move32(); + } + ELSE + { + side_gain[b] = Madd_32_16(Mpy_32_16_1(prev_side_gain[b], hStereoDft->smooth_fac_fx[0][b]), + side_gain[b], sub((Word16)0x7FFF, hStereoDft->smooth_fac_fx[0][b])); + move32(); + side_gain[b + STEREO_DFT_BAND_MAX] = Madd_32_16(Mpy_32_16_1(side_gain[b], hStereoDft->smooth_fac_fx[1][b]), + side_gain[b + STEREO_DFT_BAND_MAX], + sub((Word16)0x7FFF, hStereoDft->smooth_fac_fx[1][b])); + move32(); + res_pred_gain[b] = Madd_32_16(Mpy_32_16_1(prev_res_pred_gain[b], hStereoDft->smooth_fac_fx[0][b]), + res_pred_gain[b], + sub((Word16)0x7FFF, hStereoDft->smooth_fac_fx[0][b])); + move32(); + res_pred_gain[b + STEREO_DFT_BAND_MAX] = Madd_32_16(Mpy_32_16_1(res_pred_gain[b], hStereoDft->smooth_fac_fx[1][b]), + res_pred_gain[b + STEREO_DFT_BAND_MAX], + sub((Word16)0x7FFF, hStereoDft->smooth_fac_fx[1][b] )); + move32(); + } + } + } + + IF ( hMdDec != 0 ) + { + Word64 xfade_start_ns; + Word16 xfade_delay_subframes; + Word16 i_hist; + Word16 md_sf; + + xfade_start_ns = W_sub(W_mult_32_32((Word32)cross_fade_start_offset, 1000000000), W_mult_32_32(IVAS_FB_ENC_DELAY_NS, output_Fs)); + xfade_delay_subframes = (Word16) ( xfade_start_ns / W_mult_32_32(( FRAME_SIZE_NS / MAX_PARAM_SPATIAL_SUBFRAMES ), output_Fs) ); + move16(); + i_hist = 4 - xfade_delay_subframes; + move16(); + FOR ( k = 0; k < 2; k++ ) + { + FOR ( i_sf = k * 2; i_sf < ( k + 1 ) * 2; i_sf++ ) + { + md_sf = (Word16)(EQ_16( num_md_sub_frames, MAX_PARAM_SPATIAL_SUBFRAMES ) ? i_sf : 0); + IF ( hStereoDft->first_frame ) + { + FOR ( i = 0; i < 2; i++ ) + { + FOR ( j = 0; j < 4; j++ ) + { + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + hStereoDft->mixer_mat_smooth_fx[i][j][b + k * IVAS_MAX_NUM_BANDS] = hMdDec->mixer_mat_fx[i][j][b]; + move32(); + } + FOR ( ; b < IVAS_MAX_NUM_BANDS; b++ ) + { + hStereoDft->mixer_mat_smooth_fx[i][j][b + k * IVAS_MAX_NUM_BANDS] = 0; + move32(); + } + } + } + } + ELSE + { + FOR ( i = 0; i < 2; i++ ) + { + FOR ( j = 0; j < 4; j++ ) + { + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + Word16 beta = hStereoDft->smooth_fac_fx[k][b]; + move16(); + hStereoDft->mixer_mat_smooth_fx[i][j][b + k * IVAS_MAX_NUM_BANDS] = + Madd_32_16(Mpy_32_16_1(hStereoDft->mixer_mat_smooth_fx[i][j][b + k * IVAS_MAX_NUM_BANDS], beta), + hMdDec->mixer_mat_prev_fx[i_hist][i][j][b], sub((Word16)0x7FFF, beta)); + move32(); + } + } + } + } + + Copy32( hMdDec->mixer_mat_prev_fx[1][0][0], hMdDec->mixer_mat_prev_fx[0][0][0], IVAS_MAX_FB_MIXER_OUT_CH * IVAS_MAX_SPAR_FB_MIXER_IN_CH * IVAS_MAX_NUM_BANDS ); + Copy32( hMdDec->mixer_mat_prev_fx[2][0][0], hMdDec->mixer_mat_prev_fx[1][0][0], IVAS_MAX_FB_MIXER_OUT_CH * IVAS_MAX_SPAR_FB_MIXER_IN_CH * IVAS_MAX_NUM_BANDS ); + Copy32( hMdDec->mixer_mat_prev_fx[3][0][0], hMdDec->mixer_mat_prev_fx[2][0][0], IVAS_MAX_FB_MIXER_OUT_CH * IVAS_MAX_SPAR_FB_MIXER_IN_CH * IVAS_MAX_NUM_BANDS ); + Copy32( hMdDec->mixer_mat_prev_fx[4][0][0], hMdDec->mixer_mat_prev_fx[3][0][0], IVAS_MAX_FB_MIXER_OUT_CH * IVAS_MAX_SPAR_FB_MIXER_IN_CH * IVAS_MAX_NUM_BANDS ); + + FOR ( i = 0; i < 2; i++ ) + { + FOR ( j = 0; j < 4; j++ ) + { + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + hMdDec->mixer_mat_prev_fx[4][i][j][b] = hMdDec->mixer_mat_fx[i][j][b + md_sf * IVAS_MAX_NUM_BANDS]; + move32(); + } + } + } + } + } + + hStereoDft->first_frame = 0; + move16(); + } + + return; +} + + +/*-------------------------------------------------------------------* + * ivas_sba_dirac_stereo_dec_fx() + * + * Create stereo output for SBA DirAC via DFT stereo + *-------------------------------------------------------------------*/ + +void ivas_sba_dirac_stereo_dec_fx( + Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */ + Word32 *output[CPE_CHANNELS], /* i/o: output synthesis signal */ + const Word16 output_frame, /* i : output frame length per channel */ + const Word16 mcmasa /* i : McMASA flag */ +) +{ + Word16 dtx_flag, fd_cng_flag; + Word16 sba_mono_flag; + Word16 memOffset; + Word32 tmp_buf[NS2SA( 48000, IVAS_DEC_DELAY_NS - DELAY_BWE_TOTAL_NS )]; + Word32 tmp_synth[L_FRAME16k]; + Word32 hb_gain[NB_DIV]; + Word32 hb_synth_stereo[CPE_CHANNELS][L_FRAME48k]; + Word32 DFT[CPE_CHANNELS][STEREO_DFT_BUF_MAX]; + Word16 q_dft = 0; + Word16 q = 0; + SCE_DEC_HANDLE hSCE; + CPE_DEC_HANDLE hCPE; + STEREO_DFT_DEC_DATA_HANDLE hStereoDft; + + hSCE = st_ivas->hSCE[0]; + hCPE = st_ivas->hCPE[0]; + hStereoDft = hCPE->hStereoDft; + q = hCPE->hStereoDft->q_dft; + + IF ( GT_16(st_ivas->nchan_transport, 1) && EQ_16(mcmasa, 0) ) + { + dtx_flag = 0; + move16(); + fd_cng_flag = 0; + move16(); + } + ELSE + { + dtx_flag = (Word16)LE_32(hSCE->hCoreCoder[0]->core_brate, SID_2k40); + fd_cng_flag = ( dtx_flag && EQ_16(hSCE->hCoreCoder[0]->cng_type, FD_CNG) ); + } + sba_mono_flag = (Word16)EQ_16(st_ivas->hDecoderConfig->nchan_out, 1); + + memOffset = NS2SA( L_mult0(output_frame, FRAMES_PER_SEC), L_sub(IVAS_DEC_DELAY_NS, DELAY_BWE_TOTAL_NS) ); + + ivas_sba_dirac_stereo_config( hStereoDft->hConfig ); + hStereoDft->nbands = ivas_sba_dirac_stereo_band_config( hStereoDft->band_limits, st_ivas->hDecoderConfig->output_Fs, hStereoDft->NFFT, ( ( st_ivas->ivas_format == SBA_FORMAT || st_ivas->ivas_format == SBA_ISM_FORMAT ) && !mcmasa ) ); + stereo_dft_dec_update_fx( hStereoDft, output_frame, 1 /*st_ivas->sba_dirac_stereo_flag*/ ); + IF ( GT_16(st_ivas->nchan_transport, 1) ) + { + stereo_dft_dec_analyze_fx( hCPE, output[0], DFT, 0, output_frame, output_frame, DFT_STEREO_DEC_ANA_FB, 0, 0, &q, &q_dft ); + stereo_dft_dec_analyze_fx( hCPE, output[1], DFT, 1, output_frame, output_frame, DFT_STEREO_DEC_ANA_FB, 0, 0, &q, &q_dft ); + hStereoDft->core_hist[0] = hCPE->hCoreCoder[0]->core; + move16(); + } + ELSE + { + /* nrg calculation for TD Stereo Filling, as done in ICBWE which is not used in this case */ + ivas_sba_dirac_stereo_compute_td_stefi_nrgs( hStereoDft, hSCE->save_hb_synth_fx, hSCE->hCoreCoder[0]->core, output_frame, fd_cng_flag ); + + /* do DFT Stereo core switching (including DFT analysis) here as CPE element was not available in SCE decoder */ + Copy32( hSCE->save_synth_fx, tmp_synth, hSCE->hCoreCoder[0]->L_frame ); + stereo_dft_dec_core_switching_fx( hCPE, output[0] /*hSCE->save_output*/, hSCE->save_synth_fx, hSCE->save_hb_synth_fx, DFT, output_frame, 0, dtx_flag, &q, &q_dft ); + + /* do updates here after skipping this in SCE decoder (needs to be done after core switching) */ + ivas_updt_dec_common_fx( hSCE->hCoreCoder[0], NORMAL_HQ_CORE, -1, hSCE->save_synth_fx, q); + } + + /* mapping of DirAC parameters (azimuth, elevation, diffuseness) to DFT Stereo parameters (side gain, prediction gain) */ + map_params_dirac_to_stereo( hStereoDft, st_ivas->hQMetaData, tmp_synth, DFT[0], st_ivas->ivas_format == MC_FORMAT, + ( ( st_ivas->ivas_format != SBA_FORMAT && st_ivas->ivas_format != SBA_ISM_FORMAT ) || mcmasa ) ? hSCE->hCoreCoder[0]->L_frame : output_frame, + ( ( st_ivas->ivas_format != SBA_FORMAT && st_ivas->ivas_format != SBA_ISM_FORMAT ) || mcmasa ), q_dft ); + + IF ( (EQ_32( st_ivas->ivas_format , SBA_FORMAT) || EQ_32(st_ivas->ivas_format , SBA_ISM_FORMAT) ) && !mcmasa ) + { + set_val_Word32( hStereoDft->res_pred_gain_fx, MAX_32, 3 * STEREO_DFT_BAND_MAX ); + } + + /* DFT Stereo upmix */ + stereo_dft_dec_fx( hStereoDft, hCPE->hCoreCoder[0], DFT, NULL, NULL, 1 /*st_ivas->sba_dirac_stereo_flag*/, sba_mono_flag, ( st_ivas->hSpar != NULL && !mcmasa ) ? st_ivas->hSpar->hMdDec : NULL, ( st_ivas->hSpar != NULL && !mcmasa ) ? st_ivas->hSpar->hFbMixer->cross_fade_start_offset : 0, + st_ivas->hDecoderConfig->output_Fs, st_ivas->nchan_transport, ivas_get_spar_dec_md_num_subframes( st_ivas->sba_order, st_ivas->hDecoderConfig->ivas_total_brate, st_ivas->last_active_ivas_total_brate ) ); + + /* DFT synthesis */ + stereo_dft_dec_synthesize_fx( hCPE, DFT, 0, output[0], output_frame ); + IF ( EQ_16(sba_mono_flag, 0) ) + { + stereo_dft_dec_synthesize_fx( hCPE, DFT, 1, output[1], output_frame ); + } + + synchro_synthesis_fx( st_ivas->hDecoderConfig->ivas_total_brate, hCPE, output, output_frame, 1 /*st_ivas->sba_dirac_stereo_flag*/ ); + + /* output scaling */ + IF ( EQ_16(sba_mono_flag, 0) ) + { + v_shr( output[0], 1, output[0], output_frame ); + v_shr( output[1], 1, output[1], output_frame ); + } + + /* delay HB synth */ + IF ( EQ_16(st_ivas->nchan_transport, 1) ) + { + Copy32( hSCE->save_hb_synth_fx + output_frame - memOffset, tmp_buf, memOffset ); + Copy32( hSCE->save_hb_synth_fx, hSCE->save_hb_synth_fx + memOffset, output_frame - memOffset ); + Copy32( hSCE->prev_hb_synth_fx, hSCE->save_hb_synth_fx, memOffset ); + Copy32( tmp_buf, hSCE->prev_hb_synth_fx, memOffset ); + } + + IF ( (EQ_16( hCPE->hCoreCoder[0]->core, ACELP_CORE) || EQ_16(hCPE->hCoreCoder[0]->last_core, ACELP_CORE)) && EQ_16(fd_cng_flag, 0) && EQ_16(st_ivas->nchan_transport, 1) ) + { + /* upmix ACELP BWE */ + ivas_sba_dirac_stereo_compute_hb_gain( hStereoDft, hb_gain ); + + ivas_sba_dirac_stereo_upmix_hb( hb_synth_stereo, hSCE->save_hb_synth_fx, hb_gain, output_frame, ( ( st_ivas->ivas_format != SBA_FORMAT && st_ivas->ivas_format != SBA_ISM_FORMAT ) || mcmasa ), sba_mono_flag, hSCE->hCoreCoder[0]->bwidth, hStereoDft ); + + /* add HB to ACELP core */ + v_add_fx( output[0], hb_synth_stereo[0], output[0], output_frame ); + IF ( EQ_16(sba_mono_flag, 0) ) + { + v_add_fx( output[1], hb_synth_stereo[1], output[1], output_frame ); + + /* apply TD Stereo Filling as is done in ICBWE */ + ivas_sba_dirac_stereo_apply_td_stefi( hStereoDft, output, output_frame, ( ( st_ivas->ivas_format == SBA_FORMAT || st_ivas->ivas_format == SBA_ISM_FORMAT ) && !mcmasa ) ); + } + } + + /* reset the other channels to 0 (they are not used since here) */ + FOR ( Word16 ch = CPE_CHANNELS; ch < st_ivas->nchan_transport; ch++ ) + { + set_val_Word32( output[ch], 0, output_frame ); + } + + return; +} +#endif \ No newline at end of file diff --git a/lib_dec/ivas_sce_dec_fx.c b/lib_dec/ivas_sce_dec_fx.c index de8f53f097ae25905887a928070b93b411fa8f4a..d89aab4cfe66c2e3a34c9a6e3f4eb733e2d5faba 100644 --- a/lib_dec/ivas_sce_dec_fx.c +++ b/lib_dec/ivas_sce_dec_fx.c @@ -414,6 +414,7 @@ ivas_error create_sce_dec( #ifdef IVAS_FLOAT_FIXED_TO_BE_REMOVED IF( st_ivas->sba_dirac_stereo_flag ) { + IF( ( hSCE->save_synth = (float *) malloc( sizeof( float ) * output_frame ) ) == NULL ) { return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for stereo output\n" ) ); @@ -425,11 +426,28 @@ ivas_error create_sce_dec( return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate HB memory for stereo output\n" ) ); } set_zero( hSCE->save_hb_synth, output_frame ); +#ifdef IVAS_FLOAT_FIXED + IF( ( hSCE->save_synth_fx = (Word32 *) malloc( sizeof( *(hSCE->save_synth_fx) ) * output_frame ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for stereo output\n" ) ); + } + set_zero( hSCE->save_synth_fx, output_frame ); + + IF( ( hSCE->save_hb_synth_fx = (Word32 *) malloc( sizeof( *(hSCE->save_hb_synth_fx) ) * output_frame ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate HB memory for stereo output\n" ) ); + } + set_zero( hSCE->save_hb_synth_fx, output_frame ); +#endif } ELSE { hSCE->save_synth = NULL; hSCE->save_hb_synth = NULL; +#ifdef IVAS_FLOAT_FIXED + hSCE->save_synth_fx = NULL; + hSCE->save_hb_synth_fx = NULL; +#endif } #else IF( st_ivas->sba_dirac_stereo_flag ) diff --git a/lib_dec/ivas_stat_dec.h b/lib_dec/ivas_stat_dec.h index f8d4f0ac67cfb92db31747040bf8a849f9604440..663ec1c721ed21c7a3d016a7227716bef0d85cc3 100644 --- a/lib_dec/ivas_stat_dec.h +++ b/lib_dec/ivas_stat_dec.h @@ -93,6 +93,7 @@ typedef struct stereo_dft_dec_data_struct int16_t dft_trigo_step; #ifdef IVAS_FLOAT_FIXED + Word32 ONE_NFFT; /* Size of DFT */ const Word16 *dft_trigo_fx; const Word16 *dft_trigo_12k8_fx; const Word16 *dft_trigo_16k_fx; @@ -122,6 +123,7 @@ typedef struct stereo_dft_dec_data_struct const Word16 *win232ms_12k8_fx; /* DFT window */ const Word16 *win232ms_16k_fx; /* DFT window */ const Word16 *win232ms_8k_fx; /* DFT window */ + const Word16 *win_8k_fx; /* DFT window residual */ #endif const float *win_8k; /* DFT window residual */ @@ -145,11 +147,16 @@ typedef struct stereo_dft_dec_data_struct int16_t side_gain_index[STEREO_DFT_BAND_MAX]; float gipd[STEREO_DFT_DEC_DFT_NB]; +#ifdef IVAS_FLOAT_FIXED + Word32 gipd_fx[STEREO_DFT_DEC_DFT_NB]; +#endif int16_t no_ipd_flag; /* flag to indicate when no IPD gets used */ float itd[STEREO_DFT_DEC_DFT_NB]; +#if 0 #ifdef IVAS_FLOAT_FIXED Word16 itd_fx[STEREO_DFT_DEC_DFT_NB]; +#endif #endif float itd_xfade_step; @@ -165,6 +172,18 @@ typedef struct stereo_dft_dec_data_struct /*residual prediction*/ int16_t res_pred_mode[STEREO_DFT_DEC_DFT_NB]; /* residual prediction mode: 0(off), 1(stereo filling only), 2(enhanced stereo filling) */ float res_pred_gain[STEREO_DFT_DEC_DFT_NB * STEREO_DFT_BAND_MAX]; /* prediction gain for the residual HFs */ +#ifdef IVAS_FLOAT_FIXED + Word32 itd_fx[STEREO_DFT_DEC_DFT_NB]; + + Word32 itd_xfade_step_fx; + Word32 itd_xfade_target_fx; + Word32 itd_xfade_prev_fx; + + Word32 ipd_xfade_target_fx; + Word32 ipd_xfade_step_fx; + Word32 ipd_xfade_prev_fx; + Word32 res_pred_gain_fx[STEREO_DFT_DEC_DFT_NB * STEREO_DFT_BAND_MAX]; /* prediction gain for the residual HFs */ +#endif int16_t res_pred_band_min; /* Band min for prediction of residual */ float DFT_past_DMX[STEREO_DFT_PAST_MAX][STEREO_DFT32MS_N_32k]; /* Past DMX for residual prediction */ int16_t past_DMX_pos; @@ -186,13 +205,21 @@ typedef struct stereo_dft_dec_data_struct float bpf_error_signal_last; float bpf_error_ratio_mem; #ifdef IVAS_FLOAT_FIXED + Word32 DFT_past_DMX_fx[STEREO_DFT_PAST_MAX][STEREO_DFT32MS_N_32k]; /* Past DMX for residual prediction */ + Word32 past_res_pred_gain_fx[STEREO_DFT_PAST_MAX][STEREO_DFT_BAND_MAX]; + Word32 res_gains_ind_fx[2][2 * STEREO_DFT_BAND_MAX]; Word32 res_hb_nrg_mem_fx; Word32 bpf_error_signal_last_fx; Word16 bpf_error_ratio_mem_fx; + Word16 q_dft; + Word16 q_past_dft; + Word16 q_ip_mem; + Word16 q_smoothed_nrg; #endif // IVAS_FLOAT_FIXED float res_cod_mem[STEREO_DFT_OVL_8k]; float buff_LBTCX_mem[NS2SA( 16000, STEREO_DFT32MS_OVL_NS )]; #ifdef IVAS_FLOAT_FIXED + Word32 res_cod_mem_fx[STEREO_DFT_OVL_8k]; Word32 buff_LBTCX_mem_fx[NS2SA( 16000, STEREO_DFT32MS_OVL_NS )]; #endif @@ -215,6 +242,13 @@ typedef struct stereo_dft_dec_data_struct float ap_delay_mem[NS2SA( 16000, DELAY_BWE_TOTAL_NS )]; float ap_fade_mem[STEREO_DFT_ALLPASS_FADELEN_16k]; #ifdef IVAS_FLOAT_FIXED + Word32 stab_fac_smooth_res_fx; /* low-pass filtered stability factor */ + Word32 lt_pred_gain_fx; + Word32 lt_pred_gain_variation_fx; + Word32 lt_var_mean_ratio_fx; + Word16 stefi_short_gain_fx; + Word16 stefi_long_gain_fx; + Word16 q_lt_pred_gain; Word32 ap_delay_mem_fx[NS2SA( 16000, DELAY_BWE_TOTAL_NS )]; Word32 ap_fade_mem_fx[STEREO_DFT_ALLPASS_FADELEN_16k]; #endif @@ -229,6 +263,8 @@ typedef struct stereo_dft_dec_data_struct float hb_nrg_subr[STEREO_DFT_NBDIV]; float td_gain[STEREO_DFT_CORE_HIST_MAX]; #ifdef IVAS_FLOAT_FIXED + Word32 smooth_dmx_nrg_fx[STEREO_DFT_BAND_MAX]; + Word32 smooth_res_nrg_fx[STEREO_DFT_BAND_MAX]; Word32 td_gain_fx[STEREO_DFT_CORE_HIST_MAX]; #endif @@ -239,10 +275,14 @@ typedef struct stereo_dft_dec_data_struct Word16 Q_nrg_subr; Word16 prev_Q_stefi_sig; + Word32 q_td_gain[STEREO_DFT_CORE_HIST_MAX]; #endif /* stereo DTX */ float g_state[STEREO_DFT_BAND_MAX]; +#ifdef IVAS_FLOAT_FIXED + Word16 g_state_fx[STEREO_DFT_BAND_MAX]; +#endif int16_t frame_sid_nodata; int16_t frame_nodata; int16_t frame_sid; @@ -259,12 +299,30 @@ typedef struct stereo_dft_dec_data_struct float smooth_buf[SBA_DIRAC_STEREO_NUM_BANDS][SBA_DIRAC_NRG_SMOOTH_LONG + 1]; float smooth_fac[NB_DIV][SBA_DIRAC_STEREO_NUM_BANDS]; +#ifdef IVAS_FLOAT_FIXED + /* PLC on residual signal */ + Word32 sg_mean_fx; + Word32 res_mem_fx[STEREO_DFT_RES_BW_MAX]; + Word32 past_dmx_nrg_fx; + Word32 smooth_buf_fx[SBA_DIRAC_STEREO_NUM_BANDS][SBA_DIRAC_NRG_SMOOTH_LONG + 1]; + Word16 smooth_fac_fx[NB_DIV][SBA_DIRAC_STEREO_NUM_BANDS]; + Word16 q_hb_nrg; + Word16 q_hb_nrg_subr; +#endif int16_t first_frame; float mixer_mat_smooth[2][4][2 * IVAS_MAX_NUM_BANDS]; +#ifdef IVAS_FLOAT_FIXED + Word32 mixer_mat_smooth_fx[2][4][2 * IVAS_MAX_NUM_BANDS]; +#endif float g_L_prev; float g_R_prev; const float *max_smooth_gains, *min_smooth_gains; +#ifdef IVAS_FLOAT_FIXED + Word32 g_L_prev_fx; + Word32 g_R_prev_fx; + const Word16 *max_smooth_gains_fx, *min_smooth_gains_fx; +#endif } STEREO_DFT_DEC_DATA, *STEREO_DFT_DEC_DATA_HANDLE; @@ -296,6 +354,9 @@ typedef struct stereo_dec_cng { float coh[STEREO_DFT_BAND_MAX + 1]; /* coherence */ float cm[STEREO_DFT_BAND_MAX]; /* cm */ +#ifdef IVAS_FLOAT_FIXED + Word16 cm_fx[STEREO_DFT_BAND_MAX]; /* cm */ +#endif int16_t first_SID; /* first SID indicator */ int16_t first_SID_after_TD; /* first SID after TD-stereo indicator */ int16_t prev_sid_nodata; /* previous frame SID/FRAME_NO_DATA indicator */ diff --git a/lib_dec/ivas_stereo_dft_dec.c b/lib_dec/ivas_stereo_dft_dec.c index 7be18cb84b96912f96fb6e4cc03a850ab5ea41c7..2e0a6376d256c8544cd1b8968a38ecc89430c526 100644 --- a/lib_dec/ivas_stereo_dft_dec.c +++ b/lib_dec/ivas_stereo_dft_dec.c @@ -56,6 +56,9 @@ #define STEFI_DELAY_IND( d, buf_ind ) ( ( buf_ind ) + STEREO_DFT_PAST_MAX - ( d ) + 1 ) % STEREO_DFT_PAST_MAX #define STEREO_DFT_RES_RATIO_LIMIT 0.18f +#ifdef IVAS_FLOAT_FIXED +#define STEREO_DFT_RES_RATIO_LIMIT_FX (Word32)(0x170A3D71) +#endif #define STEREO_DFT_LT_PREDGAIN_UPD 0.1f #define STEREO_DFT_VR_PREDGAIN_UPD 0.1f #define STEREO_DFT_STEFFI_PG_THRESHOLD 0.6f @@ -329,6 +332,23 @@ static void stereo_dft_dec_open( hStereoDft->dft_trigo_12k8 = dft_trigo_12k8; hStereoDft->dft_trigo_16k = dft_trigo_32k; #ifdef IVAS_FLOAT_FIXED + switch (output_Fs) + { + case 48000: + hStereoDft->ONE_NFFT = (Word32) ( 0x00222222 ); + BREAK; + case 32000: + hStereoDft->ONE_NFFT = (Word32) ( 0x00333333 ); + BREAK; + case 16000: + hStereoDft->ONE_NFFT = (Word32) ( 0x00666666 ); + BREAK; + case 8000: + hStereoDft->ONE_NFFT = (Word32) ( 0x00CCCCCC ); + BREAK; + default: + assert(0); + } hStereoDft->dft_trigo_8k_fx = dft_trigo_32k_fx; hStereoDft->dft_trigo_12k8_fx = dft_trigo_12k8_fx; hStereoDft->dft_trigo_16k_fx = dft_trigo_32k_fx; @@ -421,6 +441,19 @@ static void stereo_dft_dec_open( hStereoDft->max_smooth_gains = max_smooth_gains1; } +#ifdef IVAS_FLOAT_FIXED + if ( nchan_transport > 2 ) + { + hStereoDft->min_smooth_gains_fx = min_smooth_gains2_fx; + hStereoDft->max_smooth_gains_fx = max_smooth_gains2_fx; + } + else + { + hStereoDft->min_smooth_gains_fx = min_smooth_gains1_fx; + hStereoDft->max_smooth_gains_fx = max_smooth_gains1_fx; + } +#endif + /* reset DFT stereo memories */ stereo_dft_dec_reset( hStereoDft ); @@ -456,6 +489,14 @@ void stereo_dft_dec_reset( set_zero( hStereoDft->past_res_pred_gain[i], STEREO_DFT_BAND_MAX ); } +#ifdef IVAS_FLOAT_FIXED + FOR ( i = 0; i < STEREO_DFT_PAST_MAX; i++ ) + { + set_val_Word32( hStereoDft->DFT_past_DMX_fx[i], 0, STEREO_DFT32MS_N_32k ); + set_val_Word32( hStereoDft->past_res_pred_gain_fx[i], 0, STEREO_DFT_BAND_MAX ); + } +#endif + hStereoDft->past_DMX_pos = 0; set_s( hStereoDft->res_pred_index_previous, 0, STEREO_DFT_BAND_MAX ); @@ -467,10 +508,22 @@ void stereo_dft_dec_reset( set_zero( hStereoDft->res_gains_ind[1], STEREO_DFT_BAND_MAX ); +#ifdef IVAS_FLOAT_FIXED + FOR ( i = 0; i < STEREO_DFT_BAND_MAX; i++ ) + { + hStereoDft->res_gains_ind_fx[0][i] = L_shl(15, Q26); + } + + set_val_Word32( hStereoDft->res_gains_ind_fx[1], 0, STEREO_DFT_BAND_MAX ); +#endif + /*residual coding*/ set_s( hStereoDft->res_cod_mode, hStereoDft->hConfig->res_cod_mode, STEREO_DFT_DEC_DFT_NB ); hStereoDft->res_cod_band_max = dft_band_res_cod[hStereoDft->hConfig->band_res][hStereoDft->hConfig->res_cod_mode]; set_zero( hStereoDft->res_cod_mem, STEREO_DFT_OVL_8k ); +#ifdef IVAS_FLOAT_FIXED + set_l( hStereoDft->res_cod_mem_fx, 0, STEREO_DFT_OVL_8k ); +#endif hStereoDft->res_pred_band_min = max( STEREO_DFT_RES_PRED_BAND_MIN, hStereoDft->res_cod_band_max ); @@ -496,6 +549,14 @@ void stereo_dft_dec_reset( set_zero( hStereoDft->itd, STEREO_DFT_DEC_DFT_NB ); set_zero( hStereoDft->res_pred_gain, STEREO_DFT_DEC_DFT_NB * STEREO_DFT_BAND_MAX ); +#ifdef IVAS_FLOAT_FIXED + /*reset parameters*/ + set_val_Word32( hStereoDft->side_gain_fx, 0, STEREO_DFT_DEC_DFT_NB * STEREO_DFT_BAND_MAX ); + set_val_Word32( hStereoDft->gipd_fx, 0, STEREO_DFT_DEC_DFT_NB ); + set_val_Word32( hStereoDft->itd_fx, 0, STEREO_DFT_DEC_DFT_NB ); + set_val_Word32( hStereoDft->res_pred_gain_fx, 0, STEREO_DFT_DEC_DFT_NB * STEREO_DFT_BAND_MAX ); +#endif + hStereoDft->wasTransient = 0; hStereoDft->attackPresent = 0; @@ -504,10 +565,19 @@ void stereo_dft_dec_reset( hStereoDft->lt_var_mean_ratio = STEREO_DFT_RES_RATIO_LIMIT; hStereoDft->stefi_short_gain = 1.0f; hStereoDft->stefi_long_gain = 0.0f; +#ifdef IVAS_FLOAT_FIXED + hStereoDft->lt_pred_gain_fx = 0; + hStereoDft->lt_pred_gain_variation_fx = 0; + hStereoDft->lt_var_mean_ratio_fx = STEREO_DFT_RES_RATIO_LIMIT_FX; + hStereoDft->stefi_short_gain_fx = MAX_16; + hStereoDft->stefi_long_gain_fx = 0; + hStereoDft->q_lt_pred_gain = 0; +#endif set_zero( hStereoDft->g_state, STEREO_DFT_BAND_MAX ); #ifdef IVAS_FLOAT_FIXED + set_val_Word32( hStereoDft->g_state_fx, 0, STEREO_DFT_BAND_MAX ); init_basic_allpass( &hStereoDft->ap1, dft_ap_gains[0], dft_ap_gains_fx[0], dft_ap_delays[0] ); init_basic_allpass( &hStereoDft->ap2, dft_ap_gains[1], dft_ap_gains_fx[1], dft_ap_delays[1] ); init_basic_allpass( &hStereoDft->ap3, dft_ap_gains[2], dft_ap_gains_fx[2], dft_ap_delays[2] ); @@ -573,6 +643,55 @@ void stereo_dft_dec_reset( hStereoDft->g_L_prev = 0.f; hStereoDft->g_R_prev = 0.f; +#ifdef IVAS_FLOAT_FIXED + set_val_Word32( hStereoDft->ap_delay_mem_fx, 0, NS2SA( 16000, DELAY_BWE_TOTAL_NS ) ); + set_val_Word32( hStereoDft->ap_fade_mem_fx, 0, STEREO_DFT_ALLPASS_FADELEN_16k ); + set_val_Word32( hStereoDft->smooth_dmx_nrg_fx, 0, STEREO_DFT_BAND_MAX ); + set_val_Word32( hStereoDft->smooth_res_nrg_fx, 0, STEREO_DFT_BAND_MAX ); + + set_s( hStereoDft->core_hist, ACELP_CORE, STEREO_DFT_CORE_HIST_MAX ); + + set_val_Word32( hStereoDft->hb_stefi_sig_fx, 0, L_FRAME48k + NS2SA( 48000, STEREO_DFT_TD_STEFI_DELAY_NS ) ); + set_val_Word32( hStereoDft->hb_nrg_fx, 0, STEREO_DFT_CORE_HIST_MAX ); + set_val_Word32( hStereoDft->td_gain_fx, 0, STEREO_DFT_CORE_HIST_MAX ); + set_val_Word32( hStereoDft->q_td_gain, 0, STEREO_DFT_CORE_HIST_MAX ); + + /* PLC parameters */ + set_val_Word32( hStereoDft->res_mem_fx, 0, STEREO_DFT_RES_BW_MAX ); + hStereoDft->past_dmx_nrg_fx = 0; + hStereoDft->sg_mean_fx = 0; + hStereoDft->q_dft = 0; + hStereoDft->q_past_dft = 0; + hStereoDft->q_smoothed_nrg = 0; + + FOR ( i = 0; i < SBA_DIRAC_STEREO_NUM_BANDS; i++ ) + { + set_val_Word32( hStereoDft->smooth_buf_fx[i], 0, SBA_DIRAC_NRG_SMOOTH_LONG + 1 ); + } + set_val_Word16( hStereoDft->smooth_fac_fx[0], 0, SBA_DIRAC_STEREO_NUM_BANDS ); + set_val_Word16( hStereoDft->smooth_fac_fx[1], 0, SBA_DIRAC_STEREO_NUM_BANDS ); + + hStereoDft->itd_xfade_target_fx = 0; + hStereoDft->itd_xfade_step_fx = 0; + hStereoDft->itd_xfade_prev_fx = 0; + hStereoDft->ipd_xfade_target_fx = 0; + hStereoDft->ipd_xfade_step_fx = 0; + hStereoDft->ipd_xfade_prev_fx = 0; + + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + FOR ( i = 0; i < 2; i++ ) + { + FOR ( j = 0; j < 4; j++ ) + { + hStereoDft->mixer_mat_smooth_fx[i][j][b] = 0; + } + } + } + hStereoDft->g_L_prev_fx = 0; + hStereoDft->g_R_prev_fx = 0; +#endif + return; } diff --git a/lib_dec/ivas_stereo_dft_dec_fx.c b/lib_dec/ivas_stereo_dft_dec_fx.c new file mode 100644 index 0000000000000000000000000000000000000000..291a987625d066554239de83ada705dc74e58ac6 --- /dev/null +++ b/lib_dec/ivas_stereo_dft_dec_fx.c @@ -0,0 +1,2833 @@ +/****************************************************************************************************** + + (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 +#include "options.h" +#include +#include "cnst.h" +#include "rom_com.h" +#include "rom_dec.h" +#include "prot.h" +#include "prot_fx2.h" +#include "ivas_prot.h" +#include "ivas_prot_fx.h" +#include "ivas_cnst.h" +#include "ivas_rom_com.h" +#include "ivas_rom_com_fx.h" +#include "ivas_rom_dec.h" +#include "wmc_auto.h" +#ifdef IVAS_FLOAT_FIXED +#include "ivas_prot_fx.h" +#include "basop_util.h" +#endif // IVAS_FLOAT_FIXED + +/*-------------------------------------------------------------------* + * Local constants + *-------------------------------------------------------------------*/ + +#define STEFI_DELAY_IND( d, buf_ind ) ( ( buf_ind ) + STEREO_DFT_PAST_MAX - ( d ) + 1 ) % STEREO_DFT_PAST_MAX + +#define STEREO_DFT_RES_RATIO_LIMIT_FX (Word32)(0x170A3D71) +#define STEREO_DFT_RES_RATIO_LIMIT_FX_3_BY_2 (Word32)(0x228F5C28) +#define ONE_STEREO_DFT_RES_RATIO_LIMIT_Q12 (Word16)(0x58E4) +#define STEREO_DFT_LT_PREDGAIN_UPD_FX (Word16)(0x0CCD) +#define STEREO_DFT_VR_PREDGAIN_UPD_FX (Word16)(0x0CCD) +#define STEREO_DFT_STEFFI_PG_THRESHOLD_FX (Word32)(0x4CCCCCCD) +#define STEREO_DFT_STEFFI_RATIO_UP_HIGH_FX (Word32)(0x03D70A3D) +#define STEREO_DFT_STEFFI_RATIO_DOWN_HIGH_FX (Word32)(0x06666666) +#define STEREO_DFT_STEFFI_RATIO_UP_LOW_FX (Word32)(0x0CCCCCCC) +#define STEREO_DFT_STEFFI_RATIO_DOWN_LOW_FX (Word32)(0x0020C49C) +#define STEREO_DFT_STEFFI_DELAY_SHORT 2 +#define STEREO_DFT_STEFFI_DELAY_LONG 4 +#define STEREO_DFT_STEFFI_DELAY_OFFSET 2 +#define STEREO_DFT_STEFFI_GAIN_REST_AMT_FX (Word16)(0x4CCD) +#define STEREO_DFT_STEFFI_GAIN_AMP_FX (Word16)(0x7FFF) + + +#define STEREO_DFT_BPF_SIZE 40 /* BPF: Number of weights for BPF in DFT: 40*40Hz=1.6kHz*/ + +/*------------------------------------------------------------------------- + * Local function prototypes + *-------------------------------------------------------------------------*/ + +static void stereo_dft_dec_open( STEREO_DFT_DEC_DATA_HANDLE hStereoDft, const int32_t output_Fs, const int16_t nchan_transport ); + +static void stereo_dft_compute_td_stefi_params_fx( STEREO_DFT_DEC_DATA_HANDLE hStereoDft, const Word16 samp_ratio ); + +static void stereo_dft_adapt_sf_delay_fx( STEREO_DFT_DEC_DATA_HANDLE hStereoDft, Word32 *pPredGain ); + +void stereo_dft_generate_res_pred_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word16 samp_ratio, /* i : sampling ratio */ + Word32 *pDFT_DMX, /* i : downmix signal */ + Word32 *DFT_PRED_RES, /* o : residual prediction signal */ + Word32 *pPredGain, /* i : residual prediction gains */ + const Word16 k, /* i : subframe index */ + Word32 *ap_filt_DMX, /* i : enhanced stereo filling signal */ + Word16 *stop, /* o : last FD stereo filling bin */ + const Word16 bfi /* i : BFI flag */ +); + +#ifdef IVAS_FLOAT_FIXED +/*------------------------------------------------------------------------- + * stereo_dft_dec_reset_fx() + * + * Reset DFT stereo memories + *------------------------------------------------------------------------*/ + +void stereo_dft_dec_reset_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft /* i/o: decoder DFT stereo handle */ +) +{ + Word16 i; + Word16 j, b; + + /*Configuration*/ + set_s( hStereoDft->prm_res, hStereoDft->hConfig->prm_res, STEREO_DFT_DEC_DFT_NB ); + + /* SIDE_GAIN */ + set_s( hStereoDft->side_gain_index, 15, STEREO_DFT_BAND_MAX ); + set_s( hStereoDft->side_gain_index_previous, 15, STEREO_DFT_BAND_MAX ); + + /*residual prediction*/ + set_s( hStereoDft->res_pred_mode, hStereoDft->hConfig->res_pred_mode, STEREO_DFT_DEC_DFT_NB ); + FOR ( i = 0; i < STEREO_DFT_PAST_MAX; i++ ) + { + set_val_Word32( hStereoDft->DFT_past_DMX_fx[i], 0, STEREO_DFT32MS_N_32k ); + set_val_Word32( hStereoDft->past_res_pred_gain_fx[i], 0, STEREO_DFT_BAND_MAX ); + } + + hStereoDft->past_DMX_pos = 0; + move16(); + + set_s( hStereoDft->res_pred_index_previous, 0, STEREO_DFT_BAND_MAX ); + + FOR ( i = 0; i < STEREO_DFT_BAND_MAX; i++ ) + { + hStereoDft->res_gains_ind_fx[0][i] = (Word32)0x3C000000; + move32(); + } + + set_val_Word32( hStereoDft->res_gains_ind_fx[1], 0, STEREO_DFT_BAND_MAX ); + + /*residual coding*/ + set_s( hStereoDft->res_cod_mode, hStereoDft->hConfig->res_cod_mode, STEREO_DFT_DEC_DFT_NB ); + hStereoDft->res_cod_band_max = dft_band_res_cod[hStereoDft->hConfig->band_res][hStereoDft->hConfig->res_cod_mode]; + set_val_Word32( hStereoDft->res_cod_mem_fx, 0, STEREO_DFT_OVL_8k ); + + hStereoDft->res_pred_band_min = s_max( STEREO_DFT_RES_PRED_BAND_MIN, hStereoDft->res_cod_band_max ); + move32(); + + hStereoDft->stab_fac_smooth_res_fx = 0; + move32(); + bass_psfilter_init( hStereoDft->hBpf ); + + tcxltp_dec_init( hStereoDft->hTcxLtpDec, 0, MODE1, IVAS_CPE_DFT, PIT_MAX, 12800 ); + + hStereoDft->reverb_flag = 0; + move16(); + + hStereoDft->res_hb_nrg_mem_fx = 0; + move32(); + hStereoDft->bpf_error_signal_last_fx = 0; + move32(); + hStereoDft->bpf_error_ratio_mem_fx = ONE_IN_Q12; + move16(); + + /*reset parameters*/ + set_val_Word32( hStereoDft->side_gain_fx, 0, STEREO_DFT_DEC_DFT_NB * STEREO_DFT_BAND_MAX ); + set_val_Word32( hStereoDft->gipd_fx, 0, STEREO_DFT_DEC_DFT_NB ); + set_val_Word32( hStereoDft->itd_fx, 0, STEREO_DFT_DEC_DFT_NB ); + set_val_Word32( hStereoDft->res_pred_gain_fx, 0, STEREO_DFT_DEC_DFT_NB * STEREO_DFT_BAND_MAX ); + + hStereoDft->wasTransient = 0; + move16(); + hStereoDft->attackPresent = 0; + move16(); + + hStereoDft->lt_pred_gain_fx = 0; + hStereoDft->lt_pred_gain_variation_fx = 0; + hStereoDft->lt_var_mean_ratio_fx = STEREO_DFT_RES_RATIO_LIMIT_FX; + hStereoDft->stefi_short_gain_fx = MAX_16; + hStereoDft->stefi_long_gain_fx = 0; + hStereoDft->q_lt_pred_gain = 0; + + set_val_Word16( &hStereoDft->g_state_fx[0], 0, STEREO_DFT_BAND_MAX ); + + init_basic_allpass( &hStereoDft->ap1, dft_ap_gains[0], dft_ap_gains_fx[0], dft_ap_delays[0] ); + init_basic_allpass( &hStereoDft->ap2, dft_ap_gains[1], dft_ap_gains_fx[1], dft_ap_delays[1] ); + init_basic_allpass( &hStereoDft->ap3, dft_ap_gains[2], dft_ap_gains_fx[2], dft_ap_delays[2] ); + + set_val_Word32( hStereoDft->ap_delay_mem_fx, 0, NS2SA( 16000, DELAY_BWE_TOTAL_NS ) ); + set_val_Word32( hStereoDft->ap_fade_mem_fx, 0, STEREO_DFT_ALLPASS_FADELEN_16k ); + hStereoDft->ap_wasTransient = 0; + move16(); + set_val_Word32( hStereoDft->smooth_dmx_nrg_fx, 0, STEREO_DFT_BAND_MAX ); + set_val_Word32( hStereoDft->smooth_res_nrg_fx, 0, STEREO_DFT_BAND_MAX ); + + set_s( hStereoDft->core_hist, ACELP_CORE, STEREO_DFT_CORE_HIST_MAX ); + + set_val_Word32( hStereoDft->hb_stefi_sig_fx, 0, L_FRAME48k + NS2SA( 48000, STEREO_DFT_TD_STEFI_DELAY_NS ) ); + set_val_Word32( hStereoDft->hb_nrg_fx, 0, STEREO_DFT_CORE_HIST_MAX ); + set_val_Word32( hStereoDft->td_gain_fx, 0, STEREO_DFT_CORE_HIST_MAX ); + set_val_Word32( hStereoDft->q_td_gain, 0, STEREO_DFT_CORE_HIST_MAX ); + + /* PLC parameters */ + set_val_Word32( hStereoDft->res_mem_fx, 0, STEREO_DFT_RES_BW_MAX ); + hStereoDft->time_offs = 0; + move16(); + hStereoDft->past_dmx_nrg_fx = 0; + move32(); + hStereoDft->sg_mean_fx = 0; + move32(); + hStereoDft->sg_mem_corrupt = 0; + move16(); + hStereoDft->recovery_flg = 0; + move16(); + + FOR ( i = 0; i < SBA_DIRAC_STEREO_NUM_BANDS; i++ ) + { + set_val_Word32( hStereoDft->smooth_buf_fx[i], 0, SBA_DIRAC_NRG_SMOOTH_LONG + 1 ); + } + set_val_Word16( &hStereoDft->smooth_fac_fx[0][0], 0, SBA_DIRAC_STEREO_NUM_BANDS ); + set_zero( hStereoDft->smooth_fac[1], SBA_DIRAC_STEREO_NUM_BANDS ); + + hStereoDft->itd_xfade_target_fx = 0; move32(); + hStereoDft->itd_xfade_step_fx = 0; move32(); + hStereoDft->itd_xfade_counter = 0; move16(); + hStereoDft->itd_xfade_prev_fx = 0; move32(); + hStereoDft->last_active_element_brate = 0; move32(); + hStereoDft->ipd_xfade_target_fx = 0; move32(); + hStereoDft->ipd_xfade_step_fx = 0; move32(); + hStereoDft->ipd_xfade_counter = 0; move16(); + hStereoDft->ipd_xfade_prev_fx = 0; move32(); + + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + FOR ( i = 0; i < 2; i++ ) + { + FOR ( j = 0; j < 4; j++ ) + { + hStereoDft->mixer_mat_smooth_fx[i][j][b] = 0; move32(); + } + } + } + hStereoDft->first_frame = 1; move16(); + hStereoDft->g_L_prev_fx = 0; move32(); + hStereoDft->g_R_prev_fx = 0; move32(); + + return; +} + +/*------------------------------------------------------------------------- + * stereo_dft_dec_open() + * + * Open DFT decoder stereo handle + *-------------------------------------------------------------------------*/ + +static void stereo_dft_dec_open_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word32 output_Fs, /* i : output sampling rate */ + const Word16 nchan_transport /* i : number of transport channels */ +) +{ + /*Sizes*/ + hStereoDft->N = (int16_t) ( STEREO_DFT_HOP_MAX * output_Fs / 48000 ); + + /*Init. DFT sizes*/ + hStereoDft->NFFT = (int16_t) ( STEREO_DFT32MS_N_MAX * output_Fs / 48000 ); + + hStereoDft->dft_trigo_8k_fx = dft_trigo_32k_fx; + hStereoDft->dft_trigo_12k8_fx = dft_trigo_12k8_fx; + hStereoDft->dft_trigo_16k_fx = dft_trigo_32k_fx; + + hStereoDft->dft32ms_ovl = (int16_t) ( ( STEREO_DFT32MS_OVL_MAX * output_Fs ) / 48000 ); + hStereoDft->win232ms_8k_fx = dft_win232ms_8k_fx; + hStereoDft->win232ms_12k8_fx = dft_win232ms_12k8_fx; + hStereoDft->win232ms_16k_fx = dft_win232ms_16k_fx; + + hStereoDft->dft32ms_ovl2 = (int16_t) ( ( STEREO_DFT32MS_OVL2_MAX * output_Fs ) / 48000 ); + hStereoDft->win32ms_8k_fx = dft_win232ms_8k_fx + 1; + hStereoDft->win32ms_12k8_fx = dft_win232ms_12k8_fx + 1; + hStereoDft->win32ms_16k_fx = dft_win232ms_16k_fx + 1; + + IF ( EQ_32(output_Fs , 16000) ) + { + hStereoDft->dft_trigo_fx = dft_trigo_32k_fx; + hStereoDft->dft_trigo_step = STEREO_DFT_TRIGO_SRATE_16k_STEP; + hStereoDft->win232ms_fx = dft_win232ms_16k_fx; + hStereoDft->win32ms_fx = dft_win232ms_16k_fx + 1; + } + ELSE IF ( EQ_32(output_Fs , 32000) ) + { + hStereoDft->dft_trigo_fx = dft_trigo_32k_fx; + hStereoDft->dft_trigo_step = STEREO_DFT_TRIGO_SRATE_32k_STEP; + hStereoDft->win232ms_fx = dft_win232ms_32k_fx; + hStereoDft->win32ms_fx = dft_win232ms_32k_fx + 1; + } + ELSE + { + assert( output_Fs == 48000 ); + hStereoDft->dft_trigo_fx = dft_trigo_48k_fx; + hStereoDft->dft_trigo_step = STEREO_DFT_TRIGO_SRATE_48k_STEP; + hStereoDft->win232ms_fx = dft_win232ms_48k_fx; + hStereoDft->win32ms_fx = dft_win232ms_48k_fx + 1; + } + + hStereoDft->win_8k_fx = dft_win_8k_fx; + + /*Bands: find the number of bands, Nyquist freq. is not taken into account*/ + set_s( hStereoDft->band_res, hStereoDft->hConfig->band_res, STEREO_DFT_DEC_DFT_NB ); + + hStereoDft->nbands = stereo_dft_band_config( hStereoDft->band_limits, hStereoDft->band_res[0], hStereoDft->NFFT, DEC ); + hStereoDft->hb_stefi_delay = NS2SA( output_Fs, STEREO_DFT_TD_STEFI_DELAY_NS ); + + IF ( GT_16(nchan_transport , 2) ) + { + hStereoDft->min_smooth_gains_fx = min_smooth_gains2_fx; + hStereoDft->max_smooth_gains_fx = max_smooth_gains2_fx; + } + ELSE + { + hStereoDft->min_smooth_gains_fx = min_smooth_gains1_fx; + hStereoDft->max_smooth_gains_fx = max_smooth_gains1_fx; + } + + /* reset DFT stereo memories */ + stereo_dft_dec_reset_fx( hStereoDft ); + + return; +} + + +/*------------------------------------------------------------------------- + * stereo_dft_dec_create_fx() + * + * Create DFT stereo handle + *------------------------------------------------------------------------*/ + +ivas_error stereo_dft_dec_create_fx( + STEREO_DFT_DEC_DATA_HANDLE *hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word32 element_brate, /* i : element bitrate */ + const Word32 output_Fs, /* i : output sampling rate */ + const Word16 sba_dirac_stereo_flag, /* i : signal stereo output for SBA DirAC */ + const Word16 nchan_transport /* i : number of transport channels */ +) +{ + STEREO_DFT_DEC_DATA_HANDLE hStereoDft_loc; + Word16 tmpS; + + IF ( *hStereoDft != NULL ) + { + return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Error: DFT Stereo memory already allocated\n" ); + } + + IF ( ( hStereoDft_loc = (STEREO_DFT_DEC_DATA_HANDLE) malloc( sizeof( STEREO_DFT_DEC_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DFT Stereo\n" ) ); + } + + IF ( ( hStereoDft_loc->hConfig = (STEREO_DFT_CONFIG_DATA_HANDLE) malloc( sizeof( STEREO_DFT_CONFIG_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DFT Stereo Config\n" ) ); + } + + IF ( ( hStereoDft_loc->hBpf = (BPF_DEC_HANDLE) malloc( sizeof( BPF_DEC_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for BPF handle\n" ) ); + } + + IF ( ( hStereoDft_loc->hTcxLtpDec = (TCX_LTP_DEC_HANDLE) malloc( sizeof( TCX_LTP_DEC_DATA ) ) ) == NULL ) + { + return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for TCX-LTP handle\n" ) ); + } + + hStereoDft_loc->hConfig->force_mono_transmission = 0; + move16(); + + IF ( sba_dirac_stereo_flag ) + { + ivas_sba_dirac_stereo_config( hStereoDft_loc->hConfig ); + } + ELSE + { + stereo_dft_config_fx( hStereoDft_loc->hConfig, element_brate, &tmpS, &tmpS ); + } + + stereo_dft_dec_open_fx( hStereoDft_loc, output_Fs, nchan_transport ); + + *hStereoDft = hStereoDft_loc; + + return IVAS_ERR_OK; +} + + +/*------------------------------------------------------------------------- + * stereo_dft_dequantize_res_gains_fx() + * + * joint dequantizer for side channel prediction gain and residual energy + *-------------------------------------------------------------------------*/ + +static void stereo_dft_dequantize_res_gains_fx( + Word16 *ind1, + Word16 *ind2, + Word32 *gout, + Word32 *rout, + const Word16 N ) +{ + Word16 i, index; + + FOR ( i = 0; i < N; i++ ) + { + /* Ensure the indices are within range -- may go out of range due to frame loss */ + ind1[i] = check_bounds_s( ind1[i], 0, 30 ); + move16(); + ind2[i] = check_bounds_s( ind2[i], 0, 7 ); + move16(); + index = add(shl( LE_16(ind1[i], 15) ? sub(15, ind1[i]) : sub(ind1[i], 15), 3 ), ind2[i]); + move16(); + gout[i] = LE_16(ind1[i], 15) ? L_negate(dft_res_gains_q_fx[index][0]) : dft_res_gains_q_fx[index][0]; + move16(); + rout[i] = dft_res_gains_q_fx[index][1]; + move16(); + } + + return; +} + +/*--------------------------------------------------------------------------- + * stereo_dft_dequantize_res_gains_f_fx() + * + * returns interepolated values for non-integer indices + *---------------------------------------------------------------------------*/ + +static void stereo_dft_dequantize_res_gains_f_fx( + Word32 *ind1, + Word32 *ind2, + Word32 *gout, + Word32 *rout, + const Word16 N ) +{ + Word16 i, i1, j1, sign, ji, ij; + Word32 fi, fj; + + FOR ( i = 0; i < N; i++ ) + { + /* Ensure the indices are within range -- may go out of range due to frame loss */ + ind1[i] = check_bounds_l( ind1[i], 0, L_shl(31, Q26)); + move32(); + ind2[i] = check_bounds_l( ind2[i], 0, L_shl(7, Q26)); + move32(); + + /* compensate for the offset and extract/remove sign of first index */ + sign = LT_32(ind1[i], L_shl(15, Q26)) ? -1 : 1; + move16(); + i1 = (Word16)L_shr(( LT_32(ind1[i], L_shl(15, Q26)) ? L_sub(L_shl(15, Q26), ind1[i]) : L_sub(ind1[i], L_shl(15, Q26)) ), Q26); + fi = (LT_32( ind1[i], L_shl(15, Q26)) ? L_sub(L_shl(15, Q26), ind1[i]) : L_sub(ind1[i], L_shl(15, Q26))) - L_shl(i1, Q26); + move16(); + j1 = (Word16) L_shr( ind2[i], Q26 ); + fj = L_sub(ind2[i], L_shl(j1, Q26)); + + /* choose base indices for interpolation */ + ji = (Word16)L_min( fj < ONE_IN_Q25 ? j1 : j1 + 1, 7 ); + ij = (Word16)L_min( fi < ONE_IN_Q25 ? i1 : i1 + 1, 15 ); + + /* interpolate values from table */ + IF ( LT_32(i1, L_shl(15, Q26)) ) + { + gout[i] = Madd_32_32( Mpy_32_32(L_sub(MAX_32, L_shl(fi , Q5)), dft_res_gains_q_fx[( i1 << 3 ) + ji][0]), dft_res_gains_q_fx[( ( i1 + 1 ) << 3 ) + ji][0], L_shl(fi, Q5) ); + move32(); + IF (EQ_16(sign , -1)) + { + gout[i] = L_negate(gout[i]); + move32(); + } + } + ELSE + { + gout[i] = sign * dft_res_gains_q_fx[120 + ji][0]; + move32(); + IF (EQ_16(sign , -1)) + { + gout[i] = L_negate(gout[i]); + move32(); + } + } + + IF ( LT_32(j1, L_shl(7, Q26)) ) + { + rout[i] = Madd_32_32(Mpy_32_32(L_sub(MAX_32, L_shl(fj , Q5)), dft_res_gains_q_fx[( ij << 3 ) + j1][1]), L_shl(fj, Q5) , dft_res_gains_q_fx[( ij << 3 ) + j1 + 1][1]); + move32(); + } + ELSE + { + rout[i] = dft_res_gains_q_fx[( ij << 3 ) + 7][1]; + move32(); + } + } + return; +} + +/*------------------------------------------------------------------------- + * stereo_dft_dec_update_fx() + * + * Update DFT memories for new frame + *-------------------------------------------------------------------------*/ + +void stereo_dft_dec_update_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word16 output_frame, /* i : output frame length */ + const Word16 sba_dirac_stereo_flag /* i : signal stereo output for SBA DirAC */ +) +{ + Word16 b, i, k_offset; + + /* Initialization */ + k_offset = STEREO_DFT_OFFSET; /*Add an offset*/ + move16(); + /* Update parameters */ + FOR ( i = 0; i < k_offset * STEREO_DFT_BAND_MAX; i++ ) + { + hStereoDft->side_gain_fx[i] = hStereoDft->side_gain_fx[STEREO_DFT_NBDIV * STEREO_DFT_BAND_MAX + i]; + move32(); + hStereoDft->res_pred_gain_fx[i] = hStereoDft->res_pred_gain_fx[STEREO_DFT_NBDIV * STEREO_DFT_BAND_MAX + i]; + move32(); + } + + FOR ( i = 0; i < k_offset; i++ ) + { + hStereoDft->gipd_fx[i] = hStereoDft->gipd_fx[STEREO_DFT_NBDIV + i]; + move32(); + } + + /* Update configuration memories */ + FOR ( i = 0; i < k_offset; i++ ) + { + hStereoDft->band_res[i] = hStereoDft->band_res[i + STEREO_DFT_NBDIV]; + move16(); + hStereoDft->prm_res[i] = hStereoDft->prm_res[i + STEREO_DFT_NBDIV]; + move16(); + hStereoDft->itd_fx[i] = hStereoDft->itd_fx[STEREO_DFT_NBDIV + i]; + move32(); + hStereoDft->res_cod_mode[i] = hStereoDft->res_cod_mode[i + STEREO_DFT_NBDIV]; + move16(); + hStereoDft->res_pred_mode[i] = hStereoDft->res_pred_mode[i + STEREO_DFT_NBDIV]; + move16(); + } + + /* Load new configurations */ + set_s( hStereoDft->band_res + k_offset, hStereoDft->hConfig->band_res, STEREO_DFT_NBDIV ); + set_s( hStereoDft->prm_res + k_offset, hStereoDft->hConfig->prm_res, STEREO_DFT_NBDIV ); + set_s( hStereoDft->res_pred_mode + k_offset, hStereoDft->hConfig->res_pred_mode, STEREO_DFT_NBDIV ); + set_s( hStereoDft->res_cod_mode + k_offset, hStereoDft->hConfig->res_cod_mode, STEREO_DFT_NBDIV ); + + /*Update attack info*/ + IF ( hStereoDft->attackPresent ) + { + hStereoDft->wasTransient = 1; + move16(); + } + ELSE IF ( hStereoDft->wasTransient ) + { + hStereoDft->wasTransient = 0; + move16(); + } + + FOR ( i = STEREO_DFT_CORE_HIST_MAX - 1; i > 0; i-- ) + { + hStereoDft->core_hist[i] = hStereoDft->core_hist[i - 1]; + move16(); + } + + Copy32( hStereoDft->hb_stefi_sig_fx + output_frame, hStereoDft->hb_stefi_sig_fx, hStereoDft->hb_stefi_delay ); + Copy32( hStereoDft->hb_nrg_fx, hStereoDft->hb_nrg_fx + 1, STEREO_DFT_CORE_HIST_MAX - 1 ); + Copy32( hStereoDft->td_gain_fx, hStereoDft->td_gain_fx + 1, STEREO_DFT_CORE_HIST_MAX - 1 ); + Copy32( hStereoDft->q_td_gain, hStereoDft->q_td_gain + 1, STEREO_DFT_CORE_HIST_MAX - 1); + + IF ( sba_dirac_stereo_flag ) + { + /* buffer update, push back by 2 because of 2 subframes */ + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + FOR ( i = SBA_DIRAC_NRG_SMOOTH_LONG; i > 1; i-- ) + { + hStereoDft->smooth_buf_fx[b][i] = hStereoDft->smooth_buf_fx[b][i - 2]; + move32(); + } + } + } + + return; +} + +/*------------------------------------------------------------------------- + * stereo_dft_dec_synthesize_fx() + * + * Inverse DFT on a 20ms frame + *-------------------------------------------------------------------------*/ + +void stereo_dft_dec_synthesize_fx( + CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ + Word32 DFT[CPE_CHANNELS][STEREO_DFT_BUF_MAX], /* i : DFT buffers */ + const Word16 chan, /* i : channel number */ + Word32 output[L_FRAME48k], /* o : output synthesis signal */ + const Word16 output_frame /* i : output frame length */ +) +{ + Word16 i, k; + Word16 offset; + STEREO_DFT_DEC_DATA_HANDLE hStereoDft; + Word32 *p_DFT; + const Word16 *win, *win2; + Word16 trigo_dec[((STEREO_DFT32MS_N_MAX) >> 1) + 1]; + Word16 trigo_step; + Word16 ovl, zp, NFFT; + Word32 outputFs; + Word16 ovl2, flat_portion_end; + Word32 ola_buff[STEREO_DFT32MS_OVL2_MAX]; + Word16 moffset; + push_wmops( "DFT_synthesis" ); + + /*-----------------------------------------------------------------* + * Initialization + *-----------------------------------------------------------------*/ + + hStereoDft = hCPE->hStereoDft; + + outputFs = L_mult0(output_frame, FRAMES_PER_SEC); + + zp = NS2SA( outputFs, STEREO_DFT32MS_ZP_NS ); + move16(); + ovl = NS2SA( outputFs, STEREO_DFT32MS_OVL_NS ); + move16(); + win = hStereoDft->win32ms_fx; + NFFT = NS2SA( outputFs, STEREO_DFT32MS_N_NS ); + move16(); + ovl2 = NS2SA( outputFs, STEREO_DFT32MS_OVL2_NS ); + move16(); + flat_portion_end = NS2SA( outputFs, L_sub(STEREO_DFT32MS_WIN_CENTER_NS , L_shr(STEREO_DFT32MS_OVL2_NS, 1)) ); + move16(); + win2 = hStereoDft->win232ms_fx; + + p_DFT = DFT[chan]; + set_val_Word32( output, 0, NS2SA( outputFs, FRAME_SIZE_NS ) ); + + /* deactivating the spectrum scrambling on active speech */ + IF ( ( EQ_16(chan, 0) && GT_16(hCPE->hCoreCoder[0]->last_coder_type, UNVOICED) ) || EQ_16(hCPE->last_element_mode, IVAS_CPE_MDCT) || LT_16(hCPE->last_element_mode, IVAS_CPE_DFT) ) + { + hCPE->stereo_switching_counter = 10; + move16(); + } + + IF ( EQ_16(hCPE->stereo_switching_counter, 0) ) + { + /* Set the level of dispersion */ + hCPE->NbFrameMod = (int16_t) ( 12.0f * max( -0.1f, min( 0.4, hCPE->lt_es_em ) ) + 1.2f + 0.5f ); /* -0.1: -0.4 ; -0.1 -> 0, 0.4 -> 6*/ + } + moffset = max( 0, 6 - hCPE->NbFrameMod ); + + /*-----------------------------------------------------------------* + * Synthesis + *-----------------------------------------------------------------*/ + + trigo_step = i_mult(hStereoDft->dft_trigo_step, STEREO_DFT_TRIGO_DEC_STEP); + FOR ( i = 0; i < shr(NFFT, 2); i++ ) + { + trigo_dec[i] = hStereoDft->dft_trigo_fx[i * trigo_step]; + move16(); + trigo_dec[sub(shr(NFFT , 1) , i)] = hStereoDft->dft_trigo_fx[i * trigo_step]; + move16(); + } + trigo_dec[shr(NFFT , 2)] = hStereoDft->dft_trigo_fx[shr(NFFT , 2) * trigo_step]; + move16(); + + FOR ( k = 0; k < STEREO_DFT_NBDIV; k++ ) + { + /* scrambling the spectrum */ + IF ( LE_16(hCPE->stereo_switching_counter , 6) && EQ_16(chan, 1) && ( hCPE->lt_es_em > -0.4f || GT_16(hCPE->NbFrameMod, 4) ) ) + { + FOR ( i = 3; i < NFFT - moffset - 1; i++ ) + { + p_DFT[i] = L_negate(p_DFT[i + moffset + 1]); + move32(); + } + } + ELSE IF ( LT_16(hCPE->stereo_switching_counter, 7) && ( hCPE->lt_es_em > 0.2f || GT_16(hCPE->NbFrameMod , 4) ) ) + { + FOR ( i = sub(16 , hCPE->NbFrameMod); i < sub(NFFT, add(moffset, 1)); i++ ) + { + p_DFT[i - 2] = L_negate(p_DFT[i + moffset + 1]); + move32(); + } + } + + /*IFFT*/ + rfft_fx( p_DFT, trigo_dec, NFFT, +1 ); + + IF ( EQ_16(k , 0) ) + { + offset = 0; + move16(); + + /* Left OLA - 3.125ms */ + FOR ( i = 0; i < ovl; i++ ) + { + output[offset + i] = Mpy_32_16_1(L_add(hCPE->output_mem_fx[chan][i], p_DFT[zp + i]), win[STEREO_DFT32MS_STEP * i]); + move32(); + } + /* Flat Portion */ + FOR ( i = ovl; i < flat_portion_end; i++ ) + { + output[offset + i] = p_DFT[zp + i]; + move32(); + } + /* Right OLA */ + FOR ( i = 0; i < ovl2; i++ ) + { + ola_buff[i] = Mpy_32_16_1( p_DFT[NFFT - zp - ovl2 + i], win2[ovl2 - 1 - i]); + move32(); + } + } + ELSE + { + /* If OVL2 = OVL offset = 10ms */ + offset = flat_portion_end; + move16(); + /* Left OLA */ + FOR ( i = 0; i < ovl2; i++ ) + { + output[offset + i] = Madd_32_16(ola_buff[i], p_DFT[zp + i], win2[i]); + move32(); + } + /* Flat Portion */ + FOR ( i = ovl2; i < NFFT - 2 * zp - ovl; i++ ) + { + output[offset + i] = p_DFT[zp + i]; + move32(); + } + /* Right OLA - 3.125ms */ + FOR ( i = 0; i < ovl; i++ ) + { + hCPE->output_mem_fx[chan][i] = Mpy_32_16_1(p_DFT[NFFT - zp - ovl + i], win[STEREO_DFT32MS_STEP * ( ovl - 1 - i )]); + move32(); + } + } + p_DFT += STEREO_DFT32MS_N_MAX; + } + + + pop_wmops(); + return; +} + +/*--------------------------------------------------------------- + * stereo_dft_dec_smooth_parameters_fx() + * + * + * ---------------------------------------------------------------*/ + +void stereo_dft_dec_smooth_parameters_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word16 prev_sid_nodata, /* i : Previous SID/No data indicator */ + const Word16 active_frame_counter, /* i : Active frame counter */ + const Word32 element_brate /* i : Element bitrate */ +) +{ + Word16 k_offset, k, k2, b, N_div; + Word32 *pIpd, *pInterpol; + Word32 *pgIpd; + Word32 *pSideGain; + Word32 diff_ipd; + Word16 nbands; + Word32 max_res_pred_ind; + + N_div = STEREO_DFT_NBDIV; + move16(); + k_offset = STEREO_DFT_OFFSET; + move16(); + + IF ( hStereoDft->frame_sid_nodata || prev_sid_nodata ) + { + k = 1; + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + *( hStereoDft->side_gain_fx + ( ( add( k , k_offset ) ) - 1 ) * STEREO_DFT_BAND_MAX + b ) = *( hStereoDft->side_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX + b ); + move32(); + } + + IF ( hStereoDft->frame_sid_nodata ) + { + /* set new xfade target if new itd received */ + IF ( NE_32(hStereoDft->gipd_fx[add( k , k_offset )], hStereoDft->ipd_xfade_target_fx) ) + { + Word16 q_val; + IF ( GT_32(L_sub( hStereoDft->gipd_fx[add( k , k_offset )], hStereoDft->ipd_xfade_prev_fx ), EVS_PI_FX) ) + { + hStereoDft->ipd_xfade_target_fx = L_sub(hStereoDft->gipd_fx[add( k , k_offset )], EVS_PI_FX); + move32(); + hStereoDft->ipd_xfade_step_fx = BASOP_Util_Divide3232_Scale(L_sub( hStereoDft->ipd_xfade_target_fx, hStereoDft->ipd_xfade_prev_fx ) , L_sub( STEREO_DFT_ITD_CNG_XFADE, hStereoDft->ipd_xfade_counter ), &q_val); + move32(); + IF (GT_16(q_val, 16)) + { + assert(0); + } + ELSE + { + hStereoDft->ipd_xfade_step_fx = L_shl(hStereoDft->ipd_xfade_step_fx, q_val); + } + } + ELSE IF ( GT_32(L_sub( hStereoDft->ipd_xfade_prev_fx, hStereoDft->gipd_fx[add( k , k_offset )] ), EVS_PI_FX) ) + { + hStereoDft->ipd_xfade_target_fx = L_add(hStereoDft->gipd_fx[add( k , k_offset )], L_shl(EVS_PI_FX, 1)); + move32(); + hStereoDft->ipd_xfade_step_fx = BASOP_Util_Divide3232_Scale(L_sub( hStereoDft->ipd_xfade_target_fx, hStereoDft->ipd_xfade_prev_fx ) , L_sub( STEREO_DFT_ITD_CNG_XFADE, hStereoDft->ipd_xfade_counter ), &q_val); + move32(); + IF (GT_16(q_val, 16)) + { + assert(0); + } + ELSE + { + hStereoDft->ipd_xfade_step_fx = L_shl(hStereoDft->ipd_xfade_step_fx, q_val); + } + } + ELSE + { + hStereoDft->ipd_xfade_target_fx = hStereoDft->gipd_fx[add( k , k_offset )]; + move32(); + hStereoDft->ipd_xfade_step_fx = BASOP_Util_Divide3232_Scale(L_sub( hStereoDft->ipd_xfade_target_fx, hStereoDft->ipd_xfade_prev_fx ) , L_sub( STEREO_DFT_ITD_CNG_XFADE, hStereoDft->ipd_xfade_counter ), &q_val); + move32(); + IF (GT_16(q_val, 16)) + { + assert(0); + } + ELSE + { + hStereoDft->ipd_xfade_step_fx = L_shl(hStereoDft->ipd_xfade_step_fx, q_val); + } + } + } + + /* xfade */ + IF ( NE_32(hStereoDft->ipd_xfade_prev_fx, hStereoDft->ipd_xfade_target_fx) && LT_16(hStereoDft->ipd_xfade_counter, STEREO_DFT_ITD_CNG_XFADE) && LE_32(hStereoDft->last_active_element_brate, 24400) ) + { + hStereoDft->gipd_fx[add( k , k_offset )] = L_add(hStereoDft->ipd_xfade_prev_fx, hStereoDft->ipd_xfade_step_fx); + move32(); + hStereoDft->ipd_xfade_prev_fx = hStereoDft->gipd_fx[add( k , k_offset )]; + move32(); + hStereoDft->ipd_xfade_counter++; + } + } + ELSE + { + /* First active frame, "reset" everything if long enough active encoding, only triggered if STEREO_DFT_ITD_CNG_XFADE_RESET = -1 */ + IF ( GT_16(active_frame_counter, STEREO_DFT_ITD_CNG_XFADE_RESET) ) + { + hStereoDft->ipd_xfade_target_fx = hStereoDft->gipd_fx[add( k , k_offset )]; + move32(); + hStereoDft->ipd_xfade_prev_fx = hStereoDft->gipd_fx[add( k , k_offset )]; + move32(); + hStereoDft->ipd_xfade_counter = 0; + move16(); + } + } + + FOR ( k2 = 1; k2 < hStereoDft->prm_res[add( k , k_offset )]; k2++ ) + { + hStereoDft->gipd_fx[( add( k , k_offset ) ) - k2] = hStereoDft->gipd_fx[add( k , k_offset )]; + move32(); + } + + IF ( hStereoDft->frame_sid_nodata ) + { + /* set new xfade target if new itd received */ + IF ( NE_32(hStereoDft->itd_fx[add( k , k_offset )], hStereoDft->itd_xfade_target_fx) ) + { + Word16 q_val; + hStereoDft->itd_xfade_target_fx = hStereoDft->itd_fx[add( k , k_offset )]; + move32(); + hStereoDft->itd_xfade_step_fx = BASOP_Util_Divide3232_Scale(L_sub( hStereoDft->itd_xfade_target_fx, hStereoDft->itd_xfade_prev_fx) , sub( STEREO_DFT_ITD_CNG_XFADE, hStereoDft->itd_xfade_counter ), &q_val); + IF (GT_16(q_val, 16)) + { + assert(0); + } + ELSE + { + hStereoDft->itd_xfade_step_fx = L_shl(hStereoDft->itd_xfade_step_fx, q_val); + } + move32(); + } + + /* xfade */ + IF ( NE_32(hStereoDft->itd_xfade_prev_fx, hStereoDft->itd_xfade_target_fx) && LT_16(hStereoDft->itd_xfade_counter, STEREO_DFT_ITD_CNG_XFADE) && LE_32(hStereoDft->last_active_element_brate, 24400) ) + { + hStereoDft->itd_fx[add( k , k_offset )] = L_add(hStereoDft->itd_xfade_prev_fx , hStereoDft->itd_xfade_step_fx); + move32(); + hStereoDft->itd_xfade_prev_fx = hStereoDft->itd_fx[add( k , k_offset )]; + move32(); + hStereoDft->itd_xfade_counter++; + } + } + ELSE + { + /* First active frame, "reset" everything if long enough active encoding, only triggered if STEREO_DFT_ITD_CNG_XFADE_RESET = -1 */ + IF ( GT_16(active_frame_counter, STEREO_DFT_ITD_CNG_XFADE_RESET) ) + { + hStereoDft->itd_xfade_target_fx = hStereoDft->itd_fx[add( k , k_offset )]; + move32(); + hStereoDft->itd_xfade_prev_fx = hStereoDft->itd_fx[add( k , k_offset )]; + move32(); + hStereoDft->itd_xfade_counter = 0; + move32(); + } + + hStereoDft->last_active_element_brate = element_brate; + move32(); + } + FOR ( k2 = 1; k2 < hStereoDft->prm_res[add( k , k_offset )]; k2++ ) + { + hStereoDft->itd_fx[( add( k , k_offset ) ) - k2] = hStereoDft->itd_fx[add( k , k_offset )]; + move32(); + } + + return; + } + + /* Active frame, "reset" everything "reset" everything if long enough active encoding */ + IF ( GT_16(active_frame_counter, STEREO_DFT_ITD_CNG_XFADE_RESET )) + { + hStereoDft->itd_xfade_counter = 0; + move16(); + hStereoDft->itd_xfade_target_fx = hStereoDft->itd_fx[STEREO_DFT_NBDIV - 1]; + move32(); + hStereoDft->itd_xfade_prev_fx = hStereoDft->itd_fx[STEREO_DFT_NBDIV - 1]; + move32(); + hStereoDft->ipd_xfade_counter = 0; + move16(); + hStereoDft->ipd_xfade_target_fx = hStereoDft->gipd_fx[STEREO_DFT_NBDIV - 1]; + move32(); + hStereoDft->ipd_xfade_prev_fx = hStereoDft->gipd_fx[STEREO_DFT_NBDIV - 1]; + move32(); + } + + hStereoDft->last_active_element_brate = element_brate; + move32(); + + FOR ( k = hStereoDft->prm_res[k_offset] - 1; k < N_div; k += hStereoDft->prm_res[add( k , k_offset )] ) + { + max_res_pred_ind = 0; + move32(); + IF ( EQ_16(hStereoDft->reverb_flag, 1) ) + { + nbands = min( 10, hStereoDft->nbands_respred ); + move16(); + /*Shift 2 last bands residual prediction gains for SWB/FB*/ + IF ( EQ_16(hStereoDft->band_res[k_offset], STEREO_DFT_BAND_RES_HIGH) ) + { + FOR ( b = hStereoDft->nbands_respred - 1; b >= nbands; b-- ) + { + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX] = + hStereoDft->res_gains_ind_fx[1][b - STEREO_DFT_RES_PRED_BAND_MIN_RED + hStereoDft->res_pred_band_min + STEREO_DFT_BAND_MAX]; + move32(); + hStereoDft->res_gains_ind_fx[1][b - STEREO_DFT_RES_PRED_BAND_MIN_RED + hStereoDft->res_pred_band_min + STEREO_DFT_BAND_MAX] = 0; + move32(); + } + } + + /* Get maximal index */ + FOR ( b = hStereoDft->res_pred_band_min; b < ( nbands - STEREO_DFT_RES_PRED_BAND_MIN_CONST ); b++ ) + { + IF ( LT_32(max_res_pred_ind, hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX]) ) + { + max_res_pred_ind = hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX]; + move32(); + } + } + + /* predictive values */ + FOR ( ; b < nbands; b++ ) + { + assert( hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX] == 0 ); + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX] = max_res_pred_ind; + move32(); + } + } + + FOR ( b = hStereoDft->res_pred_band_min; b < hStereoDft->res_cod_band_max; b++ ) + { + Word32 tmp; + Word16 tmps1, tmps2; + + hStereoDft->res_gains_ind_fx[0][b] = hStereoDft->res_gains_ind_fx[0][b + STEREO_DFT_BAND_MAX]; + move32(); + /*stereo_dft_dequantize_res_gains_f(&hStereoDft->res_gains_ind[0][b], &hStereoDft->res_gains_ind[1][b+STEREO_DFT_BAND_MAX],hStereoDft->side_gain+(k+k_offset)*STEREO_DFT_BAND_MAX+b, hStereoDft->res_pred_gain+(k+k_offset)*STEREO_DFT_BAND_MAX+b, 1);*/ + tmps1 = (Word16) L_shr( hStereoDft->res_gains_ind_fx[0][b], Q26 ); + move16(); + tmps2 = (Word16) L_shr( hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], Q26 ); + move16(); + stereo_dft_dequantize_res_gains_fx( &tmps1, &tmps2, hStereoDft->side_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX + b, hStereoDft->res_pred_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX + b, 1 ); + + IF ( hStereoDft->attackPresent ) + { + hStereoDft->res_gains_ind_fx[1][b] = Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], (Word16)0x6666); + move32(); + } + ELSE IF ( hStereoDft->trans || ( hStereoDft->res_pred_mode[k] && ( hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX] < ONE_IN_Q27 ) ) ) /* Assuming Maximum Q of res_gains_ind_fx is Q26 */ + { + hStereoDft->res_gains_ind_fx[1][b] = Madd_32_16(Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], (Word16)0x4CCD), + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], (Word16)0x3333); + move32(); + } + ELSE + { + hStereoDft->res_gains_ind_fx[1][b] = Madd_32_16( Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], dft_alpha_s2_fx[b]), + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], + sub( (Word16)0x7FFF, dft_alpha_s2_fx[b] )); + move32(); + } + + stereo_dft_dequantize_res_gains_f_fx( &hStereoDft->res_gains_ind_fx[0][b], &hStereoDft->res_gains_ind_fx[1][b], &tmp, hStereoDft->res_pred_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX + b, 1 ); + } + + /* Smoothing of prediction gains between ftrames */ + FOR ( ; b < hStereoDft->nbands; b++ ) + { + IF ( hStereoDft->attackPresent ) + { + hStereoDft->res_gains_ind_fx[0][b] = hStereoDft->res_gains_ind_fx[0][b + STEREO_DFT_BAND_MAX]; + move32(); + hStereoDft->res_gains_ind_fx[1][b] = Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], (Word16)0x6666); + move32(); + } + ELSE IF ( hStereoDft->trans || ( hStereoDft->res_pred_mode[k] && LT_32( hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], ONE_IN_Q27 ) ) ) + { + hStereoDft->res_gains_ind_fx[0][b] = hStereoDft->res_gains_ind_fx[0][b + STEREO_DFT_BAND_MAX]; + move32(); + IF ( EQ_16(hStereoDft->hConfig->band_res, STEREO_DFT_BAND_RES_LOW) ) + { + hStereoDft->res_gains_ind_fx[1][b] = Madd_32_16(Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], dft_alpha_w_b2_fx[b]), + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], sub((Word16)0x7FFF, dft_alpha_w_b2_fx[b])); + move32(); + } + ELSE + { + hStereoDft->res_gains_ind_fx[1][b] = Madd_32_16(Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], dft_alpha_w_fx[b]), + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], sub((Word16)0x7FFF, dft_alpha_w_fx[b] )); + move32(); + } + } + ELSE + { + IF ( EQ_16(hStereoDft->hConfig->band_res, STEREO_DFT_BAND_RES_LOW) ) + { + hStereoDft->res_gains_ind_fx[0][b] = Madd_32_16(Mpy_32_16_1(hStereoDft->res_gains_ind_fx[0][b], dft_alpha_s_b2_fx[b]), + hStereoDft->res_gains_ind_fx[0][b + STEREO_DFT_BAND_MAX], + sub( (Word16)0x7FFF, dft_alpha_s_b2_fx[b] ) ); + move32(); + hStereoDft->res_gains_ind_fx[1][b] = Madd_32_16(Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], dft_alpha_s2_b2_fx[b]), + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], + sub( (Word16)0x7FFF, dft_alpha_s2_b2_fx[b] ) ); + move32(); + } + ELSE + { + hStereoDft->res_gains_ind_fx[0][b] = Madd_32_16(Mpy_32_16_1(hStereoDft->res_gains_ind_fx[0][b], dft_alpha_s_fx[b]), + hStereoDft->res_gains_ind_fx[0][b + STEREO_DFT_BAND_MAX], + sub((Word16)(0x7FFF), dft_alpha_s_fx[b] )); + move32(); + hStereoDft->res_gains_ind_fx[1][b] = Madd_32_16(Mpy_32_16_1(hStereoDft->res_gains_ind_fx[1][b], dft_alpha_s2_fx[b]), + hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], + sub((Word16)(0x7FFF), dft_alpha_s2_fx[b] ) ); + move32(); + } + } + + IF ( !hStereoDft->recovery_flg ) + { + stereo_dft_dequantize_res_gains_f_fx( &hStereoDft->res_gains_ind_fx[0][b], &hStereoDft->res_gains_ind_fx[1][b], hStereoDft->side_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX + b, hStereoDft->res_pred_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX + b, 1 ); + } + } + + /* Smoothing of IPDs*/ + pgIpd = hStereoDft->gipd_fx + ( add( k , k_offset ) ); + diff_ipd = L_sub(pgIpd[0] , pgIpd[-hStereoDft->prm_res[add( k , k_offset )]]); + IF ( LT_32(diff_ipd, -EVS_PI_FX) ) + { + pgIpd[0] = L_add(L_add(pgIpd[0], EVS_PI_FX), EVS_PI_FX); + } + ELSE IF ( GT_32(diff_ipd, EVS_PI_FX) ) + { + pgIpd[0] = L_sub(L_sub(pgIpd[0], EVS_PI_FX), EVS_PI_FX); + } + + IF ( !hStereoDft->attackPresent ) + { + IF ( hStereoDft->wasTransient ) + { + pgIpd[0] = L_add(Mpy_32_16_1(pgIpd[0], (Word16)0x6666), Mpy_32_16_1(pgIpd[-hStereoDft->prm_res[add( k , k_offset )]], (Word16)(0x199A))); + move16(); + } + ELSE + { + pgIpd[0] = L_add(L_shr(pgIpd[0], 1), L_shr(pgIpd[-hStereoDft->prm_res[add( k , k_offset )]], 1)); + move16(); + } + } + + + IF ( !hStereoDft->attackPresent ) + { + pSideGain = hStereoDft->side_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX; + FOR ( b = 0; b < hStereoDft->res_cod_band_max; b++ ) + { + pSideGain[b] = Madd_32_16(Mpy_32_16_1(pSideGain[b], dft_res_cod_alpha_fx[b]), + pSideGain[b - hStereoDft->prm_res[add( k , k_offset )] * STEREO_DFT_BAND_MAX], + sub( (Word16)0x7FFF, dft_res_cod_alpha_fx[b] ) ); + move32(); + } + } + + /*Interpolation between DFT slots*/ + FOR ( k2 = 1; k2 < hStereoDft->prm_res[add( k , k_offset )]; k2++ ) + { + pInterpol = hStereoDft->gipd_fx + sub( add( k , k_offset ) , k2 ); + pIpd = hStereoDft->gipd_fx + add( k , k_offset ); + IF ( hStereoDft->attackPresent ) + { + *( pInterpol ) = *( pIpd ); + move32(); + } + ELSE + { + *( pInterpol ) = *( hStereoDft->gipd_fx + ( add( k , k_offset ) - hStereoDft->prm_res[add( k , k_offset )] ) ); + move32(); + } + + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + *( hStereoDft->res_pred_gain_fx + sub( add( k , k_offset ) , k2 ) * STEREO_DFT_BAND_MAX + b ) = *( hStereoDft->res_pred_gain_fx + ( add( k , k_offset ) - hStereoDft->prm_res[add( k , k_offset )] ) * STEREO_DFT_BAND_MAX + b ); + move32(); + IF ( b < hStereoDft->res_cod_band_max || hStereoDft->attackPresent || hStereoDft->trans || ( hStereoDft->res_pred_mode[k] && LT_32( hStereoDft->res_gains_ind_fx[1][b + STEREO_DFT_BAND_MAX], ONE_IN_Q27 ) ) ) + { + *( hStereoDft->side_gain_fx + sub( add( k , k_offset ) , k2 ) * STEREO_DFT_BAND_MAX + b ) = *( hStereoDft->side_gain_fx + ( add( k , k_offset ) ) * STEREO_DFT_BAND_MAX + b ); + move32(); + } + ELSE + { + *( hStereoDft->side_gain_fx + sub( add( k , k_offset ) , k2 ) * STEREO_DFT_BAND_MAX + b ) = *( hStereoDft->side_gain_fx + ( add( k , k_offset ) - hStereoDft->prm_res[add( k , k_offset )] ) * STEREO_DFT_BAND_MAX + b ); + move32(); + } + } + + hStereoDft->itd_fx[( add( k , k_offset ) ) - k2] = hStereoDft->itd_fx[add( k , k_offset )]; + move32(); + } /*end of interpolation*/ + } + + return; +} + + +/*------------------------------------------------------------------------- + * stereo_dft_dec_fx() + * + * DFT-based stereo main processing function + *-------------------------------------------------------------------------*/ + +void stereo_dft_dec_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + Decoder_State *st0, /* i/o: decoder state structure */ + Word32 DFT[CPE_CHANNELS][STEREO_DFT_BUF_MAX], /* i/o: DFT buffers */ + Word32 *input_mem, /* i/o: mem of buffer DFT analysis */ + STEREO_CNG_DEC_HANDLE hStereoCng, /* i/o: Stereo CNG data structure */ + const Word16 sba_dirac_stereo_flag, /* i : signal stereo output for SBA DirAC */ + const Word16 sba_mono_flag, /* i : signal mono output for SBA DirAC */ + ivas_spar_md_dec_state_t *hMdDec, /* i : SPAR MD handle for upmixing */ + const Word16 cross_fade_start_offset, /* i : SPAR mixer delay compensation */ + const Word32 output_Fs, /* i : Fs for delay calculation */ + const Word16 nchan_transport, /* i : number of transpor channels */ + const Word16 num_md_sub_frames /* i : number of MD subframes */ +) +{ + Word16 i, k, b, N_div, stop; + Word32 DFT_L[STEREO_DFT32MS_N_MAX]; + Word32 DFT_R[STEREO_DFT32MS_N_MAX]; + Word32 DFT_PRED_RES[STEREO_DFT32MS_N_32k]; + Word32 *pDFT_DMX; + Word32 *pDFT_DMX1; + Word32 *pDFT_RES; + Word16 g; + Word32 tmp; + Word32 *pPredGain; + Word32 *pSideGain; + Word16 c0, s0; + Word16 k_offset; + Word32 *pgIpd; + Word16 NFFT_inner; + Word16 gamma; + Word16 samp_ratio; + Word16 prev_bfi; + Word32 dmx_nrg; + Word16 idx_k0, idx_k1; + Word16 output_frame; + Word16 plocs[STEREO_DFT_RES_N_PEAKS_MAX]; + Word16 num_plocs; + Word32 plocsi[STEREO_DFT_RES_N_PEAKS_MAX]; + Word16 ftmp, coh; + Word32 N1, N2; + Word32 scale_fact0, scale_fact; + Word32 lev1, lev2, cna_level, *ptr_per; + Word16 q_cna_level; + HANDLE_FD_CNG_DEC hFdCngDec = st0->hFdCngDec; + HANDLE_FD_CNG_COM hFdCngCom = hFdCngDec->hFdCngCom; + Word16 *cna_seed = &( hFdCngCom->seed); + Word32 DFT_W, DFT_Y; + Word16 q_samp_ratio = Q15; + + output_frame = (Word16) Mpy_32_32( L_add(st0->output_Fs , FRAMES_PER_SEC_BY_2), ONE_BY_FRAMES_PER_SEC); + + /*------------------------------------------------------------------* + * Initialization + *-----------------------------------------------------------------*/ + + samp_ratio = (Word16)BASOP_Util_Divide3232_Scale(st0->sr_core, st0->output_Fs, &q_samp_ratio); + samp_ratio = shr(samp_ratio , sub(Q15 - Q12, q_samp_ratio)); + + + stop = shr(STEREO_DFT32MS_N_32k , 1); + + /* Analyze nature of current frame */ + hStereoDft->trans = (Word16)( ( EQ_16( st0->clas_dec, ONSET ) || EQ_16( st0->clas_dec, SIN_ONSET ) || EQ_16( st0->clas_dec, UNVOICED_CLAS ) || EQ_16( st0->clas_dec, UNVOICED_TRANSITION ) ) || LE_16( st0->stab_fac_fx, (Word16)0x2000 ) ) || + ( (EQ_16(st0->core, TCX_20_CORE) && ( EQ_16( st0->hTcxCfg->tcx_last_overlap_mode, MIN_OVERLAP ) || EQ_16( st0->hTcxCfg->tcx_last_overlap_mode, HALF_OVERLAP ) ) ) || EQ_16( st0->core, TCX_10_CORE )); + move16(); + + /* Initialization */ + k_offset = 1; + move16(); + N_div = STEREO_DFT_NBDIV; + move16(); + prev_bfi = st0->prev_old_bfi; /* The core decoding is already completed here and the prev_bfi has been updated for the next frame. + The prev_old_bfi still holds the prev_bfi for the current frame. */ + /* make sure number of bands corresponds to output bwidth in case it is lower than parameter bwidth */ + move16(); + IF ( LT_16(output_frame, inner_frame_tbl[st0->bwidth]) && EQ_16(sba_dirac_stereo_flag, 0) ) + { + hStereoDft->nbands = stereo_dft_band_config_fx( hStereoDft->band_limits, hStereoDft->band_res[k_offset], hStereoDft->NFFT, DEC ); + } + + IF ( EQ_16(st0->bfi, 0) ) + { + /* Smoothing for the current frame */ + IF ( sba_dirac_stereo_flag ) + { + ivas_sba_dirac_stereo_smooth_parameters_fx( hStereoDft, hMdDec, cross_fade_start_offset, output_Fs, num_md_sub_frames ); + } + ELSE + { + stereo_dft_dec_smooth_parameters_fx( hStereoDft, hStereoCng->prev_sid_nodata, hStereoCng->active_frame_counter, st0->element_brate ); + } + } + + dmx_nrg = 0; + move32(); + IF ( prev_bfi ) + { + dmx_nrg = stereo_dft_dmx_swb_nrg_fx( DFT[0], DFT[0] + STEREO_DFT32MS_N_MAX, min( hStereoDft->NFFT, STEREO_DFT32MS_N_32k ) ); + } + + +#ifdef DEBUG_PRINT + printf( "\nframe: %d\n", frame ); +#endif + FOR ( k = 0; k < N_div; k++ ) + { + pDFT_DMX = DFT[0] + i_mult(k , STEREO_DFT32MS_N_MAX); + pDFT_RES = DFT[1] + i_mult(k , STEREO_DFT32MS_N_MAX); + pDFT_DMX1 = 0; + IF ( GT_16(nchan_transport, 1) ) + { + pDFT_DMX1 = DFT[1] + i_mult(k , STEREO_DFT32MS_N_MAX); + } + + /*Apply Stereo*/ + IF ( hStereoDft->hConfig->dmx_active ) + { + g = MAX_16; + move16(); + c0 = MAX_16; + move16(); + s0 = 0; + move16(); + + /* since delay is just 3.125ms, the parameters received are used for the second window */ + pSideGain = hStereoDft->side_gain_fx + i_mult(add( k , k_offset ) , STEREO_DFT_BAND_MAX); + pgIpd = hStereoDft->gipd_fx + add( k , k_offset ); + pPredGain = hStereoDft->res_pred_gain_fx + i_mult(add( k , k_offset ) , STEREO_DFT_BAND_MAX); + +#ifdef DEBUG_PRINT + if ( k == 0 ) + { + printf( "Window0\n" ); + } + else + { + printf( "Window1\n" ); + } + for ( b = 0; b < hStereoDft->nbands; b++ ) + printf( "%.6f ", pSideGain[b] ); + printf( "\n" ); + for ( b = 0; b < hStereoDft->nbands; b++ ) + printf( "%.6f ", pPredGain[b] ); + printf( "\n" ); +#endif + + /* Use coarse band partition in inactive frames */ + IF ( hStereoDft->frame_sid_nodata && !sba_dirac_stereo_flag ) + { + NFFT_inner = i_mult((STEREO_DFT32MS_N_MAX / L_FRAME48k), inner_frame_tbl[st0->bwidth]); + hStereoDft->nbands = stereo_dft_band_config_fx( hStereoDft->band_limits, 2, NFFT_inner, DEC ); + } + + + IF ( st0->bfi ) + { + hStereoDft->past_DMX_pos = ( hStereoDft->past_DMX_pos + STEREO_DFT_PAST_MAX - 1 ) % STEREO_DFT_PAST_MAX; + } + + IF ( !( sba_dirac_stereo_flag && GE_16(nchan_transport, 2) ) ) + { + stereo_dft_generate_res_pred_fx( hStereoDft, samp_ratio, pDFT_DMX, DFT_PRED_RES, pPredGain, k, DFT[1] + k * STEREO_DFT32MS_N_MAX, &stop, st0->bfi ); + } + + IF ( GT_16(hStereoDft->res_cod_band_max, 0) ) + { + IF ( !st0->bfi ) + { + IF ( EQ_16(k, 1) ) + { + Copy32( pDFT_RES, hStereoDft->res_mem_fx, 2 * hStereoDft->band_limits[hStereoDft->res_cod_band_max] ); + hStereoDft->time_offs = 0; + move16(); + } + } + ELSE + { + stereo_dft_res_ecu_fx( hStereoDft, pDFT_RES, DFT_PRED_RES, k, output_frame, prev_bfi, dmx_nrg, &num_plocs, plocs, plocsi, input_mem ); + } + } + + /* Apply active DMX */ + /* pDFT_RES is used for the second channel in inactive frames */ + IF ( hStereoDft->frame_sid_nodata && !sba_dirac_stereo_flag ) + { + DFT_L[0] = pDFT_DMX[0]; + move32(); + DFT_R[0] = pDFT_RES[0]; + move32(); + } + ELSE + { + DFT_L[0] = pDFT_DMX[0]; + move32(); + DFT_R[0] = pDFT_DMX[0]; + move32(); + } + + IF ( hStereoDft->frame_sid_nodata || EQ_16(st0->VAD, 0) ) + { + hFdCngDec->cna_nbands = 0; + move16(); + } + + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + g = extract_h(pSideGain[b]); + move16(); + IF ( hStereoDft->frame_sid_nodata && !sba_dirac_stereo_flag ) + { + g = hStereoDft->g_state_fx[b]; + move16(); + } + + /* store side gains from inactive frames for later use by the stereo CNA */ + IF ( LT_16(hStereoDft->band_limits[b], L_FRAME16k) && ( hStereoDft->frame_sid_nodata || EQ_16(st0->VAD, 0) ) ) + { + hFdCngDec->cna_nbands = add(b , 1); + move16(); + hFdCngDec->cna_band_limits[b] = hStereoDft->band_limits[b]; + move16(); + hFdCngDec->cna_g_state_fx[b] = g; + move16(); + } + + /* No residual coding in inactive frames, instead pDFT_RES is used for the second channel */ + IF ( GE_16(b, hStereoDft->res_cod_band_max) && !hStereoDft->frame_sid_nodata && !( sba_dirac_stereo_flag && hMdDec ) ) + { + /*filter non-coded frequencies. It removes some MDCT frequency aliasing*/ + FOR ( i = hStereoDft->band_limits[b]; i < hStereoDft->band_limits[b + 1]; i++ ) + { + pDFT_RES[2 * i] = 0; + move32(); + pDFT_RES[2 * i + 1] = 0; + move32(); + } + } + + IF ( hStereoDft->frame_sid_nodata && !sba_dirac_stereo_flag ) + { + /* Low pass filter coherence */ + /* store coherence from inactive frames for later use by the stereo CNA */ + hFdCngDec->cna_cm_fx[b] = hStereoCng->cm_fx[b]; + move16(); + + /* Calculate gamma */ + IF ( LT_16(hStereoCng->cm_fx[b], (Word16)0x7333) ) + { + Word32 op1, op2, l_gamma; + Word16 q_loc1, q_loc2; + gamma = hStereoCng->cm_fx[b]; + move16(); + gamma = BASOP_Util_Divide3232_Scale(gamma , sub( MAX_16, gamma), &q_loc1); + l_gamma = L_deposit_l(gamma); + op1 = L_add(l_gamma, L_shr(L_deposit_l(sub(MAX_16 , mult(g, g))), q_loc1)); + q_loc1 = Q16 + q_loc1; + q_loc2 = q_loc1; + op1 = Sqrt32(op1, &q_loc1); + op2 = Sqrt32(l_gamma, &q_loc2); + IF (NE_16(q_loc1, q_loc2)) + { + op2 = L_shl(op2, sub(q_loc2, q_loc1)); + q_loc2 = q_loc1; + } + gamma = extract_h(L_sub( op1, op2)); + gamma = shl(gamma, q_loc2); + } + ELSE + { + gamma = 0; + move16(); + } + + FOR ( i = hStereoDft->band_limits[b]; i < hStereoDft->band_limits[b + 1]; i++ ) + { + /* Create L and R signals with the correct coherence by mixing channel 0 (pDFT_DMX) and channel 1 (pDFT_RES) */ + DFT_L[2 * i] = Madd_32_16(Madd_32_16(pDFT_DMX[2 * i], pDFT_DMX[2 * i], g ) , pDFT_RES[2 * i], gamma); + move32(); + DFT_R[2 * i] = Msub_32_16(Msub_32_16(pDFT_DMX[2 * i], pDFT_DMX[2 * i], g ) , pDFT_RES[2 * i], gamma); + move32(); + + DFT_L[2 * i + 1] = Madd_32_16(Madd_32_16(pDFT_DMX[2 * i + 1], pDFT_DMX[2 * i + 1], g) , pDFT_RES[2 * i + 1], gamma); + move32(); + DFT_R[2 * i + 1] = Msub_32_16(Msub_32_16(pDFT_DMX[2 * i + 1], pDFT_DMX[2 * i + 1], g) , pDFT_RES[2 * i + 1], gamma); + move32(); + } + + IF ( NE_32(pgIpd[0] , 0) ) + { + Word32 theta = pgIpd[0]; + WHILE(GT_32(theta , EVS_2PI_FX)) + { + theta = L_sub(theta, EVS_2PI_FX); + } + WHILE(LT_32(theta , -EVS_2PI_FX)) + { + theta = L_add(theta, EVS_2PI_FX); + } + c0 = getCosWord16( extract_l(theta)); + IF (EQ_16(c0, ONE_IN_Q14)) + { + c0 = MAX_16; + } + ELSE + { + c0 = shl(c0, 1); + } + s0 = getSinWord16( extract_l(theta)); + FOR ( i = hStereoDft->band_limits[b]; i < hStereoDft->band_limits[b + 1]; i++ ) + { + /*rotate L*/ + tmp = Msub_32_16(Mpy_32_16_1(DFT_L[2 * i], c0), DFT_L[2 * i + 1], s0); + DFT_L[2 * i + 1] = Madd_32_16(Mpy_32_16_1(DFT_L[2 * i], s0), DFT_L[2 * i + 1], c0); + move32(); + DFT_L[2 * i] = tmp; + move32(); + } + } + } + ELSE IF ( sba_dirac_stereo_flag && hMdDec ) + { + + IF ( EQ_16(nchan_transport , 1) ) + { + IF ( sba_mono_flag ) + { + IF ( EQ_16(b , 0) ) + { + i = 0; + move16(); + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS], pDFT_DMX[2 * i]); + move32(); + DFT_L[2 * i] = DFT_W; + move32(); + DFT_R[2 * i] = 0; + move32(); + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS], pDFT_DMX[2 * i + 1]); + move32(); + DFT_L[2 * i + 1] = DFT_W; + move32(); + DFT_R[2 * i + 1] = 0; + move32(); + } + FOR ( i = hStereoDft->band_limits[b]; i < min( stop, hStereoDft->band_limits[b + 1] ); i++ ) + { + DFT_W = Madd_32_32(Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]), + L_add( hStereoDft->mixer_mat_smooth_fx[0][1][b + k * IVAS_MAX_NUM_BANDS] , + L_add( hStereoDft->mixer_mat_smooth_fx[0][2][b + k * IVAS_MAX_NUM_BANDS] , + hStereoDft->mixer_mat_smooth_fx[0][3][b + k * IVAS_MAX_NUM_BANDS])), + DFT_PRED_RES[2 * i]); + DFT_L[2 * i] = DFT_W; + move32(); + DFT_R[2 * i] = 0; + move32(); + + DFT_W = Madd_32_32(Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]), + L_add( hStereoDft->mixer_mat_smooth_fx[0][1][b + k * IVAS_MAX_NUM_BANDS] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][b + k * IVAS_MAX_NUM_BANDS] , + hStereoDft->mixer_mat_smooth_fx[0][3][b + k * IVAS_MAX_NUM_BANDS])), + DFT_PRED_RES[2 * i + 1]); + DFT_L[2 * i + 1] = DFT_W; + move32(); + DFT_R[2 * i + 1] = 0; + move32(); + } + FOR ( ; i < hStereoDft->band_limits[b + 1]; i++ ) + { + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]); + DFT_L[2 * i] = DFT_W; + move32(); + DFT_R[2 * i] = 0; + move32(); + + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]); + DFT_L[2 * i + 1] = DFT_W; + move32(); + DFT_R[2 * i + 1] = 0; + move32(); + } + } + ELSE + { + IF ( EQ_16(b , 0) ) + { + i = 0; + move16(); + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]); + DFT_Y = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]); + + DFT_L[2 * i] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i] = L_sub(DFT_W , DFT_Y); + move32(); + + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]); + DFT_Y = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]); + + DFT_L[2 * i + 1] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i + 1] = L_sub(DFT_W , DFT_Y); + move32(); + } + FOR ( i = hStereoDft->band_limits[b]; i < min( stop, hStereoDft->band_limits[b + 1] ); i++ ) + { + DFT_W = Madd_32_32(Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]) , + L_add( hStereoDft->mixer_mat_smooth_fx[0][1][b + k * IVAS_MAX_NUM_BANDS] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][b + k * IVAS_MAX_NUM_BANDS] , + hStereoDft->mixer_mat_smooth_fx[0][3][b + k * IVAS_MAX_NUM_BANDS])), + DFT_PRED_RES[2 * i]); + DFT_Y = Madd_32_32(Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]) , + L_add( hStereoDft->mixer_mat_smooth_fx[1][1][b + k * IVAS_MAX_NUM_BANDS] , + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][b + k * IVAS_MAX_NUM_BANDS] , + hStereoDft->mixer_mat_smooth_fx[1][3][b + k * IVAS_MAX_NUM_BANDS])), + DFT_PRED_RES[2 * i]); + + DFT_L[2 * i] = L_add(DFT_W, DFT_Y); + move32(); + DFT_R[2 * i] = L_sub(DFT_W, DFT_Y); + move32(); + + DFT_W = Madd_32_32(Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]) , + L_add( hStereoDft->mixer_mat_smooth_fx[0][1][b + k * IVAS_MAX_NUM_BANDS] , + L_add(hStereoDft->mixer_mat_smooth_fx[0][2][b + k * IVAS_MAX_NUM_BANDS] , + hStereoDft->mixer_mat_smooth_fx[0][3][b + k * IVAS_MAX_NUM_BANDS])), + DFT_PRED_RES[2 * i + 1]); + DFT_Y = Madd_32_32(Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]) , + L_add( hStereoDft->mixer_mat_smooth_fx[1][1][b + k * IVAS_MAX_NUM_BANDS] , + L_add(hStereoDft->mixer_mat_smooth_fx[1][2][b + k * IVAS_MAX_NUM_BANDS] , + hStereoDft->mixer_mat_smooth_fx[1][3][b + k * IVAS_MAX_NUM_BANDS])), + DFT_PRED_RES[2 * i + 1]); + + DFT_L[2 * i + 1] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i + 1] = L_sub(DFT_W , DFT_Y); + move32(); + } + FOR ( ; i < hStereoDft->band_limits[b + 1]; i++ ) + { + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]); + DFT_Y = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]); + + DFT_L[2 * i] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i] = L_sub(DFT_W , DFT_Y); + move32(); + + DFT_W = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[0][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]); + DFT_Y = Mpy_32_32(hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]); + + DFT_L[2 * i + 1] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i + 1] = L_sub(DFT_W , DFT_Y); + move32(); + } + } + } + ELSE IF ( GE_16(nchan_transport , 2) ) + { + IF ( EQ_16(b , 0) ) + { + i = 0; + move32(); + + DFT_W = pDFT_DMX[2 * i]; + move32(); + DFT_Y = Madd_32_32(pDFT_DMX1[2 * i], hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]); + + DFT_L[2 * i] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i] = L_sub(DFT_W , DFT_Y); + move32(); + + DFT_W = pDFT_DMX[2 * i + 1]; + move32(); + DFT_Y = Madd_32_32(pDFT_DMX1[2 * i + 1], hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]); + + DFT_L[2 * i + 1] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i + 1] = L_sub(DFT_W , DFT_Y); + move32(); + } + FOR ( i = hStereoDft->band_limits[b]; i < hStereoDft->band_limits[b + 1]; i++ ) + { + DFT_W = pDFT_DMX[2 * i]; + move32(); + DFT_Y = Madd_32_32(pDFT_DMX1[2 * i], hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i]); + + DFT_L[2 * i] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i] = L_sub(DFT_W , DFT_Y); + move32(); + + DFT_W = pDFT_DMX[2 * i + 1]; + move32(); + DFT_Y = Madd_32_32(pDFT_DMX1[2 * i + 1], hStereoDft->mixer_mat_smooth_fx[1][0][b + k * IVAS_MAX_NUM_BANDS] , pDFT_DMX[2 * i + 1]); + + DFT_L[2 * i + 1] = L_add(DFT_W , DFT_Y); + move32(); + DFT_R[2 * i + 1] = L_sub(DFT_W , DFT_Y); + move32(); + } + } + ELSE + { + assert( "nhcan_transport must be 1 or 1!" ); + } + } + ELSE + { + FOR ( i = hStereoDft->band_limits[b]; i < min( stop, hStereoDft->band_limits[b + 1] ); i++ ) + { + tmp = L_add(Madd_32_16(pDFT_RES[2 * i], pDFT_DMX[2 * i], g) , DFT_PRED_RES[2 * i]); + + DFT_L[2 * i] = L_add(pDFT_DMX[2 * i] , tmp); + move32(); + DFT_R[2 * i] = L_sub(pDFT_DMX[2 * i] , tmp); + move32(); + + tmp = L_add(Madd_32_16(pDFT_RES[2 * i + 1], pDFT_DMX[2 * i + 1], g) , DFT_PRED_RES[2 * i + 1]); + + DFT_L[2 * i + 1] = L_add(pDFT_DMX[2 * i + 1] , tmp); + move32(); + DFT_R[2 * i + 1] = L_sub(pDFT_DMX[2 * i + 1] , tmp); + move32(); + + } + + FOR ( ; i < hStereoDft->band_limits[b + 1]; i++ ) + { + tmp = Madd_32_16(pDFT_RES[2 * i], pDFT_DMX[2 * i], g); + + DFT_L[2 * i] = L_add(pDFT_DMX[2 * i] , tmp); + move32(); + DFT_R[2 * i] = L_sub(pDFT_DMX[2 * i] , tmp); + move32(); + + tmp = Madd_32_16(pDFT_RES[2 * i + 1], pDFT_DMX[2 * i + 1], g); + + DFT_L[2 * i + 1] = L_add(pDFT_DMX[2 * i + 1] , tmp); + move32(); + DFT_R[2 * i + 1] = L_sub(pDFT_DMX[2 * i + 1] , tmp); + move32(); + + } + + /* Active Upmix */ + IF ( NE_32(pgIpd[0] , 0) ) + { + Word32 theta = pgIpd[0]; + WHILE(GT_32(theta , EVS_2PI_FX)) + { + theta = L_sub(theta, EVS_2PI_FX); + } + WHILE(LT_32(theta , -EVS_2PI_FX)) + { + theta = L_add(theta, EVS_2PI_FX); + } + c0 = getCosWord16( extract_l(theta) ); + IF (EQ_16(c0, ONE_IN_Q14)) + { + c0 = MAX_16; + } + ELSE + { + c0 = shl(c0, 1); + } + s0 = getSinWord16( extract_l(theta) ); + FOR ( i = hStereoDft->band_limits[b]; i < hStereoDft->band_limits[b + 1]; i++ ) + { + /*rotate L*/ + tmp = Msub_32_16(Mpy_32_16_1(DFT_L[2 * i], c0), DFT_L[2 * i + 1], s0); + DFT_L[2 * i + 1] = Madd_32_16(Mpy_32_16_1(DFT_L[2 * i], s0), DFT_L[2 * i + 1], c0); + move32(); + DFT_L[2 * i] = tmp; + move32(); + } + } + } + } + + IF ( hStereoDft->frame_sid_nodata || EQ_16(st0->VAD , 0) ) + { + hFdCngDec->cna_band_limits[hFdCngDec->cna_nbands] = hStereoDft->band_limits[hFdCngDec->cna_nbands]; + move16(); + } + + IF ( hStereoDft->frame_sid_nodata && !sba_dirac_stereo_flag ) + { + hStereoCng->first_SID = 0; + move16(); + hStereoCng->first_SID_after_TD = 0; + move16(); + } + + FOR ( i = hStereoDft->band_limits[b]; i < shr(hStereoDft->NFFT , 1); i++ ) + { + DFT_L[2 * i] = 0; + move32(); + DFT_L[2 * i + 1] = 0; + move32(); + DFT_R[2 * i] = 0; + move32(); + DFT_R[2 * i + 1] = 0; + move32(); + } + + /*Nyquist Freq.*/ + IF ( EQ_16(hStereoDft->band_limits[b] , shr(hStereoDft->NFFT , 1 ))) + { + DFT_L[1] = L_add(pDFT_DMX[1] , Mpy_32_16_1(pDFT_DMX[1], g)); + move32(); + DFT_R[1] = L_sub(pDFT_DMX[1] , Mpy_32_16_1(pDFT_DMX[1], g)); + move32(); + DFT_L[1] = Mpy_32_16_1(DFT_L[1], INV_SQRT_2_FX); + move32(); + DFT_R[1] = Mpy_32_16_1(DFT_R[1], INV_SQRT_2_FX); + move32(); + } + ELSE + { + DFT_L[1] = 0; + move32(); + DFT_R[1] = 0; + move32(); + } + } + ELSE + { + pPredGain = NULL; /* to avoid compilation warnings */ + pSideGain = NULL; + + /* Dummy upmix-> mono binauralization */ + FOR ( i = 0; i < hStereoDft->NFFT; i++ ) + { + DFT_L[i] = L_add( pDFT_DMX[i] , pDFT_RES[i] ); + move32(); + DFT_R[i] = L_sub( pDFT_DMX[i] , pDFT_RES[i] ); + move32(); + } + } + + /* Comfort Noise Addition */ + IF ( st0->flag_cna ) + { + ptr_per = &hFdCngDec->smoothed_psd_fx[hFdCngCom->startBand]; + + scale_fact0 = 0; + move16(); + IF ( GT_16(hFdCngDec->cna_rescale_fact_fx , 0) ) + { + Word16 q_scale_fact0 = 0; + Word16 op = Sqrt16( shr(hFdCngDec->cna_rescale_fact_fx, 1), &q_scale_fact0); + move16(); + scale_fact0 = L_mult0(shr(output_frame , 1) , op); + IF (GT_16(q_scale_fact0, 0)) + { + assert(0); + } + ELSE + { + scale_fact0 = L_shl(scale_fact0, q_scale_fact0); + } + } + + FOR ( b = 0; b < hFdCngDec->cna_nbands; b++ ) + { + /* calculate gamma factor reflecting inter-channel correlation and side gain (ILD) */ + coh = hFdCngDec->cna_cm_fx[b]; + move16(); + g = hFdCngDec->cna_g_state_fx[b]; + move16(); + IF ( LT_16(coh , (Word16)(0x7333)) ) + { + Word32 op1, op2, l_gamma; + Word16 q_loc1, q_loc2, q_gamma; + gamma = coh; + move16(); + gamma = BASOP_Util_Divide3232_Scale(gamma , sub( (Word16)0x7FFF, gamma), &q_gamma); + IF (EQ_16(gamma, 0)) + { + q_gamma = 0; + } + l_gamma = L_deposit_l(gamma); + op1 = L_add(l_gamma, L_shr(L_deposit_l(sub(MAX_16 , mult(g, g))), q_gamma)); + q_loc2 = Q16 + q_gamma; + q_loc1 = q_loc2; + op1 = Sqrt32(op1, &q_loc1); + op2 = Sqrt32(l_gamma, &q_loc2); + IF (NE_32(op2, 0)) + { + IF (NE_16(q_loc1, q_loc2)) + { + op2 = L_shl(op2, sub(q_loc2, q_loc1)); + q_loc2 = q_loc1; + } + gamma = extract_h(L_sub( op1, op2)); + gamma = shl(gamma, q_loc2); + } + ELSE + { + gamma = extract_h(L_shl(op1, q_loc1)); + } + } + ELSE + { + gamma = 0; + } + + FOR ( i = s_max( hFdCngDec->cna_band_limits[b], shr(hFdCngCom->startBand , 2) ); i < s_min( hFdCngDec->cna_band_limits[b + 1], (L_FRAME16k) >> 1 ); i++ ) + { + Word32 l_tmp; + lev1 = *ptr_per++; + move32(); + lev2 = *ptr_per++; + move32(); + + IF ( GT_32(lev1 , 0) && GT_32(lev2 , 0) && GT_32( Mpy_32_16_1(L_max( lev1, lev2 ), (Word16)0x6AAB) , L_min( lev1, lev2 ))) + { + /* take the minimum of two adjacent frequency bins */ + cna_level = L_min( lev1, lev2 ); + } + ELSE + { + /* take the average of two adjacent frequency bins */ + cna_level = L_add(L_shr( lev1, 1) , L_shr(lev2 , 1)); + } + q_cna_level = sub(Q31 , hFdCngDec->q_smoothed_psd); + move16(); + l_tmp = Sqrt32( cna_level, &q_cna_level); + scale_fact = Mpy_32_32(l_tmp, scale_fact0); + /* + scale_fact0 will be in Q15 by the time the above operation is performed + so the q of scale_fact represented now by q_cna_level has to be updated + */ + q_cna_level = sub(Q31, add(q_cna_level, Q16)); + + /* generate comfort noise from gaussian noise and add to the decoded DFT spectrum */ + N1 = L_shl(Mpy_32_16_1(scale_fact , rand_gauss_fix( &ftmp, cna_seed )), Q2); + N2 = L_shl(Mpy_32_16_1(scale_fact , rand_gauss_fix( &ftmp, cna_seed )), Q2); + l_tmp = L_add(Madd_32_16(N1, N1, g) , Mpy_32_16_1(N2, gamma)); + l_tmp = L_shr(l_tmp, sub(q_cna_level, hStereoDft->q_dft)); + DFT_L[2 * i] = L_add(DFT_L[2 * i], l_tmp); + move32(); + l_tmp = L_sub(Msub_32_16(N1, N1, g) , Mpy_32_16_1(N2, gamma)); + l_tmp = L_shr(l_tmp, sub(q_cna_level, hStereoDft->q_dft)); + DFT_R[2 * i] = L_add(DFT_R[2 * i], l_tmp); + move32(); + + N1 = L_shl(Mpy_32_16_1(scale_fact , rand_gauss_fix( &ftmp, cna_seed )), Q2); + N2 = L_shl(Mpy_32_16_1(scale_fact , rand_gauss_fix( &ftmp, cna_seed )), Q2); + l_tmp = L_add(Madd_32_16(N1, N1, g) , Mpy_32_16_1(N2, gamma)); + l_tmp = L_shr(l_tmp, sub(q_cna_level, hStereoDft->q_dft)); + DFT_L[2 * i + 1] = L_add(DFT_L[2 * i + 1] , l_tmp); + move32(); + l_tmp = L_sub(Msub_32_16(N1, N1, g) , Mpy_32_16_1(N2, gamma)); + l_tmp = L_shr(l_tmp, sub(q_cna_level, hStereoDft->q_dft)); + DFT_R[2 * i + 1] = L_add(DFT_R[2 * i + 1] , l_tmp); + move32(); + } + } + + /* update CNA re-scaling factor */ + hFdCngDec->cna_rescale_fact_fx = extract_l(L_shr(L_mult0((Word16)0x6666, hFdCngDec->cna_act_fact_fx), Q15)); + IF ( !hFdCngDec->first_cna_noise_updated ) + { + hFdCngDec->cna_rescale_fact_fx = 0; + move16(); + } + } + + /* Update memories */ + hStereoDft->past_DMX_pos = ( hStereoDft->past_DMX_pos + 1 ) & (STEREO_DFT_PAST_MAX - 1); + Copy32( pDFT_DMX, hStereoDft->DFT_past_DMX_fx[hStereoDft->past_DMX_pos], s_min( hStereoDft->NFFT, STEREO_DFT32MS_N_32k ) ); + hStereoDft->q_past_dft = hStereoDft->q_dft; + IF ( pPredGain ) + { + stereo_dft_adapt_sf_delay_fx( hStereoDft, pPredGain ); + } + + Copy32( DFT_L, DFT[0] + k * STEREO_DFT32MS_N_MAX, hStereoDft->NFFT ); + Copy32( DFT_R, DFT[1] + k * STEREO_DFT32MS_N_MAX, hStereoDft->NFFT ); + } + + IF ( st0->bfi && !prev_bfi ) + { + Word16 q_shift = shl(sub(hStereoDft->q_dft, hStereoDft->q_past_dft), 1); + idx_k0 = add( hStereoDft->past_DMX_pos , STEREO_DFT_PAST_MAX - 1 ) & (STEREO_DFT_PAST_MAX - 1); + idx_k1 = add( idx_k0 , 1 ) & (STEREO_DFT_PAST_MAX - 1); + /*dmx energy memory*/ + hStereoDft->past_dmx_nrg_fx = stereo_dft_dmx_swb_nrg_fx( hStereoDft->DFT_past_DMX_fx[idx_k0], hStereoDft->DFT_past_DMX_fx[idx_k1], s_min( hStereoDft->NFFT, STEREO_DFT32MS_N_32k ) ); + hStereoDft->past_dmx_nrg_fx = L_shr(hStereoDft->past_dmx_nrg_fx, q_shift); + } + + stereo_dft_compute_td_stefi_params_fx( hStereoDft, samp_ratio ); + + return; +} + +/*------------------------------------------------------------------------- + * stereo_dft_compute_td_stefi_params_fx() + * + * + *-------------------------------------------------------------------------*/ + +static void stereo_dft_compute_td_stefi_params_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word16 samp_ratio /* i : sampling ratio */ +) +{ + Word16 pdmx_ind; + Word32 g2; + Word16 bin0; + Word16 band0; + Word16 b; + Word16 nbands; + Word16 bres; + Word32 wsum; + Word32 pred_gain_avg, pred_g; + Word16 shift_g; + Word16 q_pred_g, q_pred_gain_avg; + Word32 nrg_DMX, nrg_pred_DMX; + Word32 op1; + Word16 q_div, q_sqrt; + + pdmx_ind = hStereoDft->past_DMX_pos; + move16(); + bres = hStereoDft->band_res[1]; + move16(); + + IF ( NE_16(hStereoDft->core_hist[1], ACELP_CORE) || hStereoDft->wasTransient ) + { + hStereoDft->td_gain_fx[0] = 0; + move32(); + hStereoDft->q_td_gain[0] = 0; + move16(); + return; + } + + bin0 = extract_l( L_shr_r(Mpy_32_16_1((Word32)hStereoDft->NFFT, samp_ratio), 1) ); + bin0 = shl(bin0, Q3); + bin0 = s_min( bin0, hStereoDft->band_limits[hStereoDft->nbands] ); + b = hStereoDft->nbands; + move16(); + WHILE ( GT_16(hStereoDft->band_limits[b], bin0) ) + { + b--; + } + band0 = b; + + /* calculate averages over high bands */ + pred_g = pred_gain_avg = 0; + move32(); move32(); + nbands = 0; + move16(); + wsum = 0; + move32(); + shift_g = Q15 - norm_s(sub(hStereoDft->nbands, band0)); + FOR ( b = band0; b < hStereoDft->nbands; b++ ) + { + IF ( LT_32(L_min( hStereoDft->past_res_pred_gain_fx[STEFI_DELAY_IND( STEREO_DFT_TD_STEFI_SUBFR_DELAY + 1, pdmx_ind )][b], hStereoDft->past_res_pred_gain_fx[STEFI_DELAY_IND( STEREO_DFT_TD_STEFI_SUBFR_DELAY + 2, pdmx_ind )][b] ), 0) ) + { + hStereoDft->td_gain_fx[0] = 0; + move32(); + hStereoDft->q_td_gain[0] = 0; + move16(); + return; + } + pred_g = L_add(pred_g, L_shr(Mpy_32_16_1(L_add( L_shr(hStereoDft->res_pred_gain_fx[b + STEREO_DFT_BAND_MAX], 1) , + L_shr(hStereoDft->res_pred_gain_fx[b + 2 * STEREO_DFT_BAND_MAX], 1) ), + dft_res_pred_weights_fx[bres][b - band0]), shift_g)); + pred_gain_avg = L_add(pred_gain_avg, L_shr(Mpy_32_16_1( L_add(L_shr(hStereoDft->past_res_pred_gain_fx[STEFI_DELAY_IND( STEREO_DFT_TD_STEFI_SUBFR_DELAY + 2, pdmx_ind )][b] , 1), + L_shr(hStereoDft->past_res_pred_gain_fx[STEFI_DELAY_IND( STEREO_DFT_TD_STEFI_SUBFR_DELAY + 1, pdmx_ind )][b] , 1 )), + dft_res_pred_weights_fx[bres][b - band0]), shift_g)); + + nbands++; + wsum = L_add(wsum, dft_res_pred_weights_fx[bres][b - band0]); +#ifdef DBG_TD_STEFI + printf( "frame: %d\tband: %-2d\tpred_gain1: %f\tpred_gain2: %f\tppg1: %f\tppg2: %f\n", frame, b, hStereoDft->res_pred_gain[b + STEREO_DFT_BAND_MAX], hStereoDft->res_pred_gain[b + 2 * STEREO_DFT_BAND_MAX], hStereoDft->past_res_pred_gain[STEREO_DFT_TD_STEFI_SUBFR_DELAY - 2][b], hStereoDft->past_res_pred_gain[d_short - 1][b] ); +#endif + } + + IF ( EQ_16(nbands, 0) ) + { + /* apparently, there is nothing to do here */ + hStereoDft->td_gain_fx[0] = 0; + move32(); + hStereoDft->q_td_gain[0] = 0; + move16(); + return; + } + wsum = L_shl(wsum, sub(Q16 , shift_g)); + pred_g = BASOP_Util_Divide3232_Scale(pred_g, wsum, &q_div); + IF (GT_16(q_div, 16)) + { + pred_g = L_shl(pred_g, 16); + q_pred_g = sub(q_div , 16); + } + ELSE + { + pred_g = L_shl(pred_g, q_div); + q_pred_g = 0; + } + pred_gain_avg = BASOP_Util_Divide3232_Scale(pred_gain_avg, wsum, &q_div); + IF (GT_16(q_div, 16)) + { + pred_gain_avg = L_shl(pred_gain_avg, 16); + q_pred_gain_avg = sub(q_div , 16); + } + ELSE + { + pred_gain_avg = L_shl(pred_gain_avg, q_div); + q_pred_gain_avg = 0; + } + nrg_DMX = hStereoDft->hb_nrg_fx[0]; + nrg_pred_DMX = hStereoDft->hb_nrg_fx[1]; + + op1 = BASOP_Util_Divide3232_Scale(L_add( EPSILON_FIX , nrg_DMX ) , L_add( EPSILON_FIX , nrg_pred_DMX ), &q_div); + q_sqrt = Q16 + q_div; + op1 = Sqrt32(op1, &q_sqrt); + g2 = Mpy_32_32(pred_g , op1); + IF (LT_16(q_sqrt, 0)) + { + g2 = L_shl(g2, q_sqrt); + q_sqrt = 0; + } + ELSE IF ( NE_16(q_sqrt, 0)) + { + IF (LT_32(L_shr(pred_gain_avg, q_sqrt), g2)) + { + g2 = pred_gain_avg; + } + ELSE + { + g2 = L_min( Mpy_32_16_1(L_shr(pred_gain_avg, q_sqrt) , STEREO_DFT_STEFFI_GAIN_AMP_FX), + Madd_32_16(Mpy_32_16_1(L_shr(pred_gain_avg, q_sqrt) , sub( (Word16)0x7FFF , STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )), + g2, STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )); + g2 = L_shl(g2, q_sqrt); + } + } + ELSE + { + g2 = L_min( Mpy_32_16_1(pred_gain_avg , STEREO_DFT_STEFFI_GAIN_AMP_FX), + Madd_32_16(Mpy_32_16_1(pred_gain_avg , sub( (Word16)0x7FFF , STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )), + g2, STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )); + } + + hStereoDft->td_gain_fx[0] = g2; + move32(); + if (q_pred_gain_avg != 0) + hStereoDft->q_td_gain[0] = q_pred_gain_avg; + move16(); + +#ifdef DBG_TD_STEFI + printf( "frame: %d\tpred_gain: %f\tpred_gain_avg: %f\tg2_0: %f\tgain: %f\n", frame, pred_gain, pred_gain_avg, g2, hStereoDft->td_gain[0] ); + printf( "nrg_DMX: %f\tnrd_pred_DMX: %f\tnbands: %d\tbin0: %d\n", nrg_DMX, nrg_pred_DMX, hStereoDft->nbands, bin0 ); + /*printf( "td_gain: %f\n", hStereoDft->td_gain[0] );*/ +#endif + + return; +} + + +/*------------------------------------------------------------------------- + * stereo_dft_generate_res_pred_fx() + * + * + *-------------------------------------------------------------------------*/ +void stereo_dft_generate_res_pred_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: decoder DFT stereo handle */ + const Word16 samp_ratio, /* i : sampling ratio */ + Word32 *pDFT_DMX, /* i : downmix signal */ + Word32 *DFT_PRED_RES, /* o : residual prediction signal */ + Word32 *pPredGain, /* i : residual prediction gains */ + const Word16 k, /* i : subframe index */ + Word32 *ap_filt_DMX, /* i : enhanced stereo filling signal */ + Word16 *stop, /* o : last FD stereo filling bin */ + const Word16 bfi /* i : BFI flag */ +) +{ + /* general variables */ + Word16 i, b; + Word16 begin, end; + Word16 bin0, band0; /* ESF->Stefi crossover bin/band */ + Word16 lb_stefi_start_band; + + /* variables for enhanced stereo filling */ + Word16 norm_fac, q_norm_fac = 0, lim_norm_fac; + Word16 q_sqrt; + Word16 alpha, gain_limit; + + /* variables for stereo filling */ + Word16 d_long, d_short, d_long_ind, d_short_ind; + Word16 g_short, g_long; + Word32 dmx_nrg, rev_nrg; + Word32 past_dmx_nrg; + Word32 pred_gain_avg; + Word32 g2; + Word16 nbands_respred; + + push_wmops( "gen_respred" ); + + /* smoothing and limiting parameters */ + alpha = hStereoDft->wasTransient ? 0 : (Word16)(0x199A); /* no smoothing after transients */ + gain_limit = 0x7FFF; // 2.0 in Q14 + move16(); + + /* residual prediction only used up to 16 kHz (SWB) */ + nbands_respred = s_min( hStereoDft->nbands, STEREO_DFT_RES_PRED_BAND_MAX ); + + /* In ACELP mode the downmix signal is not available in bandwidth extension area. * + * Therefore, the downmix energy in the corresponding subbands is estimated. */ + bin0 = (Word16) (L_shr(L_add(L_mult0(hStereoDft->NFFT, samp_ratio), ONE_IN_Q12), Q12 + 1)); + move16(); + bin0 = s_min( bin0, hStereoDft->band_limits[hStereoDft->nbands] ); + b = hStereoDft->nbands; + move16(); + WHILE ( GE_16(hStereoDft->band_limits[b], bin0) ) + { + b--; + } + band0 = b; + move16(); + + IF ( LT_16(hStereoDft->res_pred_mode[k + STEREO_DFT_OFFSET], STEREO_DFT_RESPRED_ESF) ) + { + /* no ESF signal available, use stereo filling over whole spectrum */ + lb_stefi_start_band = s_max( hStereoDft->res_pred_band_min, hStereoDft->res_cod_band_max ); + } + ELSE + { + /* ESF signal available, use ESF in lowband, stereo filling in highband */ + lb_stefi_start_band = s_max( band0, hStereoDft->res_cod_band_max ); + } + + IF ( bfi ) + { + lb_stefi_start_band = 0; + move16(); + } + + /* lowband: use ESF if available, else use stereo filling */ + IF ( EQ_16(hStereoDft->res_pred_mode[k + STEREO_DFT_OFFSET], STEREO_DFT_RESPRED_ESF) ) + { + /* ESF in lowband */ + /* main loop over core region*/ + FOR ( b = hStereoDft->res_cod_band_max; b <= band0; b++ ) + { + dmx_nrg = EPSILON_FIX; + move32(); + rev_nrg = EPSILON_FIX; + move32(); + + /* calculate band energies (low band only in case of ACELP) */ + FOR ( i = hStereoDft->band_limits[b]; i < s_min( hStereoDft->band_limits[b + 1], bin0 ); i++ ) + { + dmx_nrg = L_add(dmx_nrg, + Madd_32_32(Mpy_32_32(pDFT_DMX[2 * i], pDFT_DMX[2 * i]), + pDFT_DMX[2 * i + 1], pDFT_DMX[2 * i + 1])); + rev_nrg = L_add(rev_nrg, + Madd_32_32(Mpy_32_32(ap_filt_DMX[2 * i], ap_filt_DMX[2 * i]), + ap_filt_DMX[2 * i + 1], ap_filt_DMX[2 * i + 1])); + } + IF (LT_16(hStereoDft->q_smoothed_nrg , hStereoDft->q_dft)) + { + rev_nrg = L_shr(rev_nrg, shl(sub(hStereoDft->q_dft, hStereoDft->q_smoothed_nrg), 1)); + dmx_nrg = L_shr(dmx_nrg, shl(sub(hStereoDft->q_dft, hStereoDft->q_smoothed_nrg), 1)); + } + ELSE IF (GT_16(hStereoDft->q_smoothed_nrg , hStereoDft->q_dft)) + { + hStereoDft->smooth_res_nrg_fx[b] = L_shr(hStereoDft->smooth_res_nrg_fx[b], shl(sub(hStereoDft->q_smoothed_nrg, hStereoDft->q_dft), 1)); + hStereoDft->smooth_dmx_nrg_fx[b] = L_shr(hStereoDft->smooth_dmx_nrg_fx[b], shl(sub(hStereoDft->q_smoothed_nrg, hStereoDft->q_dft), 1)); + } + /* smoothing */ + hStereoDft->smooth_res_nrg_fx[b] = Madd_32_16(Mpy_32_16_1(hStereoDft->smooth_res_nrg_fx[b], alpha), rev_nrg, sub( (Word16)(0x7FFF), alpha )) ; + move32(); + hStereoDft->smooth_dmx_nrg_fx[b] = Madd_32_16(Mpy_32_16_1(hStereoDft->smooth_dmx_nrg_fx[b], alpha), dmx_nrg, sub( (Word16)(0x7FFF), alpha )) ; + move32(); + + /* normalization factor */ + IF (NE_32(hStereoDft->smooth_res_nrg_fx[b], 0)) + { + norm_fac = BASOP_Util_Divide3232_Scale(hStereoDft->smooth_dmx_nrg_fx[b], hStereoDft->smooth_res_nrg_fx[b], &q_norm_fac); + norm_fac = Sqrt16(norm_fac, &q_norm_fac); + IF (NE_16(norm_fac, 0)) + { + /* gain compressor */ + IF (LE_16(q_norm_fac, -Q1) || (EQ_16(q_norm_fac, Q1) && GT_16((Word16)0x3333, norm_fac)) || (EQ_16(q_norm_fac, 0) && GT_16((Word16)0x6666, norm_fac))) + { + lim_norm_fac = (Word16)0x5000; + } + ELSE IF (GT_16(q_norm_fac, Q1) || (EQ_16(q_norm_fac, Q1) && LT_16((Word16)0x5000, norm_fac)) || (EQ_16(q_norm_fac, 0) && GT_16((Word16)0x6666, norm_fac))) + { + lim_norm_fac = (Word16)0x3333; + } + ELSE + { + lim_norm_fac = norm_fac; + } + IF (EQ_16(lim_norm_fac, norm_fac)) + { + norm_fac = ONE_IN_Q14; + q_norm_fac = Q1; + } + ELSE + { + norm_fac = extract_l(L_shr(L_mult0(norm_fac, lim_norm_fac), Q15)); + q_norm_fac = add(q_norm_fac, 1); + IF (LT_16(q_norm_fac, 0 )) + { + norm_fac = shl(norm_fac, q_norm_fac); + q_norm_fac = 0; + } + ELSE IF (GT_16(q_norm_fac, 2) && LT_16(norm_s(norm_fac) , sub(q_norm_fac, Q1))) + { + norm_fac = MAX_16; + q_norm_fac = Q1; + } + } + } + } + ELSE + { + norm_fac = MAX_16; + q_norm_fac = Q1; + } + + FOR ( i = hStereoDft->band_limits[b]; i < s_min( hStereoDft->band_limits[b + 1], bin0 ); i++ ) + { + DFT_PRED_RES[2 * i] = L_shl(Mpy_32_32(Mpy_32_16_1(pPredGain[b], norm_fac), ap_filt_DMX[2 * i]), q_norm_fac); + move32(); + DFT_PRED_RES[2 * i + 1] = L_shl(Mpy_32_32(Mpy_32_16_1(pPredGain[b], norm_fac), ap_filt_DMX[2 * i + 1]), q_norm_fac); + move32(); + } + } + IF (GT_16(hStereoDft->q_smoothed_nrg , hStereoDft->q_dft)) + { + hStereoDft->q_smoothed_nrg = hStereoDft->q_dft; + } + } + ELSE IF ( EQ_16(hStereoDft->res_pred_mode[k + STEREO_DFT_OFFSET], STEREO_DFT_RESPRED_STEFI) ) + { + /* stefi in lowband */ + set_l( DFT_PRED_RES, 0, 2 * hStereoDft->band_limits[lb_stefi_start_band] ); + + FOR ( b = lb_stefi_start_band; b <= band0; b++ ) + { + d_short_ind = add(sub(STEREO_DFT_PAST_MAX, STEREO_DFT_STEFFI_DELAY_SHORT), b & 1); + /* ToDo:Change the float operation here */ + d_long_ind = max( 4, (int16_t) ( ( STEREO_DFT_PAST_MAX + 4 - 1 ) * ( (float) b / ( hStereoDft->nbands - 1 ) ) + 0.5f ) ) - 4; + move16(); + /* make sure d_short really corresponds to a shorter or equally long delay than d_long (e.g. not always the case for + * STEREO_DFT_STEFFI_DELAY_SHORT=3 and STEREO_DFT_STEFFI_DELAY_LONG=4)*/ + d_short_ind = max( d_short_ind, d_long_ind ); + move16(); + + /* Even number of window sliding (assymmetric OLA) */ + d_short_ind = shl( shr(d_short_ind, 1), 1 ); + d_long_ind = shl(shr( d_long_ind, 1), 1 ); + + d_short = sub(STEREO_DFT_PAST_MAX, d_short_ind); + d_long = sub(STEREO_DFT_PAST_MAX, d_long_ind); + + d_short_ind = add(add(d_short_ind, hStereoDft->past_DMX_pos), 1 ) % STEREO_DFT_PAST_MAX; + d_long_ind = add(add(d_long_ind, hStereoDft->past_DMX_pos), 1) % STEREO_DFT_PAST_MAX; + + g_short = hStereoDft->stefi_short_gain_fx; + move16(); + g_long = hStereoDft->stefi_long_gain_fx; + move16(); + + /* change mixing ratio if long and short delay are the same */ + IF ( EQ_16(d_short, d_long) ) + { + g_short = MAX_16; + move16(); + g_long = 0; + move16(); + } + + /* Avoid transient components */ + IF ( EQ_32(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], EVS_LW_MIN) && EQ_32(hStereoDft->past_res_pred_gain_fx[d_long_ind][b], EVS_LW_MIN) ) + { + g_long = 0; + move16(); + g_short = 0; + move16(); + } + ELSE IF ( EQ_32(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], EVS_LW_MIN) ) + { + g_long = MAX_16; + move16(); + g_short = 0; + move16(); + } + ELSE IF ( EQ_32(hStereoDft->past_res_pred_gain_fx[d_long_ind][b], EVS_LW_MIN) ) + { + g_long = 0; + move16(); + g_short = MAX_16; + move16(); + } + + IF ( GT_16(s_max( g_short, g_long ), 0) ) + { + Word16 q_shift = sub(hStereoDft->q_dft, hStereoDft->q_past_dft); + past_dmx_nrg = EPSILON_FIX; + move32(); + dmx_nrg = EPSILON_FIX; + move32(); + FOR ( i = hStereoDft->band_limits[b]; i < min( bin0, hStereoDft->band_limits[b + 1] ); i++ ) + { + dmx_nrg = Madd_32_32(Madd_32_32(dmx_nrg, pDFT_DMX[2 * i], pDFT_DMX[2 * i]), pDFT_DMX[2 * i + 1], pDFT_DMX[2 * i + 1]); + + DFT_PRED_RES[2 * i] = L_shr(Madd_32_16(Mpy_32_16_1(hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i] , g_short), hStereoDft->DFT_past_DMX_fx[d_long_ind][2 * i], g_long ), q_shift); + move32(); + DFT_PRED_RES[2 * i + 1] = L_shr(Madd_32_16(Mpy_32_16_1(hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i + 1] , g_short), hStereoDft->DFT_past_DMX_fx[d_long_ind][2 * i + 1], g_long ), q_shift); + move32(); + past_dmx_nrg = Madd_32_32(Madd_32_32(past_dmx_nrg, DFT_PRED_RES[2 * i], DFT_PRED_RES[2 * i]), DFT_PRED_RES[2 * i + 1], DFT_PRED_RES[2 * i + 1]); + } + IF (GT_16(hStereoDft->q_dft, hStereoDft->q_past_dft)) + { + past_dmx_nrg = L_shl(past_dmx_nrg, shl(sub(hStereoDft->q_dft , hStereoDft->q_past_dft), 1)); + } + ELSE + { + dmx_nrg = L_shl(dmx_nrg, shl(sub(hStereoDft->q_past_dft , hStereoDft->q_dft), 1)); + } + IF ( !bfi || GE_16(b, hStereoDft->res_cod_band_max) ) + { + Word16 q_div; + Word16 op; + op = BASOP_Util_Divide3232_Scale(( 1 + dmx_nrg ), ( 1 + past_dmx_nrg ), &q_div); + q_sqrt = q_div; + norm_fac = Sqrt16( op, &q_sqrt); + g2 = Mpy_32_16_1(pPredGain[b], norm_fac); + IF (LE_32(q_sqrt, norm_l(g2))) + { + g2 = L_shl(g2, q_sqrt); + pred_gain_avg = Madd_32_16(Mpy_32_16_1(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], g_short), + hStereoDft->past_res_pred_gain_fx[d_long_ind][b], g_long); + + g2 = min( Mpy_32_16_1(pred_gain_avg, STEREO_DFT_STEFFI_GAIN_AMP_FX), + Madd_32_16(Mpy_32_16_1(pred_gain_avg, sub( MAX_16, STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )), + g2, STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )); + } + ELSE + { + /* Multiplication with STEREO_DFT_STEFFI_GAIN_AMP_FX is avodided since the float value of + this constant is 1.0f */ + g2 = Madd_32_16(Mpy_32_16_1(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], g_short), + hStereoDft->past_res_pred_gain_fx[d_long_ind][b], g_long); + } + + FOR ( i = hStereoDft->band_limits[b]; i < min( bin0, hStereoDft->band_limits[b + 1] ); i++ ) + { + DFT_PRED_RES[2 * i] = Mpy_32_32(g2, DFT_PRED_RES[2 * i]); + move32(); + DFT_PRED_RES[2 * i + 1] = Mpy_32_32(g2, DFT_PRED_RES[2 * i + 1]); + move32(); + } + } + } + ELSE + { + set32_fx( DFT_PRED_RES + shl(hStereoDft->band_limits[b], 1), 0, shl( sub(min( bin0, hStereoDft->band_limits[b + 1] ), hStereoDft->band_limits[b]), 1) ); + } + } + } + + IF ( GT_16(hStereoDft->band_limits[nbands_respred], bin0) ) + { + /* apply stereo filling in ACELP BWE region */ + IF ( EQ_16(hStereoDft->core_hist[0], ACELP_CORE) && EQ_16(hStereoDft->core_hist[STEREO_DFT_STEFFI_DELAY_SHORT / 2], ACELP_CORE) ) + { + /* ACELP -> ACELP: nothing to do */ + *stop = bin0; + move16(); + } + ELSE IF ( EQ_16(hStereoDft->core_hist[STEREO_DFT_STEFFI_DELAY_SHORT / 2], ACELP_CORE) ) + { + /* ACELP -> TCX/HQ core transition */ + /* calculate high band energy only */ + dmx_nrg = EPSILON_FIX; + move32(); + FOR ( i = bin0; i < shr(hStereoDft->NFFT, 1); i++ ) + { + dmx_nrg = L_add(dmx_nrg, Madd_32_32(Mpy_32_32(pDFT_DMX[2 * i], pDFT_DMX[2 * i]), pDFT_DMX[2 * i + 1], pDFT_DMX[2 * i + 1])); + } + + hStereoDft->hb_nrg_fx[0] = Mpy_32_32(dmx_nrg , L_shr(hStereoDft->NFFT, 1)); + *stop = bin0; + move16(); + } + ELSE IF ( EQ_16(hStereoDft->core_hist[0], ACELP_CORE) ) + { + /* TCX/HQ core -> ACELP transition */ + /* apply short delay only and blend to long/short gain */ + dmx_nrg = hStereoDft->hb_nrg_subr_fx[k]; + d_short_ind = STEREO_DFT_PAST_MAX - STEREO_DFT_TD_STEFI_SUBFR_DELAY; + + d_short_ind = add( d_short_ind , add(hStereoDft->past_DMX_pos , 1) ) & (STEREO_DFT_PAST_MAX - 1); + + /* calculate high band energy of past dmx */ + past_dmx_nrg = EPSILON_FIX; + FOR ( i = bin0; i < s_min( shr(hStereoDft->NFFT , 1), STEREO_DFT32MS_N_32k / 2 ); i++ ) + { + past_dmx_nrg = L_add(past_dmx_nrg, Madd_32_32(Mpy_32_32(hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i] , hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i]) , hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i + 1] , hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i + 1])); + } + + FOR ( b = band0; b < nbands_respred; b++ ) + { + g_short = LT_32(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], 0) ? 0 : add( ONE_IN_Q14, shr(hStereoDft->stefi_short_gain_fx, 1)); + + IF ( GT_16(g_short , 0) ) + { + Word16 q_nrom_fac, q_divide, q_shift; + Word32 op = BASOP_Util_Divide3232_Scale( (EPSILON_FIX + dmx_nrg ) , ( EPSILON_FIX + past_dmx_nrg ) , &q_divide); + q_norm_fac = Q16 + q_divide + hStereoDft->q_hb_nrg_subr; + op = Sqrt32( op, &q_nrom_fac); + g2 = Mpy_32_32(pPredGain[b], op); + pred_gain_avg = Mpy_32_16_1(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], g_short); + IF ( NE_16(q_norm_fac, 0)) + { + IF (LT_32(L_shr(pred_gain_avg, q_norm_fac), g2)) + { + g2 = pred_gain_avg; + } + ELSE + { + g2 = L_min( Mpy_32_16_1(L_shr(pred_gain_avg, q_norm_fac) , STEREO_DFT_STEFFI_GAIN_AMP_FX), + Madd_32_16(Mpy_32_16_1(L_shr(pred_gain_avg, q_norm_fac) , sub( (Word16)0x7FFF , STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )), + g2, STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )); + g2 = L_shl(g2, q_norm_fac); + } + } + ELSE + { + g2 = L_min( Mpy_32_16_1(pred_gain_avg , STEREO_DFT_STEFFI_GAIN_AMP_FX), + Madd_32_16(Mpy_32_16_1(pred_gain_avg , sub( (Word16)0x7FFF , STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )), + g2, STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )); + } + q_shift = sub(hStereoDft->q_dft, hStereoDft->q_past_dft); + move16(); + FOR ( i = max( hStereoDft->band_limits[b], bin0 ); i < min( hStereoDft->band_limits[b + 1], STEREO_DFT32MS_N_32k / 2 ); i++ ) + { + DFT_PRED_RES[2 * i] = L_shr(Mpy_32_32(g2 , hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i]), q_shift); + move32(); + DFT_PRED_RES[2 * i + 1] = L_shr(Mpy_32_32(g2 , hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i + 1]), q_shift); + move32(); + } + } + ELSE + { + begin = max( hStereoDft->band_limits[b], bin0 ); + move16(); + end = min( hStereoDft->band_limits[b + 1], STEREO_DFT32MS_N_32k / 2 ); + move16(); + set_l( DFT_PRED_RES + 2 * begin, 0, 2 * ( end - begin ) ); + } + } + } + ELSE + { + FOR ( b = band0; b < nbands_respred; b++ ) + { + /* TCX/HQ core -> TCX/HQ core: business as usual */ + d_short_ind = STEREO_DFT_PAST_MAX - STEREO_DFT_STEFFI_DELAY_SHORT + b & 1; + move16(); + d_long_ind = max( 4, (int16_t) ( ( STEREO_DFT_PAST_MAX + 4 - 1 ) * ( (float) b / ( hStereoDft->nbands - 1 ) ) + 0.5f ) ) - 4; + move16(); + /* make sure d_short really corresponds to a shorter or equally long delay than d_long (e.g. not always the case for + * STEREO_DFT_STEFFI_DELAY_SHORT=3 and STEREO_DFT_STEFFI_DELAY_LONG=4)*/ + d_short_ind = s_max( d_short_ind, d_long_ind ); + + /* Even number of window sliding (assymmetric OLA) */ + d_short_ind = d_short_ind & (Word16)(0xFFFE); + move16(); + d_long_ind = d_long_ind & (Word16)(0xFFFE); + move16(); + + d_short = sub(STEREO_DFT_PAST_MAX , d_short_ind); + move16(); + d_long = sub(STEREO_DFT_PAST_MAX , d_long_ind); + move16(); + + /* Works as long as STEREO_DFT_PAST_MAX is a power of 2*/ + d_short_ind = ( add(d_short_ind, add(hStereoDft->past_DMX_pos, 1)) ) & (STEREO_DFT_PAST_MAX - 1); + move16(); + d_long_ind = ( add(d_long_ind, add(hStereoDft->past_DMX_pos, 1)) ) & (STEREO_DFT_PAST_MAX - 1); + move16(); + + g_short = hStereoDft->stefi_short_gain_fx; + move16(); + g_long = hStereoDft->stefi_long_gain_fx; + move16(); + + /* change mixing ratio if long and short delay are the same */ + IF ( EQ_16(d_short , d_long) ) + { + g_short = MAX_16; + move16(); + g_long = 0; + move16(); + } + + /* Avoid transient components */ + IF ( EQ_32(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], MIN_32) && + EQ_32(hStereoDft->past_res_pred_gain_fx[d_long_ind][b], MIN_32)) + { + g_long = 0; + move16(); + g_short = 0; + move16(); + } + ELSE IF( EQ_32(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], MIN_32) ) + { + g_long = MAX_16; + move16(); + g_short = 0; + move16(); + } + ELSE IF ( EQ_32(hStereoDft->past_res_pred_gain_fx[d_long_ind][b], MIN_32) ) + { + g_long = 0; + move16(); + g_short = MAX_16; + move16(); + } + IF ( EQ_32(hStereoDft->core_hist[d_short / 2], ACELP_CORE) ) + { + g_short = 0; + move16(); + } + IF ( EQ_32(hStereoDft->core_hist[d_long / 2] , ACELP_CORE) ) + { + g_long = 0; + move16(); + } + + IF ( GT_16(s_max( g_short, g_long ) , 0) ) + { + Word16 q_div; + Word32 op1; + Word16 q_shift = sub(hStereoDft->q_dft, hStereoDft->q_past_dft); + past_dmx_nrg = EPSILON_FIX; + move32(); + dmx_nrg = EPSILON_FIX; + move32(); + FOR ( i = max( hStereoDft->band_limits[b], bin0 ); i < min( hStereoDft->band_limits[b + 1], STEREO_DFT32MS_N_32k / 2 ); i++ ) + { + dmx_nrg = L_add(dmx_nrg, Madd_32_32(Mpy_32_32(pDFT_DMX[2 * i] , pDFT_DMX[2 * i]) , pDFT_DMX[2 * i + 1] , pDFT_DMX[2 * i + 1])); + + DFT_PRED_RES[2 * i] = L_shr(Madd_32_16(Mpy_32_16_1(hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i], g_short) , hStereoDft->DFT_past_DMX_fx[d_long_ind][2 * i], g_long ), q_shift); + move32(); + DFT_PRED_RES[2 * i + 1] = L_shr(Madd_32_16(Mpy_32_16_1(hStereoDft->DFT_past_DMX_fx[d_short_ind][2 * i + 1], g_short) , hStereoDft->DFT_past_DMX_fx[d_long_ind][2 * i + 1] , g_long ), q_shift); + move32(); + + past_dmx_nrg = L_add(past_dmx_nrg, Madd_32_32(Mpy_32_32(DFT_PRED_RES[2 * i] , DFT_PRED_RES[2 * i]) , DFT_PRED_RES[2 * i + 1] , DFT_PRED_RES[2 * i + 1])); + } + IF (GT_16(hStereoDft->q_dft, hStereoDft->q_past_dft)) + { + past_dmx_nrg = L_shl(past_dmx_nrg, shl(sub(hStereoDft->q_dft , hStereoDft->q_past_dft), 1)); + } + ELSE + { + dmx_nrg = L_shl(dmx_nrg, shl(sub(hStereoDft->q_past_dft , hStereoDft->q_dft), 1)); + } + op1 = L_deposit_h(BASOP_Util_Divide3232_Scale( (EPSILON_FIX + dmx_nrg ) , ( EPSILON_FIX + past_dmx_nrg ), &q_div)); + q_norm_fac = q_div; + op1 = Sqrt32( op1, &q_norm_fac); + IF (GT_16(q_norm_fac , 16)) + { + assert(0); + } + norm_fac = extract_h(op1); + q_norm_fac = sub(q_norm_fac, Q16); + g2 = Mpy_32_16_1(pPredGain[b], norm_fac); + pred_gain_avg = Madd_32_16(Mpy_32_16_1(hStereoDft->past_res_pred_gain_fx[d_short_ind][b], g_short) , hStereoDft->past_res_pred_gain_fx[d_long_ind][b] , g_long); + + g2 = L_min( Mpy_32_16_1(pred_gain_avg , STEREO_DFT_STEFFI_GAIN_AMP_FX), + Madd_32_16(Mpy_32_16_1(pred_gain_avg , sub( (Word16)(0x7FFF) , STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )) , g2 , STEREO_DFT_STEFFI_GAIN_REST_AMT_FX )); + + FOR ( i = max( hStereoDft->band_limits[b], bin0 ); i < min( hStereoDft->band_limits[b + 1], STEREO_DFT32MS_N_32k / 2 ); i++ ) + { + DFT_PRED_RES[2 * i] = Mpy_32_32(g2, DFT_PRED_RES[2 * i]); + move32(); + DFT_PRED_RES[2 * i + 1] = Mpy_32_32(g2, DFT_PRED_RES[2 * i + 1]); + move32(); + } + } + ELSE + { + begin = s_max( hStereoDft->band_limits[b], bin0 ); + end = s_min( hStereoDft->band_limits[b + 1], STEREO_DFT32MS_N_32k / 2 ); + set_l( DFT_PRED_RES + 2 * begin, 0, 2 * ( end - begin ) ); + } + } + } + } + + /* update buffers */ + FOR ( b = hStereoDft->res_pred_band_min; b < hStereoDft->nbands; b++ ) + { + IF ( hStereoDft->attackPresent || hStereoDft->wasTransient ) + { + hStereoDft->past_res_pred_gain_fx[( hStereoDft->past_DMX_pos + 1 ) & (STEREO_DFT_PAST_MAX - 1)][b] = MIN_32; + move32(); + } + ELSE + { + hStereoDft->past_res_pred_gain_fx[( hStereoDft->past_DMX_pos + 1 ) & (STEREO_DFT_PAST_MAX - 1)][b] = pPredGain[b]; + move32(); + } + } + + pop_wmops(); + return; +} + +/*--------------------------------------------------------------- + * stereo_dft_adapt_sf_delay_fx() + * + * + * ---------------------------------------------------------------*/ + +static void stereo_dft_adapt_sf_delay_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, + Word32 *pPredGain ) +{ + Word32 var_mean_ratio; + Word32 new_variation; + Word32 target_delay; + Word32 max_pg, sum_pg; + Word32 alpha_up, alpha_down; + Word16 b; + Word16 q_sqrt; + Word16 q_div; + Word16 q_guard; + Word16 op; + + max_pg = 0; + move32(); + sum_pg = 0; + move32(); + q_sqrt = 0; + move32(); + q_guard = sub(15 , norm_s(hStereoDft->nbands)); + + /* find sum and maximum of prediction gains */ + FOR ( b = hStereoDft->res_pred_band_min; b < hStereoDft->nbands; b++ ) + { + IF ( GT_32(pPredGain[b], max_pg) ) + { + max_pg = pPredGain[b]; + move16(); + } + sum_pg = L_add(sum_pg, L_shr(pPredGain[b], q_guard)); + } + IF (GT_16(q_guard, hStereoDft->q_lt_pred_gain)) + { + hStereoDft->lt_pred_gain_fx = L_shr(hStereoDft->lt_pred_gain_fx, sub(q_guard, hStereoDft->q_lt_pred_gain)); + hStereoDft->q_lt_pred_gain = q_guard; + } + ELSE + { + sum_pg = L_shr(sum_pg, sub(hStereoDft->q_lt_pred_gain, q_guard)); + q_guard = hStereoDft->q_lt_pred_gain; + } + IF ( GT_32(sum_pg, 0) ) + { + /* Calculate mean of the prediction gain */ + hStereoDft->lt_pred_gain_fx = Madd_32_16(Mpy_32_16_1( sum_pg, STEREO_DFT_LT_PREDGAIN_UPD_FX), hStereoDft->lt_pred_gain_fx, sub( MAX_16, STEREO_DFT_LT_PREDGAIN_UPD_FX )); + + /* Calculate the variation of the prediction gain */ + new_variation = L_abs( L_sub(sum_pg , hStereoDft->lt_pred_gain_fx) ); + hStereoDft->lt_pred_gain_variation_fx = Madd_32_16(Mpy_32_16_1(new_variation , STEREO_DFT_VR_PREDGAIN_UPD_FX) , hStereoDft->lt_pred_gain_variation_fx, sub( MAX_16 , STEREO_DFT_VR_PREDGAIN_UPD_FX )); + } + + /* Calculate ratio of variation and mean of prediction gain */ + var_mean_ratio = STEREO_DFT_RES_RATIO_LIMIT_FX; + move16(); + + IF ( GT_32(hStereoDft->lt_pred_gain_fx, 0) ) + { + Word32 opr2 = L_deposit_h(BASOP_Util_Divide3232_Scale(hStereoDft->lt_pred_gain_variation_fx , hStereoDft->lt_pred_gain_fx, &q_div)); + IF ( LT_16(q_div, 0) ) + { + opr2 = L_shl(opr2, q_div); + q_div = 0; + move16(); + } + IF ( LT_32(L_shr(STEREO_DFT_RES_RATIO_LIMIT_FX_3_BY_2, q_div), opr2)) + { + var_mean_ratio = STEREO_DFT_RES_RATIO_LIMIT_FX_3_BY_2; + } + ELSE + { + var_mean_ratio = L_shl(opr2, q_div); + } + } + + IF ( GT_32(max_pg , STEREO_DFT_STEFFI_PG_THRESHOLD_FX) ) + { + /* slow upwards */ + alpha_up = STEREO_DFT_STEFFI_RATIO_UP_HIGH_FX; + move16(); + alpha_down = STEREO_DFT_STEFFI_RATIO_DOWN_HIGH_FX; + move16(); + } + ELSE + { + /* slow downwards */ + alpha_up = STEREO_DFT_STEFFI_RATIO_UP_LOW_FX; + move16(); + alpha_down = STEREO_DFT_STEFFI_RATIO_DOWN_LOW_FX; + move16(); + } + + IF ( GT_16(extract_h(var_mean_ratio) , extract_h(hStereoDft->lt_var_mean_ratio_fx)) ) + { + hStereoDft->lt_var_mean_ratio_fx = Madd_32_32(Mpy_32_32(var_mean_ratio, alpha_up) , hStereoDft->lt_var_mean_ratio_fx, L_sub( MAX_32 , alpha_up )); + } + ELSE + { + hStereoDft->lt_var_mean_ratio_fx = Madd_32_32(Mpy_32_32(var_mean_ratio, alpha_down) , hStereoDft->lt_var_mean_ratio_fx, L_sub( MAX_32 , alpha_down )); + } + + /* Calculate a target delay for the stereo filling. Set the stereo filling delay lower when the prediction gain + variation is relatively high compared to the mean */ + IF ( GE_16(extract_h(hStereoDft->lt_var_mean_ratio_fx) , extract_h(STEREO_DFT_RES_RATIO_LIMIT_FX)) ) + { + target_delay = L_shl(STEREO_DFT_STEFFI_DELAY_SHORT, Q15); + move32(); + } + ELSE + { + target_delay = L_min( L_shl(STEREO_DFT_STEFFI_DELAY_LONG, Q15), + L_add(L_shl(STEREO_DFT_STEFFI_DELAY_SHORT, Q15) , + L_mult0(( STEREO_DFT_STEFFI_DELAY_OFFSET + STEREO_DFT_STEFFI_DELAY_LONG - STEREO_DFT_STEFFI_DELAY_SHORT ) , + sub( MAX_16 , extract_h(L_shl(Mpy_32_16_1(hStereoDft->lt_var_mean_ratio_fx , ONE_STEREO_DFT_RES_RATIO_LIMIT_Q12), Q3))) + ) + ) + ); + } + + /* Adapt the stereo filling delay by interpolating between two delay taps, one at the shortest delay and one at the longest delay */ + hStereoDft->stefi_short_gain_fx = extract_l(L_shr(L_sub(L_shl(STEREO_DFT_STEFFI_DELAY_LONG, Q15), target_delay), 1)); + q_sqrt = 0; + IF (hStereoDft->stefi_short_gain_fx == MIN_16) + { + hStereoDft->stefi_short_gain_fx = MAX_16; + hStereoDft->stefi_long_gain_fx = 0; + } + ELSE + { + op = hStereoDft->stefi_short_gain_fx; + hStereoDft->stefi_long_gain_fx = Sqrt16( sub(MAX_16 , mult(op, op)), &q_sqrt); + IF (NE_16(q_sqrt, 0)) + { + hStereoDft->stefi_long_gain_fx = shl(hStereoDft->stefi_long_gain_fx, q_sqrt); + } + } + + return; +} +#endif \ No newline at end of file diff --git a/lib_dec/ivas_stereo_dft_plc_fx.c b/lib_dec/ivas_stereo_dft_plc_fx.c new file mode 100644 index 0000000000000000000000000000000000000000..dad8245a49c8236361b6e0fd23482d8c7bfa6017 --- /dev/null +++ b/lib_dec/ivas_stereo_dft_plc_fx.c @@ -0,0 +1,995 @@ +/****************************************************************************************************** + + (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 "cnst.h" +#include "prot.h" +#include "prot_fx1.h" +#include "prot_fx2.h" +#include "ivas_cnst.h" +#include "ivas_prot.h" +#include "ivas_prot_fx.h" +#include "math.h" +#include "wmc_auto.h" +#include "basop_util.h" + +/*--------------------------------------------------------------- + * Local constants + * ---------------------------------------------------------------*/ + +#define ZP8k 15 /* zero padding in 8kHz DFT analysis */ +#define OFFSET8k 55 /* offset in 8 kHz */ +#define STEREO_DFT_PLC_STEP21 ( L_FRAME8k - OFFSET8k ) /* Step from subframe 2 in frame n to subframe 1 in frame n+1 */ +#define STEREO_DFT_PLC_PH_C_FX (Word16)( 0x0A8D ) /* Phase estimation constant, for estimating phase of fractional frequency */ + + +#ifdef IVAS_FLOAT_FIXED + +/*--------------------------------------------------------------- + * stereo_dft_res_ecu_fx() + * + * Error concealment of DFT Stereo residual, including memory + * updates of DFT analysis memory and IMDCT OLA + * ---------------------------------------------------------------*/ + +void stereo_dft_res_ecu_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: Decoder DFT stereo handle */ + Word32 *pDFT_RES, /* i/o: residual signal */ + Word32 *const DFT_PRED_RES, /* i/o: residual prediction signal */ + const Word16 k, /* i : Subframe index */ + const Word16 output_frame, /* i : Output frame length */ + const Word16 prev_bfi, /* i : Previous BFI */ + const Word32 dmx_nrg, /* i : Down-mix energy */ + Word16 *num_plocs, /* i/o: Number of peak locations */ + Word16 *plocs, /* i/o: Peak locations (bin) */ + Word32 *plocsi, /* i/o: Peak locations (fractional) */ + Word32 *input_mem /* o : Residual DFT buffer input mem */ +) +{ + Word32 res_buf[L_FRAME8k]; + Word16 i; + Word16 L_res; + Word16 step; + Word16 fac; + Word16 trigo_dec[STEREO_DFT32MS_N_8k / 2 + 1]; + Word16 trigo_step; + Word16 q_fac; + + set_l( pDFT_RES, 0, L_FRAME8k ); + + L_res = hStereoDft->band_limits[hStereoDft->res_cod_band_max]; + move16(); + + stereo_dft_res_subst_spec_fx( hStereoDft, pDFT_RES, DFT_PRED_RES, hStereoDft->time_offs, L_res, L_FRAME8k, k, num_plocs, plocs, plocsi, k == 0 ); + + fac = BASOP_Util_Divide3232_Scale( L_FRAME8k , hStereoDft->NFFT, &q_fac); + IF (GT_16(q_fac, 0)) + { + assert(0); + } + ELSE + { + fac = L_shl(fac, q_fac); + } + + IF ( EQ_16(hStereoDft->core_hist[0] , ACELP_CORE) ) + { + fac = extract_l(L_shr(L_mult0(fac, 0x2000), 15)); + } + + trigo_step = STEREO_DFT_TRIGO_SRATE_8k_STEP * STEREO_DFT_TRIGO_DEC_STEP; + move16(); + FOR ( i = 0; i < STEREO_DFT32MS_N_8k / 4; i++ ) + { + trigo_dec[i] = hStereoDft->dft_trigo_8k_fx[i * trigo_step]; + move16(); + trigo_dec[STEREO_DFT32MS_N_8k / 2 - i] = hStereoDft->dft_trigo_8k_fx[i * trigo_step]; + move16(); + } + trigo_dec[STEREO_DFT32MS_N_8k / 4] = hStereoDft->dft_trigo_8k_fx[STEREO_DFT32MS_N_8k / 4 * trigo_step]; + move16(); + + /* estimation of res_cod_mem (ola part in imdct residual signal) and input_mem (memory for buffer in DFT analysis)*/ + IF ( EQ_16(k , 0) ) + { + Copy32( pDFT_RES, res_buf, L_FRAME8k ); + stereo_dft_res_subst_spec_fx( hStereoDft, res_buf, DFT_PRED_RES, hStereoDft->time_offs + output_frame, L_res, L_FRAME8k, k, num_plocs, plocs, plocsi, FALSE ); + + rfft_fx( res_buf, trigo_dec, L_FRAME8k, +1 ); + + v_multc_fixed_16( res_buf, fac, res_buf, L_FRAME8k ); + Copy32( res_buf + ( OFFSET8k - ZP8k ), &hStereoDft->res_cod_mem_fx[0], STEREO_DFT_OVL_8k ); + + Copy32( res_buf + ZP8k, input_mem, NS2SA( 8000, STEREO_DFT32MS_OVL_NS ) ); /* Store memory for cross-fade to next frame, in case of good frame */ + hStereoDft->q_ip_mem = hStereoDft->q_dft; + } + ELSE + { + Word16 scale_fac = getScaleFactor32(res_buf, L_FRAME8k); + Word16 q_shift = 8 - scale_fac; + //Copy32( pDFT_RES, res_buf, L_FRAME8k ); + v_shr_32(pDFT_RES, res_buf, L_FRAME8k, q_shift); + + rfft_fx( res_buf, trigo_dec, L_FRAME8k, +1 ); + + v_shr_32(res_buf, res_buf, L_FRAME8k, negate(q_shift)); + + v_multc_fixed( res_buf, fac, res_buf, L_FRAME8k ); + + /* Cross-fade memory */ + fac = 0; + move16(); + step = ONE_BY_NS2A_8K_ST_DFT32MS_OVL_NS; + move16(); + FOR ( i = 0; i < NS2SA( 8000, STEREO_DFT32MS_OVL_NS ); i++ ) + { + input_mem[i] = Madd_32_16(Mpy_32_16_1(res_buf[i + L_FRAME8k - NS2SA( 8000, STEREO_DFT32MS_OVL_NS ) - ZP8k], sub( MAX_16 , fac )) , input_mem[i], fac); + move32(); + fac = add(fac, step); + } + + /*in case of burst error*/ + hStereoDft->time_offs = add(hStereoDft->time_offs, L_FRAME8k); + } + + set_l( DFT_PRED_RES, 0, 2 * L_res ); + + IF ( prev_bfi ) + { + stereo_dft_res_ecu_burst_att_fx( hStereoDft, pDFT_RES, dmx_nrg, L_res, L_FRAME8k ); + } + + return; +} + +/*-------------------------------------------------------------------* + * imax_pos() + * + * Get interpolated maximum position + *-------------------------------------------------------------------*/ + +/*! r: interpolated maximum position */ +Word32 imax_pos_fx( + const Word32 *y /* i : Input vector for peak interpolation */ +) +{ + Word32 posi, y1, y2, y3, y3_y1, y2i; + Word32 ftmp_den1, ftmp_den2; + Word16 q_div_2i, q_div_posi; + /* Seek the extrema of the parabola P(x) defined by 3 consecutive points so that P([-1 0 1]) = [y1 y2 y3] */ + y1 = y[0]; + y2 = y[1]; + y3 = y[2]; + y3_y1 = L_sub(y3 , y1); + ftmp_den1 = L_sub( L_add(y1 , y3) , L_shl(y2 , 1)); + ftmp_den2 = L_shl(L_sub( L_sub(L_shl(y2, 1) , y1) , y3), 1); + + IF ( EQ_32(ftmp_den2 , 0) || EQ_32(ftmp_den1 , 0) ) + { + return ( 0 ); /* early exit with left-most value */ + } + + y2i = Mpy_32_16_1(Mpy_32_16_1(y3_y1, BASOP_Util_Divide3232_Scale( y3_y1 , ftmp_den1 , &q_div_2i)), (Word16)(0xF000)); + IF (LT_16(q_div_2i, 0)) + { + y2i = L_shl(y2i, q_div_2i); + q_div_2i = 0; + y2i = L_add(y2i, y2); + } + ELSE + { + y2i = L_add(y2i, L_shr(y2, q_div_2i)); + } + /* their corresponding normalized locations */ + posi = BASOP_Util_Divide3232_Scale(y3_y1 , ( ftmp_den2 ), &q_div_posi); + IF (NE_16(q_div_posi, 0)) + { + posi = L_shl(posi, q_div_posi); + q_div_posi = 0; + } + /* Interpolated maxima if locations are not within [-1,1], calculated extrema are ignored */ + IF ( GE_32(posi, L_shr(ONE_IN_Q15, q_div_posi)) || LE_32(posi , L_shr(MIN_16, q_div_posi)) ) + { + posi = y3 > y1 ? ONE_IN_Q15 : MIN_16; + } + ELSE + { + IF ( GE_32(L_shr(y1, q_div_2i), y2i) ) + { + posi = ( y1 > y3 ) ? MIN_16 : ONE_IN_Q15; + } + ELSE IF ( GE_32(L_shr(y3, q_div_2i) , y2i) ) + { + posi = ONE_IN_Q15; + } + } + + return L_add(posi , ONE_IN_Q15); +} + +static void ivas_peakfinder_fx( + const Word32 *x0, /* i : vector from which the maxima will be found */ + const Word16 len0, /* i : length of input vector */ + Word16 *plocs, /* o : the indicies of the identified peaks in x0 */ + Word16 *cInd, /* o : number of identified peaks */ + const Word32 sel, /* i : The amount above surrounding data for a peak to be identified */ + const Word16 endpoints /* i : Flag to include endpoints in peak search */ +) +{ + Word32 minMag, tempMag, leftMin; + Word32 dx0[L_PROT48k_2], x[L_PROT48k_2 + 1], peakMag[MAX_PLOCS]; + Word16 k, i, len, tempLoc = 0, foundPeak, ii, xInd; + Word16 *ind, indarr[L_PROT48k_2 + 1], peakLoc[MAX_PLOCS]; + + ind = indarr; + + /* Find derivative */ + v_sub_32( x0 + 1, x0, dx0, len0 - 1 ); + + /* This is so we find the first of repeated values */ + FOR ( i = 0; i < len0 - 1; i++ ) + { + IF ( EQ_32(dx0[i] , 0) ) + { + dx0[i] = -EPSILON_FX; + } + } + + /* Find where the derivative changes sign + Include endpoints in potential peaks and valleys */ + k = 0; + + IF ( endpoints ) + { + x[k] = x0[0]; + ind[k++] = 0; + } + + FOR ( i = 1; i < len0 - 1; i++ ) + { + IF ( L_xor(dx0[i - 1] , dx0[i]) < 0 ) + { + ind[k] = i; + x[k++] = x0[i]; + } + } + + IF ( endpoints ) + { + ind[k] = sub(len0 , 1); + x[k++] = x0[len0 - 1]; + } + /* x only has the peaks, valleys, and endpoints */ + len = k; + minimum_l( x, len, &minMag ); + + IF ( ( len > 2 ) || ( !endpoints && ( len > 0 ) ) ) + { + /* Set initial parameters for loop */ + tempMag = minMag; + foundPeak = 0; + leftMin = minMag; + + IF ( endpoints ) + { + /* Deal with first point a little differently since tacked it on + Calculate the sign of the derivative since we taked the first point + on it does not necessarily alternate like the rest. */ + + /* The first point is larger or equal to the second */ + IF ( GE_32(x[0] , x[1]) ) + { + ii = -1; + IF ( GE_32(x[1] , x[2]) ) /* x[1] is not extremum -> overwrite with x[0] */ + { + x[1] = x[0]; + ind[1] = ind[0]; + ind++; + len--; + } + } + ELSE /* First point is smaller than the second */ + { + ii = 0; + IF ( LT_32(x[1] , x[2]) ) /* x[1] is not extremum -> overwrite with x[0] */ + { + x[1] = x[0]; + ind[1] = ind[0]; + ind++; + len--; + } + } + } + ELSE + { + ii = -1; /* First point is a peak */ + IF ( GE_16(len , 2) ) + { + IF ( GE_32(x[1] , x[0]) ) + { + ii = 0; /* First point is a valley, skip it */ + } + } + } + *cInd = 0; + + /* Loop through extrema which should be peaks and then valleys */ + WHILE ( ii < len - 1 ) + { + ii++; /* This is a peak */ + + /*Reset peak finding if we had a peak and the next peak is bigger + than the last or the left min was small enough to reset.*/ + IF ( foundPeak ) + { + tempMag = minMag; + foundPeak = 0; + } + + /* Make sure we don't iterate past the length of our vector */ + IF ( ii == len - 1 ) + { + BREAK; /* We assign the last point differently out of the loop */ + } + + /* Found new peak that was larger than temp mag and selectivity larger + than the minimum to its left. */ + IF ( ( x[ii] > tempMag ) && ( x[ii] > leftMin + sel ) ) + { + tempLoc = ii; + tempMag = x[ii]; + } + + ii++; /* Move onto the valley */ + + /* Come down at least sel from peak */ + IF ( !foundPeak && ( tempMag > sel + x[ii] ) ) + { + foundPeak = 1; /* We have found a peak */ + leftMin = x[ii]; + peakLoc[*cInd] = tempLoc; /* Add peak to index */ + peakMag[*cInd] = tempMag; + ( *cInd )++; + } + ELSE IF ( x[ii] < leftMin ) /* New left minimum */ + { + leftMin = x[ii]; + } + } + + /* Check end point */ + IF ( x[len - 1] > tempMag && x[len - 1] > leftMin + sel ) + { + peakLoc[*cInd] = len - 1; + peakMag[*cInd] = x[len - 1]; + ( *cInd )++; + } + ELSE IF ( !foundPeak && tempMag > minMag ) /* Check if we still need to add the last point */ + { + peakLoc[*cInd] = tempLoc; + peakMag[*cInd] = tempMag; + ( *cInd )++; + } + + /* Create output */ + FOR ( i = 0; i < *cInd; i++ ) + { + plocs[i] = ind[peakLoc[i]]; + } + } + ELSE + { + IF ( endpoints ) + { + /* This is a monotone function where an endpoint is the only peak */ + xInd = ( x[0] > x[1] ) ? 0 : 1; + peakMag[0] = x[xInd]; + IF ( GT_32(peakMag[0] , L_add(minMag , sel)) ) + { + plocs[0] = ind[xInd]; + *cInd = 1; + } + ELSE + { + *cInd = 0; + } + } + ELSE + { + /* Input constant or all zeros -- no peaks found */ + *cInd = 0; + } + } + + return; +} + +#if 0 +static void peakfinder_fx_32( + const Word32 *x0, /* i : vector from which the maxima will be found */ + const Word16 len0, /* i : length of input vector */ + Word16 *plocs, /* o : the indices of the identified peaks in x0 Q0 */ + Word16 *cInd, /* o : number of identified peaks Q0 */ + const Word32 sel /* i : The amount above surrounding data for a peak to be identified */ + ,const Word16 endpoints /* i : Flag to include endpoints in peak search */ +) +{ + const Word32 *pX0; + Word32 minMag, tempMag, leftMin; + Word32 dx0[L_PROT48k_2], x[L_PROT48k_2+1], peakMag[MAX_PLOCS]; + Word32 *pDx0, *pDx01, *pX; + Word16 i, len, tempLoc, foundPeak, ii, xInd, tmp16; + Word32 threshold, xAt0, xAt1, xAt2; + Word16 len0Minus1, len0Minus2, lenMinus1; + Word16 indarr[L_PROT48k_2+1], peakLoc[MAX_PLOCS]; + Word16 *pInd; + + tempLoc = 0; + + /* Find derivative */ + len0Minus1 = sub(len0, 1); + pX0 = x0 + 1; + v_sub_32(pX0, x0, dx0, len0Minus1); + + FOR (i=0; i 0))) + { + /* Set initial parameters for loop */ + tempMag = minMag; + move16(); + foundPeak = 0; + move16(); + leftMin = minMag; + move32(); + threshold = L_add(leftMin, sel); + + IF(endpoints) + { + /* Deal with first point a little differently since tacked it on + Calculate the sign of the derivative since we took the first point + on it does not necessarily alternate like the rest. */ + + /* The first point is larger or equal to the second */ + pX = x; + xAt0 = *pX++; + move32(); + xAt1 = *pX++; + move32(); + xAt2 = *pX--; /* After decrement, pX points to x[1]. */ move16(); + IF(GE_32(xAt0, xAt1)) + { + ii = -1; + move16(); + IF(GE_32(xAt1, xAt2)) /* x[1] is not extremum -> overwrite with x[0] */ + { + *pX = xAt0; /* x[1] = x[0] */ move16(); + tmp16 = *pInd++; + move16(); + *pInd++ = tmp16; /* ind[1] = ind[0] */ move16(); + len = sub(len, 1); + } + pX--; /* After decrement, pX points to x[0]. */ + } + ELSE /* First point is smaller than the second */ + { + ii = 0; + IF(LT_32(xAt1, xAt2)) /* x[1] is not extremum -> overwrite with x[0] */ + { + *pX = xAt0; /* x[1] = x[0] */ move16(); + tmp16 = *pInd++; + move16(); + *pInd++ = tmp16; /* ind[1] = ind[0] */ move16(); + len = sub(len, 1); + } + } + pX--; /* After decrement, pX points to either x[-1] or x[0]. */ + } + ELSE + { + ii = -1; /* First point is a peak */ + IF (GE_16(len , 2)) + { + IF (GE_32(x[1] , x[0])) + { + ii = 0; /* First point is a valley, skip it */ + } + } + } + *cInd = 0; + move16(); + /*Loop through extrema which should be peaks and then valleys*/ + lenMinus1 = sub(len, 1); + FOR (;;) + { + ii = add(ii, 1); /* This is a peak */ + + /* Make sure we don't iterate past the length of our vector */ + IF (GE_16(ii, lenMinus1)) + { + BREAK; + } + + /*Reset peak finding if we had a peak and the next peak is bigger + than the last or the left min was small enough to reset.*/ + IF (GT_16(foundPeak,0)) + { + tempMag = minMag; + move16(); + foundPeak = 0; + move16(); + } + + /* Found new peak that was larger than temp mag and selectivity larger + than the minimum to its left. */ + IF (GT_32(*(++pX), tempMag)) + { + IF ( GT_32(*pX, threshold)) /* threshold = leftMin + sel */ + { + tempLoc = ii; + move16(); + tempMag = *pX; + move16(); + } + } + + ii = add(ii, 1); /* Move onto the valley */ + pX++; + + /* Come down at least sel from peak */ + IF (foundPeak == 0) + { + IF (GT_32(tempMag, L_add(sel, *pX))) + { + foundPeak = 1; /* We have found a peak */ move16(); + leftMin = *pX; + move16(); + threshold = L_add(leftMin, sel); + peakLoc[*cInd] = tempLoc; /* Add peak to index */ move16(); + peakMag[*cInd] = tempMag; + move16(); + *cInd = add(*cInd, 1); + } + } + IF (foundPeak == 0) /* The above IF-block has not found the peak yet. */ + { + IF (LT_32(*pX, leftMin))/* New left minimum */ + { + leftMin = *pX; + move16(); + threshold = L_add(leftMin, sel); + } + } + } + + /* Check end point */ + IF (GT_32(x[lenMinus1], tempMag)) + { + IF (GT_32(x[lenMinus1], threshold)) /* threshold = leftMin + sel */ + { + peakLoc[*cInd] = lenMinus1; + move16(); + peakMag[*cInd] = x[lenMinus1]; + move16(); + *cInd = add(*cInd, 1); + foundPeak = 1; + move16(); + } + } + IF (foundPeak == 0) /* Check if we still need to add the last point */ + { + IF (GT_32(tempMag, minMag)) + { + peakLoc[*cInd] = tempLoc; + move16(); + peakMag[*cInd] = tempMag; + move16(); + *cInd = add(*cInd, 1); + } + } + + /* Create output */ + FOR (i = 0; i < *cInd; i++) + { + plocs[i] = *(indarr + peakLoc[i]); + move16(); + move16(); + } + } + ELSE /* This is a monotone function where an endpoint is the only peak */ + { + IF(endpoints) + { + xInd = 1; + move16(); + IF (GT_32(x[0], x[1])) + { + xInd = 0; + move16(); + } + + peakMag[0] = x[xInd]; + move16(); + IF(GT_32(peakMag[0], L_add(minMag, sel))) + { + plocs[0] = *(indarr + xInd); + move16(); + *cInd = 1; + move16(); + } + ELSE + { + *cInd = 0; + move16(); + } + } + ELSE + {/* Input constant or all zeros -- no peaks found */ + *cInd = 0; + move16(); + } + } +} +#endif + +/*--------------------------------------------------------------- + * stereo_dft_res_subst_spec_fx() + * + * Generate error concealment frame in DFT domain + * ---------------------------------------------------------------*/ + +void stereo_dft_res_subst_spec_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: Decoder DFT stereo handle */ + Word32 *pDFT_RES, /* i/o: residual signal */ + const Word32 *const DFT_PRED_RES, /* i : residual prediction signal */ + const Word16 time_offs, /* i : Time offset for phase adjustment*/ + const Word16 L_res, /* i : bandwidth of residual signal */ + const Word16 L_ana, /* i : Length of FFT analysis */ + const Word16 k, /* i : Subframe index */ + Word16 *num_plocs, /* i/o: Number of peak locations */ + Word16 *plocs, /* i/o: Peak locations (bin) */ + Word32 *plocsi, /* i/o: Peak locations (fractional) */ + const Word16 analysis_flag /* i : Flag for running peak analysis */ +) +{ + Word16 i, idx; + Word16 fac; + Word32 s1, s2, abs1, abs2, abs3, abs4; + Word32 abs_res[( STEREO_DFT_RES_BW_MAX ) / 2]; + Word32 Xmax, Xmin; + Word32 sel; + Word32 corr_phase; + Word32 *p_mem; + Word16 f_frac; + Word32 peak_phase; + Word32 phase_tmp; + Word32 phase; + Word32 conj_sign; + Word16 Np; + Word16 cos_F, sin_F; + + /* initialization */ + Copy32( DFT_PRED_RES, pDFT_RES, 2 * L_res ); + p_mem = hStereoDft->res_mem_fx; + Np = 1; + + IF ( analysis_flag ) + { + Word16 q_res = sub(getScaleFactor32(p_mem, shl(L_res, 1)) , 1); + /* Perform spectral analysis on 2nd subframe of last good frame */ + abs_res[0] = L_shr( Mpy_32_32(L_shl(p_mem[0], q_res) , L_shl(p_mem[0], q_res)), 1); /* DC */ + move32(); + FOR ( i = 1; i < L_res; i++ ) + { + Word32 r = L_shl(p_mem[2 * i], q_res); + Word32 l = L_shl(p_mem[2 * i + 1], q_res); + abs_res[i] = Madd_32_32(Mpy_32_32( r, r) , l, l ); + move32(); + } + + /* Find maxima */ + maximum_l( abs_res, L_res, &Xmax ); + minimum_l( abs_res, L_res, &Xmin ); + sel = Mpy_32_16_1(L_sub( Xmax , Xmin ) , (Word16)(0x03D7)); + + ivas_peakfinder_fx( abs_res, L_res, plocs, num_plocs, sel, FALSE ); + /* Refine peaks */ + FOR ( i = 0; i < *num_plocs; i++ ) + { + IF ( EQ_16(plocs[i] , 0) ) + { + plocsi[i] = L_add(L_deposit_h(plocs[i]) , L_shl(imax_pos_fx( &abs_res[plocs[i]]), Q1)); + move32(); + } + ELSE IF ( EQ_16(plocs[i] , L_res) ) + { + plocsi[i] = L_add(L_deposit_h(sub(plocs[i], 2)) , L_shl(imax_pos_fx( &abs_res[plocs[i] - 2] ), Q1)); + move32(); + } + ELSE + { + plocsi[i] = L_add(L_deposit_h(sub(plocs[i] , 1)) , L_shl(imax_pos_fx( &abs_res[plocs[i] - 1] ), Q1)); + move16(); + } + } + } + + /* Apply phase of stereo filling on noise spectrum */ + FOR ( i = 1; i < L_res; i++ ) + { + s1 = sign_l( pDFT_RES[2 * i] ); + s2 = sign_l( pDFT_RES[2 * i + 1] ); + abs1 = L_abs( pDFT_RES[2 * i] ); + abs2 = L_abs( pDFT_RES[2 * i + 1] ); + abs3 = L_abs( p_mem[2 * i] ); + abs4 = L_abs( p_mem[2 * i + 1] ); + + fac = MAX_16; + move16(); + /* Low-complex phase matching that brings the angle within pi/4 of the target angle */ + IF ( ( GT_32( abs1 , abs2 ) && LT_32( abs3 , abs4 ) ) || ( LE_32( abs1 , abs2 ) && GE_32( abs3 , abs4 ) ) ) + { + pDFT_RES[2 * i] = Mpy_32_32(s1 , abs4); + move32(); + pDFT_RES[2 * i + 1] = Mpy_32_32(s2 , abs3); + move32(); + } + ELSE + { + pDFT_RES[2 * i] = Mpy_32_32(s1 , abs3); + move32(); + pDFT_RES[2 * i + 1] = Mpy_32_32(s2 , abs4); + move32(); + } + } + + /* Apply phase adjustment of identified peaks, including Np=1 peak neighbors on each side */ + FOR ( i = *num_plocs - 1; i >= 0; i-- ) + { + Flag flg_ov; + IF ( EQ_16(k , 0) ) + { + Word32 op; + Word16 q_div, q_shift; + /* For 1st subframe, apply reversed time ECU to get correct analysis window */ + f_frac = extract_l(L_shr(L_sub(plocsi[i] , L_shl(plocs[i], Q16)),1)); + peak_phase = BASOP_util_atan2( p_mem[2 * plocs[i] + 1], p_mem[2 * plocs[i]], 0 ); + phase_tmp = L_sub(peak_phase , mult(f_frac , STEREO_DFT_PLC_PH_C_FX)); + phase = L_sub(phase_tmp , mult(f_frac , EVS_PI_FX)); + op = L_negate(L_shl(phase, 1)); + corr_phase = L_add( L_add( STEREO_DFT_PLC_STEP21 , L_ana) , time_offs ) ; + q_shift = norm_l(corr_phase); + corr_phase = Mpy_32_32(L_shl(corr_phase, q_shift), plocsi[i]); + corr_phase = L_deposit_l(BASOP_Util_Divide3232_Scale(corr_phase, L_ana, &q_div)); + corr_phase = L_shl(corr_phase, sub(q_div, sub(q_shift, Q15))); + corr_phase = L_negate(L_shl(Mpy_32_16_1(corr_phase, EVS_PI_FX), Q1)); + corr_phase = L_add(op, corr_phase); + WHILE ( LT_32(corr_phase, -EVS_PI_FX) ) + { + corr_phase = L_add(L_add(corr_phase, EVS_PI_FX), EVS_PI_FX); + } + WHILE ( GT_32(corr_phase, EVS_PI_FX) ) + { + corr_phase = L_sub(L_sub(corr_phase, EVS_PI_FX), EVS_PI_FX); + } + conj_sign = MIN_32; + } + ELSE + { + Word32 op = L_add(L_ana, time_offs); + Word16 q_div; + op = Mpy_32_32(L_shl(op, Q15), plocsi[i]); + corr_phase = BASOP_Util_Divide3232_Scale(op, L_ana, &q_div); + corr_phase = extract_l(L_and(L_shl(corr_phase, q_div), MAX_16)); + /* For 2nd subframe, do regular phase shift */ + corr_phase = L_negate(L_shr(L_mult0(extract_l(corr_phase), EVS_PI_FX), Q14)); + conj_sign = MAX_32; + } + + cos_F = shl_o(getCosWord16(extract_l(corr_phase)), 1, &flg_ov); + sin_F = getSinWord16(extract_l(corr_phase)); + + idx = max( 0, plocs[i] - Np ); /* Iterate over plocs[i]-1:plocs[i]+1, considering the edges of the spectrum */ + WHILE ( ( idx < plocs[i] + Np + 1 ) && ( idx < L_res ) ) + { + pDFT_RES[2 * idx] = Msub_32_16(Mpy_32_16_1(p_mem[2 * idx] , cos_F) , p_mem[2 * idx + 1] , sin_F); + pDFT_RES[2 * idx + 1] = Mpy_32_32(conj_sign , Madd_32_16(Mpy_32_16_1( p_mem[2 * idx] , sin_F) , p_mem[2 * idx + 1] , cos_F)); + idx++; + } + } + return; +} + + +/*--------------------------------------------------------------- + * stereo_dft_res_ecu_burst_att_fx() + * + * scaling residual PLC in burst error, considering DMX PLC attenuation + * ---------------------------------------------------------------*/ + +void stereo_dft_res_ecu_burst_att_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft, /* i/o: Decoder DFT stereo handle */ + Word32 *pDFT_RES, /* i/o: residual signal /att. residual */ + const Word32 dmx_nrg, /* i : dmx energy of current frame */ + const Word16 L_res, /* i : Bandwidth of residual */ + const Word16 L_ana /* i : Length of FFT analysis */ +) +{ + Word32 fac; + Word16 q_fac; + Word16 exponent; + + q_fac = 0; move16(); + exponent = 0; move16(); + + /* attenuation of residual; follow attenuation of DMX */ + IF ( EQ_16(hStereoDft->core_hist[0] , ACELP_CORE) ) + { + fac = Mpy_32_16_1(Sqrt32( L_deposit_h(BASOP_Util_Divide3232_Scale(dmx_nrg , hStereoDft->past_dmx_nrg_fx, &q_fac)), &exponent), (Word16)(0x0CCD)); + } + ELSE + { + fac = L_sub(MAX_32 , L_deposit_h(BASOP_Util_Divide3232_Scale(sub( hStereoDft->time_offs , L_ana ) , add( hStereoDft->time_offs , L_ana ) , &q_fac))); + } + + v_multc_fixed( pDFT_RES, fac, pDFT_RES, shl(L_res, 1) ); + + return; +} + +/*--------------------------------------------------------------- + * stereo_dft_dmx_swb_nrg_fx() + * + * Calculate DMX energy + * ---------------------------------------------------------------*/ + +/*! r: total energy of downmix with maximum swb bandwidth max */ +Word32 stereo_dft_dmx_swb_nrg_fx( + const Word32 *dmx_k0, /* i : first subframe spectrum */ + const Word32 *dmx_k1, /* i : second subframe spectrum */ + const int16_t frame_length /* i : frame lanegth */ +) +{ + int16_t i; + Word32 dmx_nrg; + + dmx_nrg = EPSILON_FIX; + move32(); + FOR ( i = 0; i < shr(frame_length, 1); i++ ) + { + dmx_nrg = L_add(dmx_nrg, + L_add( Madd_32_32(Mpy_32_32(dmx_k0[shl(i, 1)], dmx_k0[shl(i, 1)]), dmx_k0[add(shl(i, 1), 1)], dmx_k0[add(shl(i, 1), 1)]), + Madd_32_32(Mpy_32_32(dmx_k1[shl(i, 1)], dmx_k1[shl(i, 1)]), dmx_k1[add(shl(i, 1), 1)], dmx_k1[add(shl(i, 1), 1)]))); + } + + return dmx_nrg; +} + +/*--------------------------------------------------------------- + * stereo_dft_sg_recovery_fx() + * + * estimates panning measure + * updates recovery flag that might enbale recovery of side gain + * ---------------------------------------------------------------*/ + +Word16 stereo_dft_sg_recovery_fx( + STEREO_DFT_DEC_DATA_HANDLE hStereoDft /* i/o: Decoder DFT stereo handle */ +) +{ + Word16 b; + Word32 *pSideGain; + Word32 sg_m; + Word16 beta; + + IF ( !hStereoDft->sg_mem_corrupt ) + { + pSideGain = hStereoDft->side_gain_fx + 2 * STEREO_DFT_BAND_MAX; + beta = (Word16)(0x3666); + + sg_m = EPSILON_FIX; + FOR ( b = 0; b < hStereoDft->nbands; b++ ) + { + sg_m = L_add(sg_m , pSideGain[b]); + } + sg_m /= hStereoDft->nbands; + + IF ( LT_32(sg_m , (Word32)0x4CCCCCCD) && GT_32(sg_m , (Word32)(0xB3333333) )) + { + hStereoDft->sg_mean_fx = 0; + } + ELSE + { + hStereoDft->sg_mean_fx = Madd_32_16(Mpy_32_16_1(sg_m, beta), hStereoDft->sg_mean_fx, sub( MAX_16 , beta )); /* LP filter delta_sg to obtain side gain stability measure */ + } + } + ELSE IF ( GT_32(hStereoDft->sg_mean_fx , (Word32)0x4CCCCCCD) || LT_32(hStereoDft->sg_mean_fx , (Word32)(0xB3333333)) ) + { + return MAX_16; + } + + return 0; +} +#endif \ No newline at end of file diff --git a/lib_dec/ivas_stereo_switching_dec.c b/lib_dec/ivas_stereo_switching_dec.c index c08b3b9d33ff357aaeebbc2f4fa29937c5e0e4b4..e66192a6afc722ecb1ec75e949e9cf7c9c5f1b22 100644 --- a/lib_dec/ivas_stereo_switching_dec.c +++ b/lib_dec/ivas_stereo_switching_dec.c @@ -1520,6 +1520,361 @@ void synchro_synthesis( return; } +#ifdef IVAS_FLOAT_FIXED +void synchro_synthesis_fx( + const Word32 ivas_total_brate, /* i : IVAS total bitrate */ + CPE_DEC_HANDLE hCPE, /* i/o: CPE decoder structure */ + Word32 *output[CPE_CHANNELS], /* i/o: output synthesis signal */ + const Word16 output_frame, /* i : Number of samples */ + const Word16 sba_dirac_stereo_flag /* i : signal stereo output for SBA DirAC */ +) +{ + Word16 n, delay_comp_TD, delay_comp_DFT; + Word32 output_Fs; + Decoder_State **sts; + Word16 i, delay_cldfb, dft32ms_ovl; + Word32 *p_output_mem[CPE_CHANNELS]; + Word32 tmp_out[CPE_CHANNELS][NS2SA( 48000, DELAY_CLDFB_NS )]; + Word32 tmp_out_TD[CPE_CHANNELS][STEREO_DFT32MS_OVL_MAX]; + Word32 tmp_out_TD2[CPE_CHANNELS][STEREO_DFT32MS_OVL_MAX]; + Word16 use_cldfb_for_last_dft; + Word16 dft_mono_brate_switch; + Word16 delay_diff; + Word32 tmpF; + Word16 nChannels; + + sts = hCPE->hCoreCoder; + output_Fs = sts[0]->output_Fs; + + use_cldfb_for_last_dft = 0; + if ( ( hCPE->element_mode != IVAS_CPE_DFT && hCPE->nchan_out == 1 && hCPE->last_element_brate <= IVAS_24k4 ) /* note: this is to mimic the DFT stereo condition "hCPE->hStereoDft->hConfig->res_cod_mode == 0" in last frame */ + || ( hCPE->element_mode == IVAS_CPE_DFT && hCPE->nchan_out == 1 && hCPE->hStereoDft->hConfig->res_cod_mode == STEREO_DFT_RES_COD_OFF ) ) + { + use_cldfb_for_last_dft = 1; + } + + dft_mono_brate_switch = 0; + if ( hCPE->element_mode == IVAS_CPE_DFT && ( hCPE->last_element_mode == IVAS_CPE_DFT || hCPE->last_element_mode == IVAS_CPE_MDCT ) && hCPE->nchan_out == 1 && hCPE->element_brate != hCPE->last_element_brate ) + { + if ( hCPE->last_element_brate >= IVAS_32k && hCPE->hStereoDft->hConfig->res_cod_mode == STEREO_DFT_RES_COD_OFF ) + { + dft_mono_brate_switch = -1; /* switch from residual coding mode or MDCT Stereo */ + } + else if ( hCPE->last_element_brate <= IVAS_24k4 && hCPE->hStereoDft->hConfig->res_cod_mode > STEREO_DFT_RES_COD_OFF ) + { + dft_mono_brate_switch = 1; /* switch to residual coding mode*/ + } + } + + if ( use_cldfb_for_last_dft ) + { + if ( hCPE->element_mode == IVAS_CPE_DFT && hCPE->last_element_mode == IVAS_CPE_TD && ( ivas_total_brate > IVAS_SID_5k2 || hCPE->nchan_out == 2 ) ) + { + stereo_tca_scale_R_channel( hCPE, output[0], output_frame ); + } + } + + /* set delays */ + delay_comp_DFT = NS2SA( output_Fs, IVAS_DEC_DELAY_NS - STEREO_DFT32MS_OVL_NS ); + delay_comp_TD = NS2SA( output_Fs, IVAS_DEC_DELAY_NS - DELAY_CLDFB_NS ); + delay_diff = delay_comp_TD - delay_comp_DFT; + + dft32ms_ovl = (int16_t) ( ( STEREO_DFT32MS_OVL_MAX * output_Fs ) / 48000 ); + delay_cldfb = NS2SA( output_Fs, DELAY_CLDFB_NS ); + + /* initialize pointers */ + if ( hCPE->element_mode >= IVAS_CPE_DFT && hCPE->output_mem[0] != NULL ) + { + for ( n = 0; n < CPE_CHANNELS; n++ ) + { + p_output_mem[n] = hCPE->output_mem[n]; + } + } + + /*----------------------------------------------------------------* + * DFT stereo synchro + *----------------------------------------------------------------*/ + + if ( hCPE->element_mode == IVAS_CPE_DFT || sba_dirac_stereo_flag ) + { + /* handling of bitrate switching from residual (using DFT) to non-residual mode (using CLDFB) for mono output - as in DFT->TD switching */ + if ( dft_mono_brate_switch == -1 ) + { + for ( i = delay_comp_DFT; i < delay_comp_TD; i++ ) + { + sts[0]->prev_synth_buffer[i] = p_output_mem[0][i - delay_comp_DFT]; + } + + for ( i = delay_comp_TD; i < delay_comp_TD + delay_cldfb; i++ ) + { + tmp_out[0][i - delay_comp_TD] = p_output_mem[0][i - delay_comp_DFT]; + } + } + + if ( hCPE->nchan_out == 1 && hCPE->last_element_mode == IVAS_CPE_MDCT ) + { + v_add( sts[0]->prev_synth_buffer, sts[1]->prev_synth_buffer, sts[0]->prev_synth_buffer, delay_comp_DFT ); + v_multc( sts[0]->prev_synth_buffer, INV_SQRT_2, sts[0]->prev_synth_buffer, delay_comp_DFT ); + } + + if ( use_cldfb_for_last_dft ) + { + /* delay CLDFB-based mono output (<= 24.4 kbps) to be aligned with DFT-based mono output (32 kbps), needed to avoid discontinuities with TCX-LTP. */ + mvr2r( sts[0]->prev_synth_buffer + delay_comp_DFT, hCPE->hCoreCoder[0]->hTcxDec->FBTCXdelayBuf_float, delay_diff ); + delay_signal_float( output[0], output_frame, hCPE->hCoreCoder[0]->hTcxDec->FBTCXdelayBuf_float, delay_diff ); + } + + if ( hCPE->element_mode != IVAS_CPE_MDCT ) + { + ivas_post_proc( NULL, hCPE, 0, output[0], output, output_frame, sba_dirac_stereo_flag ); + } + + /* zero padding in order to synchronize the upmixed DFT stereo synthesis with the TD/MDCT stereo synthesis */ + for ( n = 0; n < hCPE->nchan_out; n++ ) + { + if ( sba_dirac_stereo_flag ) + { + delay_signal_float( output[n], output_frame, hCPE->prev_synth[n], delay_comp_DFT ); + } + else + { + delay_signal_float( output[n], output_frame, sts[n]->prev_synth_buffer, delay_comp_DFT ); + } + } + + if ( use_cldfb_for_last_dft ) + { + mvr2r( hCPE->hCoreCoder[0]->hTcxDec->FBTCXdelayBuf_float, sts[0]->prev_synth_buffer + delay_comp_DFT, delay_diff ); + } + + /* handling of TD->DFT switching */ + for ( n = 0; n < hCPE->nchan_out; n++ ) + { + if ( ( hCPE->last_element_mode != IVAS_CPE_DFT && !sba_dirac_stereo_flag && dft_mono_brate_switch != -1 ) || dft_mono_brate_switch == 1 ) + { + Word16 *pPrev_synth; + Word16 inv_fade_len = 1.f / delay_diff; + + /* cross-fading between TD synchro memory and the DFT output */ + if ( sba_dirac_stereo_flag ) + { + pPrev_synth = hCPE->prev_synth_fx[n]; + } + else + { + pPrev_synth = sts[n]->prev_synth_buffer; + } + + if ( hCPE->last_element_mode != IVAS_CPE_MDCT ) + { + for ( i = delay_comp_DFT; i < delay_comp_TD; i++ ) + { + output[n][i] = ( pPrev_synth[i] * ( delay_comp_TD - i ) + output[n][i] * ( i - delay_comp_DFT ) ) * inv_fade_len; + } + } + } + else if ( dft_mono_brate_switch == -1 ) + { + float inv_fade_len_1 = 1.0f / (float) delay_diff; + float inv_fade_len_2 = 1.0f / (float) delay_cldfb; + + for ( i = 0; i < delay_diff; i++ ) + { + output[0][i + delay_comp_DFT] = ( output[0][i + delay_comp_DFT] * ( delay_diff - i ) + p_output_mem[0][i] * i ) * inv_fade_len_1; + } + + for ( i = 0; i < delay_cldfb; i++ ) + { + output[0][i + delay_comp_TD] = ( tmp_out[0][i] * ( delay_cldfb - i ) + output[0][i + delay_comp_TD] * i ) * inv_fade_len_2; + } + } + } + } + + /*----------------------------------------------------------------* + * TD/MDCT stereo synchro + *----------------------------------------------------------------*/ + + if ( sba_dirac_stereo_flag ) + { + return; + } + + if ( hCPE->element_mode == IVAS_CPE_TD || hCPE->element_mode == IVAS_CPE_MDCT ) + { + /* handling of DFT->TD switching */ + if ( hCPE->last_element_mode == IVAS_CPE_DFT && !use_cldfb_for_last_dft && hCPE->output_mem[0] != NULL ) + { + /* use redressed DFT stereo OLA part to reconstruct the TD stereo synchro memory */ + for ( n = 0; n < hCPE->nchan_out; n++ ) + { + for ( i = delay_comp_DFT; i < delay_comp_TD; i++ ) + { + sts[n]->prev_synth_buffer[i] = p_output_mem[n][i - delay_comp_DFT]; + } + + for ( i = delay_comp_TD; i < delay_comp_TD + delay_cldfb; i++ ) + { + tmp_out[n][i - delay_comp_TD] = p_output_mem[n][i - delay_comp_DFT]; + } + } + } + + /* if previous frame had only one channel copy buffers to other channel */ + if ( hCPE->nchan_out == 1 && hCPE->element_mode == IVAS_CPE_MDCT && hCPE->last_element_mode == IVAS_CPE_DFT ) + { + mvr2r( sts[0]->prev_synth_buffer, sts[1]->prev_synth_buffer, delay_comp_TD ); + mvr2r( tmp_out[0], tmp_out[1], delay_cldfb ); + mvr2r( p_output_mem[0], p_output_mem[1], delay_diff ); + } + + /*----------------------------------------------------------------* + * update DFT synthesis overlap memory @output_Fs; needed for TD->DFT stereo switching + *----------------------------------------------------------------*/ + + /* resample LB synthesis to output_Fs */ + if ( hCPE->element_mode != IVAS_CPE_MDCT && !use_cldfb_for_last_dft ) + { + for ( n = 0; n < hCPE->nchan_out; n++ ) + { + if ( sts[n]->core == ACELP_CORE ) + { + lerp_flt( hCPE->input_mem_LB[n], tmp_out_TD[n], dft32ms_ovl, NS2SA( sts[n]->L_frame * FRAMES_PER_SEC, STEREO_DFT32MS_OVL_NS ) ); + } + else /* TCX/HQ core */ + { + lerp_flt( hCPE->input_mem_LB[n], tmp_out_TD[n], dft32ms_ovl, NS2SA( sts[n]->L_frame * FRAMES_PER_SEC, STEREO_DFT32MS_OVL_NS ) ); + + /* use TCX synchro memory (perfect signal is available) */ + for ( i = delay_diff; i < dft32ms_ovl; i++ ) + { + tmp_out_TD[n][i] = sts[n]->delay_buf_out[i - delay_diff]; + } + } + } + + if ( hCPE->nchan_out == CPE_CHANNELS ) + { + /* upmix the resampled LB / the TCX synchro memory */ + tdm_upmix_plain( tmp_out_TD2[0], tmp_out_TD2[1], tmp_out_TD[0], tmp_out_TD[1], tdm_ratio_tabl[hCPE->hStereoTD->tdm_last_ratio_idx], tdm_den_ratio_tabl[hCPE->hStereoTD->tdm_last_ratio_idx], 0, dft32ms_ovl, 1 ); + } + else + { + mvr2r( tmp_out_TD[0], tmp_out_TD2[0], dft32ms_ovl ); + } + + for ( n = 0; n < hCPE->nchan_out; n++ ) + { + if ( sts[0]->core == ACELP_CORE ) /* ACELP core in primary channel */ + { + tmpF = 1.0f / (float) delay_diff; + + /* cross-fading between regular output synthesis and lerp_flt() resampled synthesis in 3.125 - 1.25 ms OLA part */ + for ( i = 0; i < delay_diff; i++ ) + { + p_output_mem[n][i] = ( output[n][output_frame - dft32ms_ovl + delay_cldfb + i] * ( delay_diff - i ) + tmp_out_TD2[n][i] * i ) * tmpF; + } + } + else /* TCX core */ + { + /* reconstruct the 3.125 - 1.25 ms OLA part */ + for ( i = 0; i < delay_diff; i++ ) + { + p_output_mem[n][i] = output[n][output_frame - dft32ms_ovl + delay_cldfb + i]; + } + } + + /* reconstruct the last 1.25 ms part of OLA window */ + for ( i = delay_diff; i < dft32ms_ovl; i++ ) + { + p_output_mem[n][i] = tmp_out_TD2[n][i]; + } + } + } + + /*----------------------------------------------------------------* + * zero padding TD/MDCT synthesis in order to synchronize + * the upmixed TD/MDCT stereo synthesis with the DFT stereo synthesis + *----------------------------------------------------------------*/ + + if ( hCPE->element_mode == IVAS_CPE_TD && hCPE->stereo_switching_counter == 0 && hCPE->nchan_out == 1 && hCPE->last_element_brate <= IVAS_24k4 ) + { + float step; + tmpF = 1.0f; + step = 0.5f / delay_comp_TD; + + /* for the first switching frame from DFT to TD, downmix memory too */ + for ( n = 0; n < delay_comp_TD; n++ ) + { + sts[0]->prev_synth_buffer[n] = ( sts[0]->prev_synth_buffer[n] ) * tmpF; + tmpF -= step; + } + } + + if ( hCPE->element_mode == IVAS_CPE_MDCT && hCPE->nchan_out == 1 && !is_DTXrate( hCPE->element_brate ) && is_DTXrate( hCPE->last_element_brate ) ) + { + mvr2r( sts[0]->prev_synth_buffer, sts[1]->prev_synth_buffer, delay_comp_TD ); + } + + nChannels = ( hCPE->element_mode == IVAS_CPE_MDCT ) ? 2 : hCPE->nchan_out; + for ( n = 0; n < nChannels; n++ ) + { + if ( hCPE->element_mode == IVAS_CPE_MDCT ) + { + mvr2r( sts[n]->prev_synth_buffer + delay_comp_DFT, hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_float, delay_diff ); + delay_signal_float( output[n], output_frame, hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_float, delay_diff ); + ivas_post_proc( NULL, hCPE, n, output[n], output, output_frame, 0 ); + delay_signal_float( output[n], output_frame, sts[n]->prev_synth_buffer, delay_comp_DFT ); + mvr2r( hCPE->hCoreCoder[n]->hTcxDec->FBTCXdelayBuf_float, sts[n]->prev_synth_buffer + delay_comp_DFT, delay_diff ); + } + else + { + delay_signal_float( output[n], output_frame, sts[n]->prev_synth_buffer, delay_comp_TD ); + } + } + + /* handling of DFT->TD switching */ + if ( hCPE->last_element_mode == IVAS_CPE_DFT && !use_cldfb_for_last_dft ) + { + if ( hCPE->element_mode == IVAS_CPE_TD && hCPE->hStereoCng->prev_sid_nodata ) + { + for ( n = 0; n < hCPE->nchan_out; n++ ) + { + tmpF = 1.0f / (float) delay_cldfb; + + for ( i = 0; i < delay_cldfb; i++ ) + { + tmp_out[n][i] = tmp_out[n][i] * ( delay_cldfb - i ) * tmpF; + } + } + } + + /* cross-fading between DFT OLA memory and TD output */ + for ( n = 0; n < nChannels; n++ ) + { + if ( hCPE->element_mode == IVAS_CPE_MDCT ) + { + tmpF = 1.0f / (float) delay_diff; + + for ( i = 0; i < delay_diff; i++ ) + { + output[n][i + delay_comp_DFT] = ( output[n][i + delay_comp_DFT] * ( delay_diff - i ) + p_output_mem[n][i] * i ) * tmpF; + } + } + + tmpF = 1.0f / (float) delay_cldfb; + + for ( i = 0; i < delay_cldfb; i++ ) + { + output[n][i + delay_comp_TD] = ( tmp_out[n][i] * ( delay_cldfb - i ) + output[n][i + delay_comp_TD] * i ) * tmpF; + } + } + } + } + + return; +} +#endif /*-------------------------------------------------------------------* * Function stereo_switching_dec() diff --git a/lib_dec/stat_dec.h b/lib_dec/stat_dec.h index 90e573273eeeadf2bcbb13ae4686ec7346646abf..849050de56348807855661dd81c244b5929254d9 100644 --- a/lib_dec/stat_dec.h +++ b/lib_dec/stat_dec.h @@ -198,6 +198,15 @@ typedef struct int16_t msPeriodogBufPtr; +#ifdef IVAS_FLOAT_FIXED + Word32 smoothed_psd_fx[L_FRAME16k]; + Word16 cna_g_state_fx[STEREO_DFT_BAND_MAX]; /* stereo CNA - side gains from the last inactive frame */ + Word16 cna_cm_fx[STEREO_DFT_BAND_MAX]; /* stereo CNA - coherence from the last inactive frame */ + Word16 cna_act_fact_fx; /* stereo CNA - long-term signal activity factor (0-1) */ + Word16 cna_rescale_fact_fx; + Word16 q_smoothed_psd; +#endif + } FD_CNG_DEC, *HANDLE_FD_CNG_DEC; /*---------------------------------------------------------------* diff --git a/lib_dec/updt_dec_fx.c b/lib_dec/updt_dec_fx.c index 28baf92434fbcd085f2c55456a4dd12564d5427d..80c72b57be0bbc3ca0bb6dbaca511a9ab3a6653e 100644 --- a/lib_dec/updt_dec_fx.c +++ b/lib_dec/updt_dec_fx.c @@ -742,6 +742,358 @@ void updt_dec_common_fx( } +#ifdef IVAS_FLOAT_FIXED +static void ivas_updt_bw_switching_fx( + Decoder_State *st_fx, /* i/o: decoder state structure */ + const Word32 *synth, /* i : float synthesis signal */ + const Word16 Qpost +) +{ + test(); + IF(st_fx->output_Fs == 32000 && st_fx->bwidth == SWB) + { +#ifdef BASOP_NOGLOB + st_fx->tilt_swb_fx = round_fx_sat(L_shl_sat(ivas_calc_tilt_bwe_fx(synth, Qpost, L_FRAME32k), 3)); +#else + st_fx->tilt_swb_fx = round_fx(L_shl(calc_tilt_bwe_fx(synth, Qpost, L_FRAME32k), 3)); +#endif + } + + st_fx->prev_enerLH_fx = st_fx->enerLH_fx; + move32(); + st_fx->prev_enerLL_fx = st_fx->enerLL_fx; + move32(); + st_fx->last_bwidth = st_fx->bwidth; + move32(); + + IF( EQ_16(st_fx->core, ACELP_CORE)) + { + st_fx->last_inner_frame = L_FRAME32k; + move16(); + test(); + IF( EQ_16(st_fx->bwidth, WB) && EQ_16(st_fx->bws_cnt_fx, 0)) + { + st_fx->last_inner_frame = L_FRAME16k; + move16(); + } + } + ELSE + { + test(); + test(); + test(); + IF( !(GE_16(st_fx->last_inner_frame, L_FRAME16k)&&LE_16(inner_frame_tbl[st_fx->bwidth],L_FRAME16k)&&st_fx->bws_cnt_fx>0&<_16(st_fx->bws_cnt_fx,N_WS2N_FRAMES))) + { + st_fx->last_inner_frame = inner_frame_tbl[st_fx->bwidth]; + move16(); + } + } + st_fx->prev_bws_cnt_fx = st_fx->bws_cnt_fx; + move16(); + return; +} + +void ivas_updt_dec_common_fx( + Decoder_State *st_fx, /* i/o: decoder state structure */ + Word16 hq_core_type_fx, /* i : HQ core type */ + const Word16 concealWholeFrameTmp, /* i : concealWholeFrameTmp flag */ + const Word32 *synth, /* i : decoded synthesis */ + const Word16 Qpostd /* i : Synthesis Q value */ + +) +{ + Word16 i; + Word32 L_tmp; + + TCX_DEC_HANDLE hTcxDec; + hTcxDec = st_fx->hTcxDec; + + st_fx->last_codec_mode = st_fx->codec_mode; + move16(); + st_fx->last_extl = st_fx->extl; + move16(); + st_fx->last_L_frame = st_fx->L_frame; + move16(); + + st_fx->prev_old_bfi_fx = st_fx->prev_bfi; + st_fx->prev_bfi = st_fx->bfi; + move16(); + IF (NE_16(st_fx->core, AMR_WB_CORE)) + { + st_fx->old_bfi_cnt_fx = st_fx->nbLostCmpt; + move16(); + } + move16(); + st_fx->last_con_tcx = st_fx->con_tcx; + move16(); + st_fx->con_tcx = 0; + + move16(); + IF(st_fx->hHQ_nbfec != NULL) + { + st_fx->hHQ_nbfec->prev_last_core_fx = st_fx->last_core; + } + IF(st_fx->hTcxDec != NULL) + { + hTcxDec->tcxConceal_recalc_exc = 0; + move16(); + } + test();test(); + IF( (GE_16(st_fx->rf_frame_type,RF_TCXFD) && LE_16(st_fx->rf_frame_type,RF_TCXTD2) && st_fx->use_partial_copy && st_fx->bfi) || !st_fx->bfi) + { + test();test(); + test(); test(); + IF( st_fx->bfi && (LE_16(st_fx->last_good_fx, UNVOICED_TRANSITION)) && (GT_16(st_fx->clas_dec,UNVOICED_TRANSITION)) && st_fx->last_con_tcx && st_fx->hTcxDec != NULL) + { + hTcxDec->tcxConceal_recalc_exc = 1; + move16(); + } + st_fx->last_good_fx = st_fx->clas_dec; + move16(); + } + IF (st_fx->use_partial_copy) + { + st_fx->prev_rf_frame_type = st_fx->rf_frame_type; + } + ELSE + { + st_fx->prev_rf_frame_type = INACTIVE; + } + + IF (EQ_16(st_fx->m_frame_type, ACTIVE_FRAME) && (st_fx->bfi!=1 || st_fx->use_partial_copy!=0)) + { + st_fx->rf_flag_last = st_fx->rf_flag; + } + + IF( EQ_16(st_fx->codec_mode,MODE1)) + { + test(); + IF( !st_fx->bfi && (st_fx->core_brate > SID_2k40 || (GT_32(st_fx->core_brate, SID_1k75) && EQ_16(st_fx->core, AMR_WB_CORE)))) + { + move16(); + st_fx->last_active_brate = st_fx->total_brate; + } + + move16(); + move16(); + st_fx->last_core = st_fx->core; + if (st_fx->hHQ_core != NULL) + { + st_fx->hHQ_core->last_hq_core_type_fx = hq_core_type_fx; + } + } + ELSE IF( EQ_16(st_fx->codec_mode,MODE2)) + { + test(); + IF ((!st_fx->bfi) && (st_fx->last_is_cng==0)) + { + move16(); + st_fx->last_active_brate = st_fx->total_brate; + } + /* INFO: moved from update_decoder_LPD_cng() */ + IF (NE_16(st_fx->m_frame_type,ACTIVE_FRAME)) + { + move16(); + st_fx->last_is_cng = 1; + } + + + IF (!st_fx->bfi) + { + st_fx->last_core = st_fx->core; + } + move16(); + move16(); + st_fx->last_core_bfi = st_fx->core; /* also required for clean channel decoding */ + } + move16(); + st_fx->last_core_brate = st_fx->core_brate; + + /* save synthesis for core switching */ + test(); + IF (EQ_16(st_fx->element_mode, EVS_MONO) && NE_16(st_fx->core, AMR_WB_CORE)) + { + Copy_Scale_sig_32_16(synth + NS2SA_fx2(st_fx->output_Fs, ACELP_LOOK_NS + DELAY_BWE_TOTAL_NS), st_fx->old_synth_sw_fx, NS2SA_fx2(st_fx->output_Fs, FRAME_SIZE_NS - ACELP_LOOK_NS - DELAY_BWE_TOTAL_NS), st_fx->hHQ_core->Q_old_postdec); + } + test(); + test(); + test(); +#ifdef IVAS_CODE + /* Store long-term estimates of stab_fac and log energy diff to estimate env_stab in case of core switch ACELP/TCX->HQ */ + if (st->element_mode != EVS_MONO) + { + output_frame = NS2SA(st->output_Fs, FRAME_SIZE_NS); + log_energy = log2f((sum2_f(synth, output_frame) / output_frame) + 1.0f); + log_energy_diff = fabsf(st->log_energy_old - log_energy); + st->log_energy_old = log_energy; + st->log_energy_diff_lt = ENV_SMOOTH_FAC * log_energy_diff + (1.0f - ENV_SMOOTH_FAC) * st->log_energy_diff_lt; + if (st->core == HQ_CORE) + { + st->stab_fac = min(1, (STAB_FAC_EST1 + (STAB_FAC_EST2 * st->hHQ_core->mem_env_delta) + (STAB_FAC_EST3 * st->log_energy_diff_lt))); + st->stab_fac = max(0, st->stab_fac); + } + st->stab_fac_smooth_lt = ENV_SMOOTH_FAC * st->stab_fac + (1.0f - ENV_SMOOTH_FAC) * st->stab_fac_smooth_lt; + } +#endif + IF( ((LE_32(st_fx->core_brate,SID_2k40))&&EQ_16(st_fx->cng_type,FD_CNG)) + || (st_fx->tcxonly && EQ_16(st_fx->codec_mode,MODE2)) + ) + + { + /* reset LP memories */ + set16_fx( st_fx->mem_MA_fx,0, M ); + IF( EQ_32(st_fx->sr_core,INT_FS_16k)) + { + Copy( GEWB2_Ave_fx, st_fx->mem_AR_fx, M ); + } + ELSE + { + Copy( GEWB_Ave_fx, st_fx->mem_AR_fx, M ); + } + } + IF(EQ_16(st_fx->codec_mode, MODE2)) + { + test(); + IF(EQ_16(st_fx->use_partial_copy, 1) && EQ_16(st_fx->rf_frame_type, RF_NELP)) + { + st_fx->last_nelp_mode_dec_fx = 1; + } + ELSE + { + st_fx->last_nelp_mode_dec_fx = 0; + } + } + + st_fx->prev_use_partial_copy = st_fx->use_partial_copy; + move16(); + + st_fx->prev_tilt_code_dec_fx = 0; + move16(); + + st_fx->prev_Q_exc = st_fx->Q_exc; + move16(); + + L_tmp = L_mult(st_fx->tilt_code_dec_fx[0], 4096); + FOR(i = 1; i < NB_SUBFR; i++) + { + L_tmp = L_mac(L_tmp, st_fx->tilt_code_dec_fx[i], 4096); + } + st_fx->prev_tilt_code_dec_fx = round_fx(L_tmp); + + IF (EQ_16(st_fx->core, HQ_CORE)) + { + st_fx->prev_coder_type_fx = GENERIC; + } + ELSE IF (NE_16(st_fx->core, AMR_WB_CORE) ) + { + st_fx->prev_coder_type_fx = st_fx->coder_type_fx; + } + + test(); + IF((GT_32(st_fx->core_brate, SID_2k40) || (GT_32(st_fx->core_brate, SID_1k75) && EQ_16(st_fx->core, AMR_WB_CORE))) && EQ_16(st_fx->first_CNG, 1) && st_fx->hTdCngDec != NULL) + { + IF (GE_16(st_fx->hTdCngDec->act_cnt_fx, BUF_DEC_RATE)) + { + st_fx->hTdCngDec->act_cnt_fx = 0; + move16(); + } + + st_fx->hTdCngDec->act_cnt_fx = add(st_fx->hTdCngDec->act_cnt_fx, 1); + + test(); + IF ((EQ_16(st_fx->hTdCngDec->act_cnt_fx, BUF_DEC_RATE)) && (st_fx->hTdCngDec->ho_hist_size_fx > 0)) + { + st_fx->hTdCngDec->ho_hist_size_fx = sub(st_fx->hTdCngDec->ho_hist_size_fx, 1); + } + + st_fx->hTdCngDec->act_cnt2_fx = add(st_fx->hTdCngDec->act_cnt2_fx, 1); + IF (GE_16(st_fx->hTdCngDec->act_cnt2_fx, MIN_ACT_CNG_UPD)) + { + st_fx->hTdCngDec->act_cnt2_fx = MIN_ACT_CNG_UPD; + move16(); + } + } + + test(); + test(); + if (LE_32(st_fx->core_brate, SID_2k40) && st_fx->first_CNG == 0 && (EQ_16(st_fx->cng_type, LP_CNG) || EQ_16(st_fx->element_mode, IVAS_CPE_MDCT))) + { + st_fx->first_CNG = 1; + move16(); + } + + /* update bandwidth switching parameters */ + test(); test(); + st_fx->last_flag_cna = st_fx->flag_cna; + move16(); + if (st_fx->hFdCngDec != NULL) + { + st_fx->hFdCngDec->hFdCngCom->frame_type_previous = st_fx->m_frame_type; + move16(); + } + + if (GT_16(st_fx->element_mode, EVS_MONO)) + { + st_fx->m_old_frame_type = st_fx->m_frame_type; + } + + /* update bandwidth switching parameters */ + IF ( EQ_16(st_fx->core, AMR_WB_CORE)) + { + st_fx->last_bwidth = WB; + + st_fx->prev_bws_cnt_fx = 0; + st_fx->bws_cnt_fx = 0; + st_fx->bws_cnt1_fx = 0; + move16();move16();move16();move16(); + + } + ELSE IF(EQ_16(st_fx->codec_mode, MODE1) && ((GT_32(st_fx->core_brate, SID_2k40)) || (EQ_16(st_fx->element_mode, EVS_MONO)))) + { + ivas_updt_bw_switching_fx(st_fx, synth, Qpostd); + } + ELSE + { + st_fx->last_bwidth = st_fx->bwidth; + st_fx->prev_bws_cnt_fx = st_fx->bws_cnt_fx; + move32(); + move16(); + } + + /* synchronisation of CNG seeds*/ + test(); + test(); + IF(st_fx->hTdCngDec != NULL && (st_fx->bfi || (NE_32(st_fx->core_brate, FRAME_NO_DATA) && NE_32(st_fx->core_brate, SID_2k40))) && NE_16(st_fx->core, AMR_WB_CORE)) + { + Random(&(st_fx->hTdCngDec->cng_seed_fx)); + Random(&(st_fx->hTdCngDec->cng_ener_seed_fx)); + } + + test();test();test(); + IF(st_fx->hTcxDec != NULL && st_fx->enablePlcWaveadjust && !concealWholeFrameTmp && NE_16(st_fx->core, AMR_WB_CORE)) + { + /* update the parameters used in waveform adjustment */ + concealment_update2_x(synth, &st_fx->plcInfo, hTcxDec->L_frameTCX); + } + + st_fx->last_total_brate_ber = st_fx->total_brate; + move32(); + if (st_fx->bfi == 0) + { + st_fx->last_total_brate = st_fx->total_brate; + st_fx->last_bits_frame_nominal = st_fx->bits_frame_nominal; + move32(); + } + st_fx->last_low_rate_mode = st_fx->low_rate_mode; move16(); + if (LT_16(st_fx->ini_frame, MAX_FRAME_COUNTER)) + { + st_fx->ini_frame = add(st_fx->ini_frame,1); + } + + return; +} +#endif + /*-------------------------------------------------------------------* * update_decoder_LPD_cng() *