From 9a8f0a3b18dd00925b6fbc755eae4f413d69ec32 Mon Sep 17 00:00:00 2001 From: Sandesh Venkatesh Date: Sat, 2 Mar 2024 22:55:38 +0530 Subject: [PATCH] Converted functions in reverb filter design --- lib_com/cnst.h | 4 + lib_rend/ivas_prot_rend.h | 102 +++- lib_rend/ivas_reverb.c | 246 +++++++- lib_rend/ivas_reverb_filter_design.c | 884 ++++++++++++++++++++++++++- lib_rend/ivas_reverb_utils.c | 80 ++- 5 files changed, 1286 insertions(+), 30 deletions(-) diff --git a/lib_com/cnst.h b/lib_com/cnst.h index af5c81594..72152c22b 100644 --- a/lib_com/cnst.h +++ b/lib_com/cnst.h @@ -2640,6 +2640,8 @@ enum #define LG10_G_CODE_MIN_TC_Q14 LG10_G_CODE_MIN_Q14 /* log10(0.02) Q15*/ #define LG10_G_CODE_MAX_TC_Q13 LG10_G_CODE_MAX_Q13 +#define LN_2_Q31 (1488521848 ) + /* AVQ (RE8) related consatnts */ #define QR 32768 #define Q_AVQ_OUT 6 /* AVQ_output scaling currently Q9, but may change */ @@ -2678,6 +2680,8 @@ enum #define LG10 24660 /* 10*log10(2) in Q13 */ #define LG10_s3_0 16440 /* 10*log10(2)/1.55 = 1.00343331 in Q14 */ +#define LOG2_10 27213 /* log base 2 of 10 in Q12 */ +#define LOG10_2 646456993 /* log base 10 of 2 in Q31 */ #define MU_MA_FX 10923 /* original prediction factor for the AMR WB tables (Q15) */ diff --git a/lib_rend/ivas_prot_rend.h b/lib_rend/ivas_prot_rend.h index 5e32b5be2..a68896ef8 100644 --- a/lib_rend/ivas_prot_rend.h +++ b/lib_rend/ivas_prot_rend.h @@ -1537,14 +1537,34 @@ void ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR( float *fft_real, const int16_t fft_size ); - +#ifdef IVAS_FLOAT_FIXED +void ivas_reverb_define_window_fft_fx( + Word32 *pWindow, //output in Q31 + const Word16 transitionStart, + const Word16 transitionLength, + const Word16 spectrumLength +); +#else void ivas_reverb_define_window_fft( float *pWindow, const int16_t transitionStart, const int16_t transitionLength, const int16_t spectrumLength ); - +#endif +#if 0 +Word16 ivas_reverb_calc_color_filters_fx( + const Word32 *pTargetL, + const Word32 *pTargetR, + const Word32 *pWindow, + const Word16 fft_size, + const Word32 delay, + Word32 **pBeqL, + Word32 **pBeqR, + Word16 *q_pBeqL, + Word16 *q_pBeqR +); +#else int16_t ivas_reverb_calc_color_filters( const float *pTargetL, const float *pTargetR, @@ -1554,16 +1574,42 @@ int16_t ivas_reverb_calc_color_filters( rv_fftwf_type_complex *pBeqL, rv_fftwf_type_complex *pBeqR ); - +#endif +#ifdef IVAS_FLOAT_FIXED +Word16 ivas_reverb_calc_correl_filters_fx( + Word32 *pTargetICC, //input in Q30 + const Word32 *pWindow, //input in Q30 + const Word16 fft_size, + const Word16 delay, + Word32 **pU, //input in Q31 + Word32 **pV, //input in Q31 + Word16 *q_pU, //Output q + Word16 *q_pV //output q +); +#else int16_t ivas_reverb_calc_correl_filters( - const float *pTargetICC, - const float *pWindow, - const int16_t fft_size, - const float delay, - rv_fftwf_type_complex *pU, - rv_fftwf_type_complex *pV + const float *pTargetICC, + const float *pWindow, + const int16_t fft_size, + const float delay, + rv_fftwf_type_complex *pU, + rv_fftwf_type_complex *pV ); - +#endif +#ifdef IVAS_FLOAT_FIXED +void ivas_reverb_calc_color_levels_fx( + const Word32 output_Fs, + const Word16 freq_count, + const Word16 loop_count, + const Word32 *pFc, //input in Q14 + const Word32 *pAcoustic_dsr, //input in Q31 + const Word32 *pHrtf_avg_pwr_L, //input in Q28 + const Word32 *pHrtf_avg_pwr_R, //input in Q28 + const Word16 *pLoop_delays, + const Word32 *pT60_filter_coeff, //input in Q31 + Word32 *pTarget_color_L, //output in Q30 + Word32 *pTarget_color_R); //output in Q30 +#else void ivas_reverb_calc_color_levels( const int32_t output_Fs, const int16_t freq_count, @@ -1577,7 +1623,7 @@ void ivas_reverb_calc_color_levels( float *pTarget_color_L, float *pTarget_color_R ); - +#endif ivas_error ivas_reverb_prepare_cldfb_params( IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pInput_params, const HRTFS_FASTCONV_HANDLE hHrtfFastConv, @@ -1586,7 +1632,20 @@ ivas_error ivas_reverb_prepare_cldfb_params( const int32_t output_Fs, float *pOutput_t60, float *pOutput_ene ); - +#ifdef IVAS_FLOAT_FIXED +void ivas_reverb_interpolate_acoustic_data_fx( + const Word16 input_table_size, + const Word32 *pInput_fc, //input in Q16 + const Word32 *pInput_t60, //input in Q26 + const Word32 *pInput_dsr, //input in Q30 + const Word16 output_table_size, + const Word32 *pOutput_fc, + Word32 *pOutput_t60, + Word32 *pOutput_dsr, + Word16 *pOutput_t60_e, //output e + Word16 *pOutput_dsr_e //output e +); +#else void ivas_reverb_interpolate_acoustic_data( const int16_t input_table_size, const float *pInput_fc, @@ -1597,7 +1656,22 @@ void ivas_reverb_interpolate_acoustic_data( float *pOutput_t60, float *pOutput_dsr ); - +#endif +#ifdef IVAS_FLOAT_FIXED +void ivas_reverb_get_hrtf_set_properties_fx( + Word32 **ppHrtf_set_L_re, + Word32 **ppHrtf_set_L_im, + Word32 **ppHrtf_set_R_re, + Word32 **ppHrtf_set_R_im, + const AUDIO_CONFIG input_audio_config, + const Word16 hrtf_count, + const Word16 in_freq_count, + const Word16 out_freq_count, + Word32 *pOut_avg_pwr_L, //output in Q23 + Word32 *pOut_avg_pwr_R, //output in Q23 + Word32 *out_i_a_coherence //output in Q27 +); +#else void ivas_reverb_get_hrtf_set_properties( float **ppHrtf_set_L_re, float **ppHrtf_set_L_im, @@ -1611,7 +1685,7 @@ void ivas_reverb_get_hrtf_set_properties( float *pOut_avg_pwr_R, float *pOut_i_a_coherence ); - +#endif /*---------------------------------------------------------------------------------* * Shoebox Prototypes diff --git a/lib_rend/ivas_reverb.c b/lib_rend/ivas_reverb.c index 85f57849f..7c133b8b4 100644 --- a/lib_rend/ivas_reverb.c +++ b/lib_rend/ivas_reverb.c @@ -1386,10 +1386,17 @@ static void set_reverb_acoustic_data( { int16_t nr_out_ch, hrtf_idx, offset, iter_idx, bin_idx; float ln_1e6_inverted, delay_diff, exp_argument; +#ifdef IVAS_FLOAT_FIXED + Word32 *pHrtf_set_l_re_fx[MAX_INTERN_CHANNELS]; + Word32 *pHrtf_set_l_im_fx[MAX_INTERN_CHANNELS]; + Word32 *pHrtf_set_r_re_fx[MAX_INTERN_CHANNELS]; + Word32 *pHrtf_set_r_im_fx[MAX_INTERN_CHANNELS]; +#else float *pHrtf_set_l_re[MAX_INTERN_CHANNELS]; float *pHrtf_set_l_im[MAX_INTERN_CHANNELS]; float *pHrtf_set_r_re[MAX_INTERN_CHANNELS]; float *pHrtf_set_r_im[MAX_INTERN_CHANNELS]; +#endif /* use crend hrtf filters */ if ( hHrtf != NULL ) @@ -1408,30 +1415,96 @@ static void set_reverb_acoustic_data( if ( nr_out_ch == 0 ) { - pHrtf_set_l_re[hrtf_idx] = &hHrtf->pOut_to_bin_re[hrtf_idx][0][offset]; - pHrtf_set_l_im[hrtf_idx] = &hHrtf->pOut_to_bin_im[hrtf_idx][0][offset]; +#ifdef IVAS_FLOAT_FIXED + pHrtf_set_l_re_fx[hrtf_idx] = &hHrtf->pOut_to_bin_re_fx[hrtf_idx][0][offset]; + pHrtf_set_l_im_fx[hrtf_idx] = &hHrtf->pOut_to_bin_im_fx[hrtf_idx][0][offset]; +#else + pHrtf_set_l_re[hrtf_idx] = &hHrtf->pOut_to_bin_re[hrtf_idx][0][offset]; + pHrtf_set_l_im[hrtf_idx] = &hHrtf->pOut_to_bin_im[hrtf_idx][0][offset]; +#endif } else { - pHrtf_set_r_re[hrtf_idx] = &hHrtf->pOut_to_bin_re[hrtf_idx][1][offset]; - pHrtf_set_r_im[hrtf_idx] = &hHrtf->pOut_to_bin_im[hrtf_idx][1][offset]; +#ifdef IVAS_FLOAT_FIXED + pHrtf_set_r_re_fx[hrtf_idx] = &hHrtf->pOut_to_bin_re_fx[hrtf_idx][1][offset]; + pHrtf_set_r_im_fx[hrtf_idx] = &hHrtf->pOut_to_bin_im_fx[hrtf_idx][1][offset]; +#else + pHrtf_set_r_re[hrtf_idx] = &hHrtf->pOut_to_bin_re[hrtf_idx][1][offset]; + pHrtf_set_r_im[hrtf_idx] = &hHrtf->pOut_to_bin_im[hrtf_idx][1][offset]; +#endif } } } /* Compute HRTF set properties using frequency-domain HRTF data */ +#ifdef IVAS_FLOAT_FIXED + Word32 *pHrtf_avg_pwr_response_l_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32 *pHrtf_avg_pwr_response_r_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32 *pHrtf_inter_aural_coherence_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + ivas_reverb_get_hrtf_set_properties_fx(pHrtf_set_l_re_fx, pHrtf_set_l_im_fx, pHrtf_set_r_re_fx, pHrtf_set_r_im_fx, input_audio_config, hHrtf->max_num_ir, subframe_len, + nr_fc_fft_filter, pHrtf_avg_pwr_response_l_fx, pHrtf_avg_pwr_response_r_fx, pHrtf_inter_aural_coherence_fx); + + for (int i = 0; i < nr_fc_fft_filter; i++) + { + pParams->pHrtf_avg_pwr_response_l[i] = (float)pHrtf_avg_pwr_response_l_fx[i] / (ONE_IN_Q23); + pParams->pHrtf_avg_pwr_response_r[i] = (float)pHrtf_avg_pwr_response_r_fx[i] / (ONE_IN_Q23); + pParams->pHrtf_inter_aural_coherence[i] = (float)pHrtf_inter_aural_coherence_fx[i] / (ONE_IN_Q27); + } + + free(pHrtf_avg_pwr_response_l_fx); + free(pHrtf_avg_pwr_response_r_fx); + free(pHrtf_inter_aural_coherence_fx); +#else ivas_reverb_get_hrtf_set_properties( pHrtf_set_l_re, pHrtf_set_l_im, pHrtf_set_r_re, pHrtf_set_r_im, input_audio_config, hHrtf->max_num_ir, subframe_len, nr_fc_fft_filter, pParams->pHrtf_avg_pwr_response_l, pParams->pHrtf_avg_pwr_response_r, pParams->pHrtf_inter_aural_coherence ); - +#endif pParams->pHrtf_avg_pwr_response_l_const = (const float *) pParams->pHrtf_avg_pwr_response_l; pParams->pHrtf_avg_pwr_response_r_const = (const float *) pParams->pHrtf_avg_pwr_response_r; pParams->pHrtf_inter_aural_coherence_const = (const float *) pParams->pHrtf_inter_aural_coherence; } /* interpolate input table data for T60 and DSR to the FFT filter grid */ +#ifdef IVAS_FLOAT_FIXED + Word32* pFc_input_fx = (Word32*)malloc(60 * sizeof(Word32*)); + Word32* pAcoustic_rt60_fx = (Word32*)malloc(60 * sizeof(Word32*)); + Word32* pAcoustic_dsr_fx = (Word32*)malloc(60 * sizeof(Word32*)); + + Word32* pFc_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32* pRt60_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word16* pRt60_e = (Word16*)malloc(nr_fc_fft_filter * sizeof(Word16*)); + Word32* pDsr_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word16* pDsr_e = (Word16*)malloc(nr_fc_fft_filter * sizeof(Word16*)); + + for (int i = 0; i < 60; i++) + { + pFc_input_fx[i] = (Word32)(pRoomAcoustics->pFc_input[i] * ONE_IN_Q16); + pAcoustic_rt60_fx[i] = (Word32)((pRoomAcoustics->pAcoustic_rt60[i]) * ONE_IN_Q26); + pAcoustic_dsr_fx[i] = (Word32)(pRoomAcoustics->pAcoustic_dsr[i] * ONE_IN_Q30); + } + + for (int i = 0; i < nr_fc_fft_filter; i++) + { + pFc_fx[i] = (Word32)(pParams->pFc[i] * ONE_IN_Q16); + } + + ivas_reverb_interpolate_acoustic_data_fx(nr_fc_input, pFc_input_fx, pAcoustic_rt60_fx, pAcoustic_dsr_fx, + nr_fc_fft_filter, pFc_fx, pRt60_fx, pDsr_fx, pRt60_e, pDsr_e); + for (int i = 0; i < nr_fc_fft_filter; i++) { + pParams->pRt60[i] = fabsf(me2f(pRt60_fx[i], pRt60_e[i])); + pParams->pDsr[i] = fabsf(me2f(pDsr_fx[i], pDsr_e[i])); + } + free(pFc_input_fx); + free(pAcoustic_rt60_fx); + free(pAcoustic_dsr_fx); + free(pFc_fx); + free(pRt60_fx); + free(pRt60_e); + free(pDsr_fx); + free(pDsr_e); +#else ivas_reverb_interpolate_acoustic_data( nr_fc_input, pRoomAcoustics->pFc_input, pRoomAcoustics->pAcoustic_rt60, pRoomAcoustics->pAcoustic_dsr, nr_fc_fft_filter, pParams->pFc, pParams->pRt60, pParams->pDsr ); - +#endif /* adjust DSR for the delay difference */ delay_diff = pRoomAcoustics->inputPreDelay - pRoomAcoustics->acousticPreDelay; ln_1e6_inverted = 1.0f / logf( 1e06f ); @@ -1698,9 +1771,45 @@ ivas_error ivas_reverb_open( } /* Compute target levels (gains) for the coloration filters */ +#ifdef IVAS_FLOAT_FIXED + Word32 *pFc = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32 *pDsr = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32 *pHrtf_avg_pwr_response_l_const = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32 *pHrtf_avg_pwr_response_r_const = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32 *pT60_filter_coeff = (Word32*)malloc((params.nr_loops * 4 + 4) * sizeof(Word32*)); + Word32 *pColor_target_l_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + Word32 *pColor_target_r_fx = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32*)); + + + for (int i = 0; i < nr_fc_fft_filter; i++) + { + pFc[i] = (Word32)(params.pFc[i] * ONE_IN_Q14); + pDsr[i] = (Word32)(params.pDsr[i] * ONE_IN_Q31); + pHrtf_avg_pwr_response_l_const[i] = (Word32)(params.pHrtf_avg_pwr_response_l_const[i] * ONE_IN_Q28); + pHrtf_avg_pwr_response_r_const[i] = (Word32)(params.pHrtf_avg_pwr_response_r_const[i] * ONE_IN_Q28); + } + for (int i = 0; i < params.nr_loops * 4 + 4; i++) + { + pT60_filter_coeff[i] = (Word32)(params.pT60_filter_coeff[i] * ONE_IN_Q31); + } + ivas_reverb_calc_color_levels_fx(output_Fs, nr_fc_fft_filter, params.nr_loops, pFc, pDsr, pHrtf_avg_pwr_response_l_const, pHrtf_avg_pwr_response_r_const, + params.pLoop_delays, pT60_filter_coeff, pColor_target_l_fx, pColor_target_r_fx); + for (int i = 0; i < nr_fc_fft_filter; i++) + { + pColor_target_l[i] = (float)pColor_target_l_fx[i] / ONE_IN_Q30; + pColor_target_r[i] = (float)pColor_target_r_fx[i] / ONE_IN_Q30; + } + free(pFc); + free(pDsr); + free(pHrtf_avg_pwr_response_l_const); + free(pHrtf_avg_pwr_response_r_const); + free(pT60_filter_coeff); + free(pColor_target_l_fx); + free(pColor_target_r_fx); +#else ivas_reverb_calc_color_levels( output_Fs, nr_fc_fft_filter, params.nr_loops, params.pFc, params.pDsr, params.pHrtf_avg_pwr_response_l_const, params.pHrtf_avg_pwr_response_r_const, params.pLoop_delays, params.pT60_filter_coeff, pColor_target_l, pColor_target_r ); - +#endif /* Defining appropriate windowing parameters for FFT filters to prevent aliasing */ fft_hist_size = pState->fft_size - pState->fft_subblock_size; @@ -1708,8 +1817,16 @@ ivas_error ivas_reverb_open( transition_length = (int16_t) roundf( FFT_FILTER_WND_TRANS_REGION * fft_hist_size ); /* Compute the window used for FFT filters */ +#ifdef IVAS_FLOAT_FIXED + Word32 *pTime_window_fx = (Word32*)malloc(512 * sizeof(Word32*)); + ivas_reverb_define_window_fft_fx(pTime_window_fx, transition_start, transition_length, nr_fc_fft_filter); + for (int i = 0; i < RV_FILTER_MAX_FFT_SIZE; i++) { + pTime_window[i] = (float)pTime_window_fx[i] / ONE_IN_Q31; + } + free(pTime_window_fx); +#else ivas_reverb_define_window_fft( pTime_window, transition_start, transition_length, nr_fc_fft_filter ); - +#endif /* === Now, copy parameters from ivas_reverb_params_t into DSP blocks === */ /* === to be used for subsequent audio signal processing === */ @@ -1725,8 +1842,61 @@ ivas_error ivas_reverb_open( if ( pState->do_corr_filter ) { /* Computing correlation filters on the basis of target IA coherence */ +#ifdef IVAS_FLOAT_FIXED + Word32** pFft_wf_filter_ch0_fx = (Word32**)malloc(nr_fc_fft_filter * sizeof(Word32*)); + + for (int i = 0; i < nr_fc_fft_filter; i++) { + pFft_wf_filter_ch0_fx[i] = (Word32*)malloc(2 * sizeof(Word32)); + } + + Word32** pFft_wf_filter_ch1_fx = (Word32**)malloc(nr_fc_fft_filter * sizeof(Word32*)); + + for (int i = 0; i < nr_fc_fft_filter; i++) { + pFft_wf_filter_ch1_fx[i] = (Word32*)malloc(2 * sizeof(Word32)); + } + Word32* pWindow_fx = (Word32*)malloc(512 * sizeof(Word32)); + + Word16 q_pFft_wf_filter_ch0_fx, q_pFft_wf_filter_ch1_fx; + + for (int i = 0; i < nr_fc_fft_filter; i++) { + pFft_wf_filter_ch0_fx[i][0] = ((Word32)pFft_wf_filter_ch0[i][0] * ONE_IN_Q31); + pFft_wf_filter_ch0_fx[i][1] = ((Word32)pFft_wf_filter_ch0[i][1] * ONE_IN_Q31); + } + for (int i = 0; i < nr_fc_fft_filter; i++) { + pFft_wf_filter_ch1_fx[i][0] = (Word32)(pFft_wf_filter_ch1_fx[i][0] * ONE_IN_Q31); + pFft_wf_filter_ch1_fx[i][1] = (Word32)(pFft_wf_filter_ch1_fx[i][1] * ONE_IN_Q31); + } + for (int i = 0; i < RV_FILTER_MAX_FFT_SIZE; i++) { + pWindow_fx[i] = (Word32)(pTime_window[i] * ONE_IN_Q30); + } + + Word32* pHrtf_inter_aural_coherence_const = (Word32*)malloc(nr_fc_fft_filter * sizeof(Word32)); + for (int i = 0; i < nr_fc_fft_filter; i++) { + pHrtf_inter_aural_coherence_const[i] = (Word32)(params.pHrtf_inter_aural_coherence_const[i] * ONE_IN_Q30); + } + ivas_reverb_calc_correl_filters_fx(pHrtf_inter_aural_coherence_const, pWindow_fx, pState->fft_size, 0, pFft_wf_filter_ch0_fx, pFft_wf_filter_ch1_fx, &q_pFft_wf_filter_ch0_fx, &q_pFft_wf_filter_ch1_fx); + + for (int i = 0; i < nr_fc_fft_filter; i++) { + pFft_wf_filter_ch0[i][0] = (float)pFft_wf_filter_ch0_fx[i][0] / (1u << q_pFft_wf_filter_ch0_fx); + pFft_wf_filter_ch0[i][1] = (float)pFft_wf_filter_ch0_fx[i][1] / (1u << q_pFft_wf_filter_ch0_fx); + } + + for (int i = 0; i < nr_fc_fft_filter; i++) { + pFft_wf_filter_ch1[i][0] = (float)pFft_wf_filter_ch1_fx[i][0] / (1u << q_pFft_wf_filter_ch1_fx); + pFft_wf_filter_ch1[i][1] = (float)pFft_wf_filter_ch1_fx[i][1] / (1u << q_pFft_wf_filter_ch1_fx); + } + + for (int i = 0; i < nr_fc_fft_filter; i++) { + free(pFft_wf_filter_ch1_fx[i]); + free(pFft_wf_filter_ch0_fx[i]); + } + free(pFft_wf_filter_ch1_fx); + free(pFft_wf_filter_ch0_fx); + free(pWindow_fx); + free(pHrtf_inter_aural_coherence_const); +#else ivas_reverb_calc_correl_filters( params.pHrtf_inter_aural_coherence_const, pTime_window, pState->fft_size, 0.0f, pFft_wf_filter_ch0, pFft_wf_filter_ch1 ); - +#endif /* Copying the computed FFT correlation filters to the fft_filter components */ if ( ( error = set_correl_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK ) { @@ -1740,8 +1910,64 @@ ivas_error ivas_reverb_open( } /* Computing coloration filters on the basis of target responses */ - ivas_reverb_calc_color_filters( pColor_target_l, pColor_target_r, pTime_window, pState->fft_size, 0.0f, pFft_wf_filter_ch0, pFft_wf_filter_ch1 ); +#if 0 + Word32** pFft_wf_filter_ch0_fx = (Word32**)malloc(257 * sizeof(Word32*)); + + for (int i = 0; i < 257; i++) { + pFft_wf_filter_ch0_fx[i] = (Word32*)malloc(2 * sizeof(Word32)); + } + Word32** pFft_wf_filter_ch1_fx = (Word32**)malloc(257 * sizeof(Word32*)); + + for (int i = 0; i < 257; i++) { + pFft_wf_filter_ch1_fx[i] = (Word32*)malloc(2 * sizeof(Word32)); + } + Word32* pWindow_fx = (Word32*)malloc(RV_FILTER_MAX_FFT_SIZE * sizeof(Word32)); + + Word16 q_pFft_wf_filter_ch0_fx, q_pFft_wf_filter_ch1_fx; + + for (int i = 0; i < 257; i++) { + pFft_wf_filter_ch0_fx[i][0] = pFft_wf_filter_ch0[i][0] * 2147483648; + pFft_wf_filter_ch0_fx[i][1] = pFft_wf_filter_ch0[i][1] * 2147483648; + } + for (int i = 0; i < 257; i++) { + pFft_wf_filter_ch1_fx[i][0] = pFft_wf_filter_ch1_fx[i][0] * 2147483648; + pFft_wf_filter_ch1_fx[i][1] = pFft_wf_filter_ch1_fx[i][1] * 2147483648; + } + for (int i = 0; i < RV_FILTER_MAX_FFT_SIZE; i++) { + pWindow_fx[i] = pTime_window[i] * (1 << 30); + } + + Word32* pColor_target_l_fx = (Word32*)malloc(pState->fft_size * sizeof(Word32)); + Word32* pColor_target_r_fx = (Word32*)malloc(pState->fft_size * sizeof(Word32)); + for (int i = 0; i < RV_FILTER_MAX_FFT_SIZE; i++) { + pColor_target_l_fx[i] = pColor_target_l[i] * ONE_IN_Q30; + pColor_target_r_fx[i] = pColor_target_r[i] * ONE_IN_Q30; + } + ivas_reverb_calc_color_filters_fx(pColor_target_l_fx, pColor_target_r_fx, pWindow_fx, pState->fft_size, 0, pFft_wf_filter_ch0_fx, pFft_wf_filter_ch1_fx, &q_pFft_wf_filter_ch0_fx, &q_pFft_wf_filter_ch1_fx); + + for (int i = 0; i < 257; i++) { + pFft_wf_filter_ch0[i][0] = (float)pFft_wf_filter_ch0_fx[i][0] / (1u << q_pFft_wf_filter_ch0_fx); + pFft_wf_filter_ch0[i][1] = (float)pFft_wf_filter_ch0_fx[i][1] / (1u << q_pFft_wf_filter_ch0_fx); + } + + for (int i = 0; i < 257; i++) { + pFft_wf_filter_ch1[i][0] = (float)pFft_wf_filter_ch1_fx[i][0] / (1u << q_pFft_wf_filter_ch1_fx); + pFft_wf_filter_ch1[i][1] = (float)pFft_wf_filter_ch1_fx[i][1] / (1u << q_pFft_wf_filter_ch1_fx); + } + + for (int i = 0; i < 257; i++) { + free(pFft_wf_filter_ch1_fx[i]); + free(pFft_wf_filter_ch0_fx[i]); + } + free(pFft_wf_filter_ch1_fx); + free(pFft_wf_filter_ch0_fx); + free(pWindow_fx); + free(pColor_target_r_fx); + free(pColor_target_l_fx); +#else + ivas_reverb_calc_color_filters( pColor_target_l, pColor_target_r, pTime_window, pState->fft_size, 0.0f, pFft_wf_filter_ch0, pFft_wf_filter_ch1 ); +#endif /* Copying the computed FFT colorations filters to the fft_filter components */ if ( ( error = set_color_fft_filter( pState, 0, pFft_wf_filter_ch0 ) ) != IVAS_ERR_OK ) { diff --git a/lib_rend/ivas_reverb_filter_design.c b/lib_rend/ivas_reverb_filter_design.c index a354276f9..a65cca31d 100644 --- a/lib_rend/ivas_reverb_filter_design.c +++ b/lib_rend/ivas_reverb_filter_design.c @@ -33,11 +33,13 @@ #include #include "options.h" #include "prot.h" +#include "prot_fx2.h" #include "ivas_prot_rend.h" #include #include #include #include "wmc_auto.h" +#include "control.h" /*------------------------------------------------------------------------------------------* @@ -46,7 +48,9 @@ #define STEP_LIMIT_PIVOT_FREQ ( 1000.0f ) /* Pivot (initial reference) frequency for response gradient limit */ #define RESPONSE_STEP_LIMIT_LF ( 4.0f ) /* Maximum step in dB per bin at low frequencies (< pivot frequency) */ +#define RESPONSE_STEP_LIMIT_LF_FX ( 536870912 ) /* Maximum step in dB per bin at low frequencies (< pivot frequency) */ #define RESPONSE_STEP_LIMIT_HF ( 1.5f ) /* Maximum step in dB per bin at high frequencies (> pivot frequency) */ +#define RESPONSE_STEP_LIMIT_HF_FX ( 1610612736 ) /* Maximum step in dB per bin at high frequencies (> pivot frequency) */ #define EPS ( 1e-30f ) @@ -187,7 +191,174 @@ static void calc_min_phase( return; } +static void calc_min_phase_fx( + Word32 **pSpectrum, + const Word16 fft_size, + Word32 *pMinPhase, + Word16 *q_pCepstrum +) +{ + Word16 idx; + const Word16 half_fft_size = shr(fft_size, 1); + const Word16 log2_fft_size = int_log2(fft_size); + const Word16 spectrum_size = add(half_fft_size, 1); + const Word16 cepstrum_smoothing_extent = shr(fft_size, 3); + + Word32 pCepstrum[RV_FILTER_MAX_FFT_SIZE]; + Word32 pFolded_cepstrum_re[RV_FILTER_MAX_FFT_SIZE]; + Word32 pFolded_cepstrum_im[RV_FILTER_MAX_FFT_SIZE]; + Word32 pFolded_cepstrum_smoothing_win[RV_FILTER_MAX_FFT_SIZE]; + Word16 angle_increment; + Word16 initial_angle; + Word32 scale_factor; + + IF(EQ_16(fft_size, 512)) + { + scale_factor = 4194304; /* q = 31, 1.0f / (float)512 */ + move32(); + } + ELSE + { + scale_factor = 8388608; /* q = 31, 1.0f / (float)256 */ + move32(); + } + + + /* Prepare the smoothing window. Portion of the pCepstrum that will be smoothed out by a window to prevent aliasing. */ + + /* The first portion of the pCepstrum is kept unchanged */ + FOR(idx = 0; idx < half_fft_size - cepstrum_smoothing_extent; idx++) + { + pFolded_cepstrum_smoothing_win[idx] = ONE_IN_Q31; move32(); + } + + /* Adding Hann half-window for smooth transition */ + + Word16 s1 = sub(norm_s(shr(EVS_PI_FX, 1)), 1); + Word16 s2 = norm_s(sub(shl(cepstrum_smoothing_extent, 1), 1)); + Word16 var1 = shl(EVS_PI_FX, s1); + Word16 var2 = shl(sub(shl(cepstrum_smoothing_extent, 1), 1), s2); + angle_increment = div_s(shr(var1, 5), var2); //q = 15 + + /* Initial angle set to match Hann window alignment in Matlab */ + + initial_angle = shr(add((EVS_PI_FX), shr(angle_increment, 2)), 1); // q = 13 + + FOR(idx = 0; idx < cepstrum_smoothing_extent; idx++) + { + const Word16 sine_value = getSineWord16R2(mult(add(initial_angle, shl(mult(shl(idx, 8), angle_increment), 5)), 20858)); + + pFolded_cepstrum_smoothing_win[idx + half_fft_size - cepstrum_smoothing_extent] = L_mult(sine_value, sine_value); //q31 + } + + /* Padding the rest with zeros */ + FOR(idx = half_fft_size; idx < fft_size; idx++) + { + pFolded_cepstrum_smoothing_win[idx] = 0; move32(); + } + + /* Compute the log amplitude spectrum */ + FOR(idx = 0; idx < spectrum_size; idx++) + { + pCepstrum[idx] = Mpy_32_32(L_add(BASOP_Util_Log2(L_add(Mpy_32_32(pSpectrum[idx][0], pSpectrum[idx][0]), Mpy_32_32(pSpectrum[idx][1], pSpectrum[idx][1]))), L_shl(0, 25)), LN_2_Q31); /* log2 = 0.693147, q = 31, value = 1488521848 */ //q =26 + } + + /* Extending one-sided spectrum to double-sided one */ + FOR(idx = spectrum_size; idx < fft_size; idx++) + { + pCepstrum[idx] = pCepstrum[fft_size - idx]; move32(); + } + Word16 guarded_bits; + guarded_bits = find_guarded_bits_fx(fft_size); + *q_pCepstrum = sub(L_norm_arr(pCepstrum, fft_size), guarded_bits); + + FOR(Word16 j = 0; j < fft_size; j++) + { + pCepstrum[j] = L_shl(pCepstrum[j], *q_pCepstrum); + } + *q_pCepstrum = add(*q_pCepstrum,26); + /* Compute the real pCepstrum of the log amplitude spectrum */ + fft_rel_fx32(pCepstrum, fft_size, log2_fft_size); + + /* Note: using real-input fft rather than cmplx ifft to ensure support for 1024 size */ + /* Extra scaling is though required on the real/img parts, and img part is later inverted */ + + FOR(idx = 0; idx < fft_size; idx++) + { + pCepstrum[idx] = Mpy_32_32(pCepstrum[idx], scale_factor); //q = q_pCepstrum + } +#if 0 + guarded_bits = L_norm_arr(pCepstrum, fft_size); + FOR(Word16 j = 0; j < fft_size; j++) + { + pCepstrum[j] = L_shl(pCepstrum[j], guarded_bits - 3); + } + q_pCepstrum += guarded_bits - 3; +#endif + /* Fold the pCepstrum to ensure that zeros outside the unit circle move inside it, making it minimum phase. */ + pFolded_cepstrum_re[0] = pCepstrum[0]; move32(); + pFolded_cepstrum_im[0] = 0; move32(); + + FOR(idx = 1; idx < half_fft_size; idx++) + { + pFolded_cepstrum_re[idx] = L_shl(pCepstrum[idx], 1);//q = q_pCepstrum + pFolded_cepstrum_im[idx] = L_negate(L_shl(pCepstrum[fft_size - idx], 1));//q = q_pCepstrum + /* Note: sign inverted because of fft rather than ifft used before */ + } + pFolded_cepstrum_re[half_fft_size] = pCepstrum[half_fft_size]; //q = q_pCepstrum + move32(); + pFolded_cepstrum_im[half_fft_size] = 0; + move32(); + + FOR(idx = spectrum_size; idx < fft_size; idx++) + { + pFolded_cepstrum_re[idx] = 0; move32(); + pFolded_cepstrum_im[idx] = 0; move32(); + } + + /* Smoothing out the folded pCepstrum, to remove discontinuity at Ns, + hoping to significantly reduce the secondary response in the minimum-phase IR */ + FOR(idx = 0; idx < fft_size; idx++) + { + pFolded_cepstrum_re[idx] = Mpy_32_32(pFolded_cepstrum_re[idx], pFolded_cepstrum_smoothing_win[idx]); // q = q_pCepstrum + pFolded_cepstrum_im[idx] = Mpy_32_32(pFolded_cepstrum_im[idx], pFolded_cepstrum_smoothing_win[idx]); // q = q_pCepstrum + } + + /* Convert back and isolate the phase. */ + IF(LE_16(fft_size, 512)) /* for size <= 512 using complex-value FFT (more effecient, but available only up to 512 size) */ + { + DoRTFTn_fx_ivas(pFolded_cepstrum_re, pFolded_cepstrum_im, fft_size); + //guarded_bits = L_norm_arr(pFolded_cepstrum_im, fft_size); +#if 0 + FOR(Word16 j = 0; j < fft_size; j++) + { + pFolded_cepstrum_im[j] = L_shl(pFolded_cepstrum_im[j], 30 - *q_pCepstrum); + } +#endif + /* Copying the img part into the output */ + FOR(idx = 1; idx < half_fft_size; idx++) + { + pMinPhase[idx] = pFolded_cepstrum_im[idx]; move32(); + } + } + ELSE /* for fft_size > 512 using real-values FFT twice (for real + imag parts) */ + { + /* Real part */ + fft_rel_fx32(pFolded_cepstrum_re, fft_size, log2_fft_size); + /* Imag part */ + fft_rel_fx32(pFolded_cepstrum_im, fft_size, log2_fft_size); + + /* Copying the img part into the output */ + FOR(idx = 1; idx < half_fft_size; idx++) + { + pMinPhase[idx] = L_add(pFolded_cepstrum_re[fft_size - idx], pFolded_cepstrum_im[idx]); + } + } + pMinPhase[0] = 0; move32(); + pMinPhase[half_fft_size] = 0; move32(); + return; +} /*-------------------------------------------------------------------* * calc_min_phase_filter() * @@ -226,7 +397,38 @@ static void calc_min_phase_filter( return; } - +static void calc_min_phase_filter_fx( + Word32 **pH_flt, + const Word16 fft_size, + Word16 delay) +{ + const Word16 spectrum_size = add(shr(fft_size, 1), 1); + Word16 idx; + Word16 phase_increment; + Word32 pMin_phase[RV_FILTER_MAX_FFT_SIZE]; + + phase_increment = 0; // delay is 0.0, -PI2 * delay / (float)fft_size; + move16(); + Word16 q_pMin_phase; + calc_min_phase_fx(pH_flt, fft_size, pMin_phase, &q_pMin_phase); + + FOR(idx = 0; idx < spectrum_size; idx++) + { + /* Cancel out initial phase by computing amplitude */ + /* Note: slightly different (but mathematically equivalent) approach used for better efficiency */ + Word16 exp = 0; //31-31 + move16(); + Word32 current_ampl = Sqrt32(L_add(Mpy_32_32(pH_flt[idx][0], pH_flt[idx][0]), Mpy_32_32(pH_flt[idx][1], pH_flt[idx][1])), &exp); // q = 31 -exp == 31 + current_ampl = L_shl(current_ampl, exp); + /* Using the phase computed by calc_min_phase() + additional delay */ + + /* Apply the computed phase */ + pH_flt[idx][0] = Mpy_32_16_1(current_ampl, getCosWord16R2(mult(abs_s((Word16)L_shr(pMin_phase[idx], sub(q_pMin_phase, 13))), 20858))); //shifting right for next function. + pH_flt[idx][1] = Mpy_32_16_1(current_ampl, getSineWord16R2(mult((Word16)L_shr(pMin_phase[idx], sub(q_pMin_phase, 13)), 20858))); + } + + return; +} /*-------------------------------------------------------------------* * apply_window_fft() * @@ -281,7 +483,77 @@ static void apply_window_fft( return; } - +static void apply_window_fft_fx( + Word32 **pH_flt, + const Word32 *pWindow, + const Word16 fft_size, + Word16 *q_pFilter +) +{ + Word16 idx; + Word32 pFilter[RV_FILTER_MAX_FFT_SIZE]; + const Word16 half_fft_size = shr(fft_size, 1); + const Word16 log2_fft_size = int_log2(fft_size); + + /* Converting pFilter to ifft function input format */ + /* Real parts */ + FOR(idx = 0; idx <= half_fft_size; idx++) + { + pFilter[idx] = pH_flt[idx][0]; move32(); + } + /* Img parts */ + FOR(idx = 1; idx < half_fft_size; idx++) + { + pFilter[fft_size - idx] = pH_flt[idx][1]; move32(); + } + *q_pFilter = 31; + /* Do inverse fft to go to the time domain */ + Word16 guarded_bits, temp; + guarded_bits = find_guarded_bits_fx(fft_size); + temp = sub(L_norm_arr(pFilter, fft_size), guarded_bits); + IF(temp < 0) + { + FOR(Word16 j = 0; j < fft_size; j++) + { + pFilter[j] = L_shl(pFilter[j], temp); + } + *q_pFilter = add(*q_pFilter, temp); + } + + ifft_rel_fx32(pFilter, fft_size, log2_fft_size); + + /* Apply the window in the time domain */ + FOR(idx = 0; idx < fft_size; idx++) + { + pFilter[idx] = Mpy_32_32(pWindow[idx], pFilter[idx]); //q = q_pFilter + 30 - 31 + } + *q_pFilter = add(*q_pFilter, sub(30, 31)); + /* Convert back to the frequency domain */ + temp = sub(L_norm_arr(pFilter, fft_size), guarded_bits); + IF(LT_16(temp, 0)) + { + FOR(Word16 j = 0; j < fft_size; j++) + { + pFilter[j] = L_shl(pFilter[j], temp); + } + *q_pFilter = add(*q_pFilter, temp); + } + + fft_rel_fx32(pFilter, fft_size, log2_fft_size); //q = q_pFilter + + /* Copy data to the output with format conversion */ + pH_flt[0][0] = pFilter[0]; move32(); + pH_flt[half_fft_size][0] = pFilter[half_fft_size]; move32(); + pH_flt[0][1] = 0; move32(); + pH_flt[half_fft_size][1] = 0; move32(); + FOR(idx = 1; idx < half_fft_size; idx++) + { + pH_flt[idx][0] = pFilter[idx]; move32(); + pH_flt[idx][1] = pFilter[fft_size - idx]; move32(); + } + + return; +} /*-------------------------------------------------------------------* * response_step_limit() * @@ -349,6 +621,92 @@ static void response_step_limit( return; } +static void response_step_limit_fx( + Word32 *X, + const Word16 dim_x, + const Word32 step_limit_lf_dB, + const Word32 step_limit_hf_dB, + const Word16 pivot_bin_idx) +{ + Word16 i; + const Word32 positive_step_limit_lf = 1701766107; //powf(10.0f, 0.05f * step_limit_lf_dB) = 1.5848931924611134852; //q = 30 + const Word32 negative_step_limit_lf = 677485289; // 1.0f / positive_step_limit_lf = 0.63095734448019324;//q = 30 + const Word32 positive_step_limit_hf = 1276144549; // powf(10.0f, 0.05f * step_limit_hf_dB) = 1.188502227437018437; //q = 30 + const Word32 negative_step_limit_hf = 903441154; // 1.0f / positive_step_limit_hf = 1.26209271246779263; //q = 30 + + /* Go up from pivot frequency and limit the slope to the maximum given by T. */ + FOR(i = pivot_bin_idx + 1; i < dim_x; i++) + { + Word16 div_e; + Word32 desiredChange = L_deposit_h((BASOP_Util_Divide3232_Scale(X[i], X[i - 1], &div_e))); + Word16 desiredChange_q =sub( 31, (div_e)); + Word64 temp; + IF(GT_16(desiredChange_q, 30)) + { + desiredChange = L_shr(desiredChange, desiredChange_q - 30); + desiredChange_q = 30; move16(); + } + Word32 change = L_abs(desiredChange); + + IF(GE_32(X[i], X[i - 1])) + { + IF(GT_32(change, L_shr(positive_step_limit_hf, 30 - desiredChange_q))) + { + change = positive_step_limit_hf; // q = 30; + move32(); + temp = W_mult0_32_32(X[i - 1], change); + X[i] = (Word32)W_shr(temp, 30); + } + } + ELSE + { + IF(LT_32(change, L_shr(negative_step_limit_hf, 30 - desiredChange_q))) + { + change = negative_step_limit_hf; // q = 30; + move32(); + temp = W_mult0_32_32(X[i - 1], change); + X[i] = (Word32)W_shr(temp, 30); + } + } + } + + /* Go down from pivot frequency and limit the slope to the maximum given by T. */ + FOR(i = pivot_bin_idx - 1; i >= 0; i--) + { + Word16 div_e; + Word32 desiredChange = L_deposit_h((BASOP_Util_Divide3232_Scale(X[i], X[i + 1], &div_e))); + Word16 desiredChange_q = sub(31, (div_e)); + Word64 temp; + IF(GT_16(desiredChange_q, 30)) + { + desiredChange = L_shr(desiredChange, desiredChange_q - 30); + desiredChange_q = 30; move16(); + } + Word32 change = L_abs(desiredChange); + + IF(GE_32(X[i], X[i + 1])) + { + IF(GT_32(change, L_shr(positive_step_limit_lf, 30 - desiredChange_q))) + { + change = positive_step_limit_lf; // q = 30; + move32(); + temp = W_mult0_32_32(X[i + 1], change); + X[i] = (Word32)W_shr(temp, 30); + } + } + ELSE + { + IF(LT_32(change, L_shr(negative_step_limit_lf, 30 - desiredChange_q))) + { + change = negative_step_limit_lf; // q = 30; + move32(); + temp = W_mult0_32_32(X[i + 1], change); + X[i] = (Word32)W_shr(temp, 30); + } + } + } + return; +} /*-------------------------------------------------------------------* * ivas_reverb_define_window_fft() @@ -395,6 +753,50 @@ void ivas_reverb_define_window_fft( return; } +void ivas_reverb_define_window_fft_fx( + Word32 *pWindow, //output in Q31 + const Word16 transitionStart, + const Word16 transitionLength, + const Word16 spectrumLength) +{ + Word16 idx, fftLength; + Word16 angle_increment; + Word16 initial_angle; + + fftLength = shl(sub(spectrumLength, 1), 1); + + /* The first portion of the sequence is kept unchanged, window == 1 */ + FOR(idx = 0; idx < transitionStart; idx++) + { + pWindow[idx] = ONE_IN_Q31; //q31 + move32(); + } + + /* Adding Hann half-window for smooth transition */ + Word16 s1 = sub(norm_s(shr(EVS_PI_FX, 1)), 1); + Word16 s2 = norm_s(sub(shl(transitionLength, 1), 1)); + Word16 var1 = shl(EVS_PI_FX, s1); + Word16 var2 = shl(sub(shl(transitionLength, 1), 1), s2); + angle_increment = div_s(shr(var1, 5), var2); //q = 15 + + /* Initial angle set to match Hann window alignment in Matlab */ + initial_angle = shr(add((EVS_PI_FX), shr(angle_increment, 2)), 1); // q = 13 + + FOR(idx = 0; idx < transitionLength; idx++) + { + const Word16 sine_value = getSineWord16R2(mult(add(initial_angle, shl(mult(shl(idx, 8), angle_increment), 5)), 20858)); //q31 + + pWindow[idx + transitionStart] = L_mult(sine_value, sine_value); + } + + /* Padding the rest with zeros */ + FOR(idx = transitionStart + transitionLength; idx < fftLength; idx++) + { + pWindow[idx] = 0; move32(); + } + + return; +} /*-------------------------------------------------------------------* * apply_window_fft() * @@ -441,7 +843,46 @@ int16_t ivas_reverb_calc_color_filters( return 0; } +Word16 ivas_reverb_calc_color_filters_fx( + const Word32 *pTargetL, + const Word32 *pTargetR, + const Word32 *pWindow, + const Word16 fft_size, + const Word16 delay, + Word32 **pBeqL, + Word32 **pBeqR, + Word16 *q_pBeqL, + Word16 *q_pBeqR +) +{ + Word16 idx, half_fft_size; + + half_fft_size = shr(fft_size, 1); + FOR(idx = 0; idx <= half_fft_size; idx++) + { + pBeqL[idx][0] = pTargetL[idx]; move32(); + pBeqL[idx][1] = 0; move32(); + pBeqR[idx][0] = pTargetR[idx]; move32(); + pBeqR[idx][1] = 0; move32(); + } + + /* Make the response minimum phase. Does make the spectrum complex, but + will avoid aliasing when applied in the FFT domain. */ + calc_min_phase_filter_fx(pBeqL, fft_size, delay); + calc_min_phase_filter_fx(pBeqR, fft_size, delay); + apply_window_fft_fx(pBeqL, pWindow, fft_size, q_pBeqL); + apply_window_fft_fx(pBeqR, pWindow, fft_size, q_pBeqR); + + FOR(idx = 0; idx <= half_fft_size; idx++) + { + IF(LT_32(pTargetL[idx], 0) || LT_32(pTargetR[idx], 0)) /* Shouldn't have negative gains. */ + { + return 1; + } + } + return 0; +} /*-------------------------------------------------------------------* * ivas_reverb_calc_correl_filters() * @@ -486,7 +927,55 @@ int16_t ivas_reverb_calc_correl_filters( return 0; } +Word16 ivas_reverb_calc_correl_filters_fx( + Word32 *pTargetICC, //input in Q30 + const Word32 *pWindow, //input in Q30 + const Word16 fft_size, + const Word16 delay, + Word32 **pU, //input in Q31 + Word32 **pV, //input in Q31 + Word16 *q_pU, //Output q + Word16 *q_pV //output q +) +{ + Word16 idx, half_fft_size; + + half_fft_size = shr(fft_size, 1); + FOR(idx = 0; idx <= half_fft_size; idx++) + { + IF(LT_32(pTargetICC[idx], L_negate(ONE_IN_Q30)) || LT_32(ONE_IN_Q30, pTargetICC[idx])) /* Shouldn't have negative gains. */ + { + return 1; + } + } + Word16 temp; + FOR(idx = 0; idx <= half_fft_size; idx++) + { + temp = 1; move32(); + pU[idx][0] = Sqrt32(L_shr(L_add(ONE_IN_Q30, pTargetICC[idx]), 1), &temp); + IF(temp) + { + pU[idx][0] = L_shl(pU[idx][0], temp); + } + pU[idx][1] = 0; move32(); + temp = 1; move32(); + pV[idx][0] = Sqrt32(L_shr(L_sub(ONE_IN_Q30, pTargetICC[idx]), 1), &temp); + IF(temp) + { + pV[idx][0] = L_shl(pV[idx][0], temp); + } + pV[idx][1] = 0; move32(); + } + + /* Make the response minimum phase. Does make the spectrum complex, but + will avoid aliasing when applied in the FFT domain. */ + calc_min_phase_filter_fx(pU, fft_size, delay); + calc_min_phase_filter_fx(pV, fft_size, delay); + apply_window_fft_fx(pU, pWindow, fft_size, q_pU); + apply_window_fft_fx(pV, pWindow, fft_size, q_pV); + return 0; +} /*-------------------------------------------------------------------* * ivas_reverb_calc_color_levels() * @@ -593,7 +1082,145 @@ void ivas_reverb_calc_color_levels( return; } +void ivas_reverb_calc_color_levels_fx( + const Word32 output_Fs, + const Word16 freq_count, + const Word16 loop_count, + const Word32 *pFc, //input in Q14 + const Word32 *pAcoustic_dsr, //input in Q31 + const Word32 *pHrtf_avg_pwr_L, //input in Q28 + const Word32 *pHrtf_avg_pwr_R, //input in Q28 + const Word16 *pLoop_delays, + const Word32 *pT60_filter_coeff, //input in Q31 + Word32 *pTarget_color_L, //output in Q30 + Word32 *pTarget_color_R) //output in Q30 +{ + Word16 i, freq_idx, idx_pivot, nrcoefs, loop_idx; + Word32 t60[RV_LENGTH_NR_FC]; + Word16 t60_e[RV_LENGTH_NR_FC + 1]; + + /* Pre-computing inverse values for optimisation (to avoid divisions in inner loops) */ + Word16 fs_inverted_q; + const Word32 fs_inverted = BASOP_Util_Divide3232_Scale(ONE_IN_Q11, L_shl(output_Fs, 11), &fs_inverted_q); // q= 15 - fs_inverted_q = 29 + const Word32 loop_count_inverted = divide3232(ONE_IN_Q27, L_shl(loop_count, 27)); // q= 15; + + const Word32 log__0_001 = -1854286438; //logf( 0.001f ) in q28 + move32(); + /* Pre-computed for better efficiency */ + + /* revEnergyFactor == 1 for IVAS, as the pDsr values are already scaled previously for predelay delta */ + /* Computing minimum delays in a simpler way, as they are already provided in descending order */ + const Word16 minDelay = pLoop_delays[loop_count - 1]; move32(); + const Word16 minDelayDiff = sub(pLoop_delays[loop_count - 2], pLoop_delays[loop_count - 1]); + + FOR(freq_idx = 0; freq_idx < freq_count; freq_idx++) + { + t60[freq_idx] = 0; move32(); + t60_e[freq_idx] = 31; move16(); + } + + FOR(loop_idx = 0; loop_idx < loop_count; loop_idx++) + { + Word32 coefA[2]; + Word32 coefB[2]; + + nrcoefs = 2; move16(); + /* for pFilter order == 1 */ + + /* Obtaining T60 filters coefficients for the current loop */ + FOR(i = 0; i < nrcoefs; i++) + { + coefA[i] = pT60_filter_coeff[add(i_mult(shl(nrcoefs, 1), loop_idx), add(i, nrcoefs))]; // q = 31 + coefB[i] = pT60_filter_coeff[add(i_mult(shl(nrcoefs, 1), loop_idx), i)]; // // q = 31 + } + t60_e[freq_count] = -100; move16(); + /* Loop over frequencies */ + FOR(freq_idx = 0; freq_idx < freq_count; freq_idx++) + { + /* Compute T60 pFilter gain at the given frequency */ + Word32 cos_w; + Word32 H_filter; + Word32 T60_est; + Word16 temp = 0, result_e = 0; move16(); move16(); + cos_w = getCosWord16R2((Word16)abs(L_shl(Mpy_32_32(pFc[freq_idx], fs_inverted), 3))); // q = 15 + H_filter = L_add(L_shr(L_add(L_shr(Mpy_32_32(coefB[0], coefB[0]), 1), L_shr(Mpy_32_32(coefB[1], coefB[1]), 1)), 2), L_shr(Mpy_32_32(coefB[0], Mpy_32_32(coefB[1], L_shl(cos_w, 15))), 1)); //q = 28 + H_filter = BASOP_Util_Divide3232_Scale(H_filter, L_add(ONE_IN_Q28, L_shr(L_add(L_shr(Mpy_32_32(coefA[1], coefA[1]), 2), Mpy_32_32(coefA[1], L_shl(cos_w, 15))), 1)), &temp); + H_filter = Sqrt32(L_shl(H_filter, 16), &temp); + T60_est = BASOP_Util_Divide3232_Scale(L_shl(i_mult(-3, pLoop_delays[loop_idx]), 2), Mpy_32_32(Mpy_32_32(L_add(BASOP_Util_Log2(H_filter), L_shl(temp, 25)), LOG10_2), L_shl(output_Fs, 8)), &temp);//conversion of log2 to log10. + T60_est = L_shl(T60_est, 16); + t60[freq_idx] = BASOP_Util_Add_Mant32Exp(T60_est, temp, t60[freq_idx], t60_e[freq_idx], &result_e); + t60_e[freq_idx] = result_e; + t60_e[freq_count] = max(result_e, t60_e[freq_count]); + } + FOR(freq_idx = 0; freq_idx < freq_count; freq_idx++) + { + t60[freq_idx] = L_shr(t60[freq_idx], t60_e[freq_count] - t60_e[freq_idx]); + t60_e[freq_idx] = t60_e[freq_count]; + } + } + + /* Dividing by the number of loops to compute the average T60 estimate */ + FOR(freq_idx = 0; freq_idx < freq_count; freq_idx++) + { + t60[freq_idx] = Mpy_32_32(t60[freq_idx], L_shl(loop_count_inverted, 16)); + } + + Word16 *pTarget_color_L_e = (Word16*)malloc(257 * sizeof(Word16)); + Word16 *pTarget_color_R_e = (Word16*)malloc(257 * sizeof(Word16)); + /* Compute target gains on the basis of the estimated T60 values */ + FOR(freq_idx = 0; freq_idx < freq_count; freq_idx++) + { + Word16 temp, temp1, temp2, temp3 = 0, temp4, temp5; move32(); + Word32 var1 = divide3232((Word32)i_mult(-6, minDelay), L_shr(Mpy_32_32(t60[freq_idx], L_shl(output_Fs, 11)), 11 - t60_e[freq_idx])); + var1 = L_mult((Word16)var1, LOG2_10); // q = 29 + Word32 A0_square_est = BASOP_util_Pow2(var1, 31 - 29, &temp); + Word16 alpha_e; + Word16 alpha = BASOP_Util_Divide3232_Scale(-log__0_001, t60[freq_idx], &alpha_e);//alpha_e = 1 + alpha_e + (3 - t60_e[257]) + + Word16 div11 = BASOP_Util_Divide3216_Scale(A0_square_est, alpha, &temp1); //e = temp1 + (temp - alpha_e) + Word32 div2 = BASOP_Util_Divide3232_Scale(L_shl(output_Fs, 11), L_shr(L_add(Mpy_32_16_1(1884631649, shl(minDelayDiff, 3)), 14037339), 8), &temp2); //e = temp2, 26.7741 in Q19, 0.8776 in Q31 + + const Word32 revPredNormEnergy = Mpy_32_16_1(L_shl(div2, 16), div11);//q = (15 - temp2) + (15 - temp1) - 15 + 1 + //L_max + Word32 div1; + temp3 = add(add(temp1, sub(temp, add(1, add(alpha_e, sub(3, t60_e[freq_count]))))), temp2); + div1 = L_max(Sqrt32(revPredNormEnergy, &temp3), 1); + temp4 = 3; + div2 = Sqrt32(Mpy_32_32(pAcoustic_dsr[freq_idx], pHrtf_avg_pwr_L[freq_idx]), &temp4); + pTarget_color_L[freq_idx] = (Word32)BASOP_Util_Divide3232_Scale(div2, div1, &temp5); + temp5 = add(temp5, sub(temp4, temp3)); + pTarget_color_L_e[freq_idx] = temp5; move16(); + + temp3 = add(add(temp1, sub(temp, add(1, add(alpha_e, sub(3, t60_e[freq_count]))))), temp2); + div1 = L_max(Sqrt32(revPredNormEnergy, &temp3), 1); + temp4 = 3; move16(); + div2 = Sqrt32(Mpy_32_32(pAcoustic_dsr[freq_idx], pHrtf_avg_pwr_R[freq_idx]), &temp4); + pTarget_color_R[freq_idx] = BASOP_Util_Divide3232_Scale(div2, div1, &temp5); + temp5 = add(temp5, sub(temp4, temp3)); + pTarget_color_R_e[freq_idx] = temp5; move16(); + } + FOR(freq_idx = 0; freq_idx < freq_count; freq_idx++) + { + pTarget_color_R[freq_idx] = L_shr(L_shl(pTarget_color_R[freq_idx], 16), sub(1, pTarget_color_R_e[freq_idx]));// (31 - pTarget_color_R_e[freq_idx]) - 30 + pTarget_color_L[freq_idx] = L_shr(L_shl(pTarget_color_L[freq_idx], 16), sub(1, pTarget_color_L_e[freq_idx]));// (31 - pTarget_color_L_e[freq_idx]) - 30 + } + /* Limiting the frequency response gradients + Find frequency band closest to chosen pivot frequency. */ + Word32 div1; + Word16 temp = 0; move16(); + div1 = BASOP_Util_Divide3232_Scale(L_mult0(1000, sub(freq_count, 1)), L_shr(output_Fs, 1), &temp); + div1 = BASOP_Util_Add_Mant32Exp(L_shl(div1, 16), temp, ONE_IN_Q30, 1, &temp); + idx_pivot = (Word16)L_shr(div1, sub(31, temp)); + /* Perform step limiting */ + + response_step_limit_fx(pTarget_color_L, freq_count, RESPONSE_STEP_LIMIT_LF_FX, RESPONSE_STEP_LIMIT_HF_FX, idx_pivot); + response_step_limit_fx(pTarget_color_R, freq_count, RESPONSE_STEP_LIMIT_LF_FX, RESPONSE_STEP_LIMIT_HF_FX, idx_pivot); + + free(pTarget_color_L_e); + free(pTarget_color_R_e); + return; +} /*-------------------------------------------------------------------* * ivas_reverb_interpolate_acoustic_data() * @@ -651,7 +1278,67 @@ void ivas_reverb_interpolate_acoustic_data( return; } - +void ivas_reverb_interpolate_acoustic_data_fx( + const Word16 input_table_size, + const Word32 *pInput_fc, //input in Q16 + const Word32 *pInput_t60, //input in Q26 + const Word32 *pInput_dsr, //input in Q30 + const Word16 output_table_size, + const Word32 *pOutput_fc, + Word32 *pOutput_t60, + Word32 *pOutput_dsr, + Word16 *pOutput_t60_e, //output e + Word16 *pOutput_dsr_e //output e +) +{ + Word16 input_idx, output_idx; + Word32 rel_offset; + Word16 rel_offset_e; + input_idx = 0; + + FOR(output_idx = 0; output_idx < output_table_size; output_idx++) + { + /* if the bin frequency is lower than the 1st frequency point in the input table, take this 1st point */ + IF(LT_32(pOutput_fc[output_idx], pInput_fc[0])) + { + input_idx = 0; move16(); + rel_offset = 0; move32(); + rel_offset_e = 0; move16(); + } + ELSE + { + /* if the bin frequency is higher than the last frequency point in the input table, take this last point */ + IF(GT_32(pOutput_fc[output_idx], pInput_fc[input_table_size - 1])) + { + input_idx = sub(input_table_size, 2); + rel_offset = ONE_IN_Q30; //Q30; + move32(); + rel_offset_e = 1; move16(); + } + /* otherwise use linear interpolation between 2 consecutive points in the input table */ + ELSE + { + WHILE(GT_32(pOutput_fc[output_idx], pInput_fc[input_idx + 1])) + { + input_idx++; + } + rel_offset = BASOP_Util_Divide3232_Scale(L_sub(pOutput_fc[output_idx], pInput_fc[input_idx]), L_sub(pInput_fc[input_idx + 1], pInput_fc[input_idx]), &rel_offset_e); //q15 + rel_offset = L_shl(rel_offset, 16); + } + } + Word32 mult1; + Word16 mult_e = 0; move16(); + mult1 = Mpy_32_32(rel_offset, L_sub(pInput_t60[input_idx + 1], pInput_t60[input_idx])); + pOutput_t60[output_idx] = BASOP_Util_Add_Mant32Exp(pInput_t60[input_idx], 5, mult1, add(5, rel_offset_e), &mult_e);//31 - (31 - rel_offset_e + 26 - 31) + pOutput_t60_e[output_idx] = mult_e; move16(); + + mult1 = Mpy_32_32(rel_offset, L_sub(pInput_dsr[input_idx + 1], pInput_dsr[input_idx])); + pOutput_dsr[output_idx] = BASOP_Util_Add_Mant32Exp(pInput_dsr[input_idx], 1, mult1, add(1, rel_offset_e), &mult_e);//31 - (31 - rel_offset_e + 26 - 31) + pOutput_dsr_e[output_idx] = mult_e; move16(); + } + + return; +} /*-------------------------------------------------------------------* * ivas_reverb_get_hrtf_set_properties() * @@ -827,3 +1514,194 @@ void ivas_reverb_get_hrtf_set_properties( return; } + +void ivas_reverb_get_hrtf_set_properties_fx( + Word32 **ppHrtf_set_L_re, + Word32 **ppHrtf_set_L_im, + Word32 **ppHrtf_set_R_re, + Word32 **ppHrtf_set_R_im, + const AUDIO_CONFIG input_audio_config, + const Word16 hrtf_count, + const Word16 in_freq_count, + const Word16 out_freq_count, + Word32 *pOut_avg_pwr_L, //output in Q23 + Word32 *pOut_avg_pwr_R, //output in Q23 + Word32 *out_i_a_coherence) //output in Q27 +{ + const Word16 foa_sum_coeffs[4][3] = { + { MAX_WORD16, MAX_WORD16, 0 }, + { MAX_WORD16, -MAX_WORD16, 0 }, + { MAX_WORD16, 0, MAX_WORD16 }, + { MAX_WORD16, 0, -MAX_WORD16 } + }; + const Word32 inp_freq_step = divide3232(ONE_IN_Q22, L_shl(in_freq_count, 23)); // q= 15 + const Word32 inp_freq_offset = L_shr(inp_freq_step, 1); // q= 15 + const Word16 out_freq_step = divide3232(ONE_IN_Q21, L_shl(L_sub(out_freq_count, 1), 22)); //q = 15 + + Word16 hrtf_count_inverted, used_hrtf_count, freq_idx, hrtf_idx, out_bin_idx, ch_index, is_ambisonics; + Word32 relative_pos, weight_1st, base_idx; + Word32 avg_pwr_left[2]; + Word32 avg_pwr_right[2]; + Word32 IA_coherence[2]; + + IF(input_audio_config == IVAS_AUDIO_CONFIG_FOA || input_audio_config == IVAS_AUDIO_CONFIG_HOA2 || input_audio_config == IVAS_AUDIO_CONFIG_HOA3) + { + is_ambisonics = 1; move16(); + used_hrtf_count = 4; /* Using only 1st order HRTFs */ + move16(); + } + ELSE + { + is_ambisonics = 0; move16(); + used_hrtf_count = hrtf_count; move16(); + } + + /* Interpolation (linear to a new grid) */ + base_idx = 0; move32(); + relative_pos = 0; move32(); + hrtf_count_inverted = divide1616(ONE_IN_Q11, shl(used_hrtf_count, 11)); //q = 15 + + /* Loop over output frequency bins */ + FOR(out_bin_idx = 0; out_bin_idx < out_freq_count; out_bin_idx++) + { + /* Computing normalized frequency for the current bin (1.0 corresponds to sampling rate) */ + + const Word32 norm_freq = L_mult(out_freq_step, shl(out_bin_idx, 5)); //q = 21 + + /* Computing the bin index in the source data */ + Word16 div_q = 0; move16(); + //Word32 tbl_index = BASOP_Util_Divide3232_Scale(L_sub(norm_freq , L_shl(inp_freq_offset, 6)), L_shl(inp_freq_step, 6), &div_q);//q =15 - div_q + Word32 tbl_index = Mpy_32_32(L_sub(norm_freq, L_shl(inp_freq_offset, 6)), L_shl(in_freq_count, 22)); //q = 11 + IF(LT_16(div_q, 0)) + { + tbl_index = L_shl(tbl_index, div_q); + div_q = 0; move16(); + } + IF(LE_32(tbl_index, 0)) /* In case of extrapolation (below 1st bin), choose nearest */ + { + base_idx = 0; move32(); + relative_pos = 0; move32(); + } + ELSE + { + base_idx = (tbl_index); //q = 21 + move32(); + relative_pos = L_shl(L_sub(tbl_index, L_shl(L_shr(base_idx, 11), 11)),20); //q = 31 + base_idx = L_shr(base_idx, 11); + IF(GT_32(base_idx, L_sub(in_freq_count, 2))) /* In case of extrapolation (above last bin), choose nearest */ + { + base_idx = L_sub(in_freq_count, 2); + relative_pos = ONE_IN_Q31; move32(); + } + } + + /* Computing 2 bins data for later interpolation */ + + /* Zeroing before accumalation for average value computing */ + avg_pwr_left[0] = 0; move32(); + avg_pwr_left[1] = 0; move32(); + avg_pwr_right[0] = 0; move32(); + avg_pwr_right[1] = 0; move32(); + IA_coherence[0] = 0; move32(); + IA_coherence[1] = 0; move32(); + + /* Get power spectra and cross - correlation between left and right hrtfs */ + /* Loop over all the HRTFs available */ + FOR(hrtf_idx = 0; hrtf_idx < used_hrtf_count; hrtf_idx++) + { + /* Pointers to current HRTF data */ + Word32 *current_base_L_ptr_re, *current_base_L_ptr_im, *current_base_R_ptr_re, *current_base_R_ptr_im; + + /* combined HRTF data used for FOA */ + Word32 combined_channels_L_re[2]; + Word32 combined_channels_L_im[2]; + Word32 combined_channels_R_re[2]; + Word32 combined_channels_R_im[2]; + + /* Process the frequency bins containing both real and img parts */ + /* In case of 5.1 or 7.1 formats, use the available HRTF paires directly*/ + IF(!is_ambisonics) + { + current_base_L_ptr_re = (ppHrtf_set_L_re[hrtf_idx] + base_idx); + current_base_R_ptr_re = (ppHrtf_set_R_re[hrtf_idx] + base_idx); + current_base_L_ptr_im = (ppHrtf_set_L_im[hrtf_idx] + base_idx); + current_base_R_ptr_im = (ppHrtf_set_R_im[hrtf_idx] + base_idx); + } + + /* In case of FOA format, combine the W channel with the X/Y channels */ + ELSE + { + FOR(freq_idx = 0; freq_idx < 2; freq_idx++) + { + combined_channels_L_re[freq_idx] = 0; + combined_channels_R_re[freq_idx] = 0; + combined_channels_L_im[freq_idx] = 0; + combined_channels_R_im[freq_idx] = 0; + + FOR(ch_index = 0; ch_index < 3; ch_index++) + { + combined_channels_L_re[freq_idx] = L_add(combined_channels_L_re[freq_idx], Mpy_32_16_1(ppHrtf_set_L_re[ch_index][base_idx + freq_idx], foa_sum_coeffs[hrtf_idx][ch_index])); + combined_channels_R_re[freq_idx] = L_add(combined_channels_R_re[freq_idx], Mpy_32_16_1(ppHrtf_set_R_re[ch_index][base_idx + freq_idx], foa_sum_coeffs[hrtf_idx][ch_index])); + combined_channels_L_im[freq_idx] = L_add(combined_channels_L_im[freq_idx], Mpy_32_16_1(ppHrtf_set_L_im[ch_index][base_idx + freq_idx], foa_sum_coeffs[hrtf_idx][ch_index])); + combined_channels_R_im[freq_idx] = L_add(combined_channels_R_im[freq_idx], Mpy_32_16_1(ppHrtf_set_R_im[ch_index][base_idx + freq_idx], foa_sum_coeffs[hrtf_idx][ch_index])); + } + } + + current_base_L_ptr_re = &combined_channels_L_re[0]; + current_base_R_ptr_re = &combined_channels_R_re[0]; + current_base_L_ptr_im = &combined_channels_L_im[0]; + current_base_R_ptr_im = &combined_channels_R_im[0]; + } + + FOR(freq_idx = 0; freq_idx < 2; freq_idx++) + { + Word32 L_re, L_im, R_re, R_im, C_re; + + L_re = current_base_L_ptr_re[freq_idx];//q = 29 + R_re = current_base_R_ptr_re[freq_idx];//q = 29 + L_im = current_base_L_ptr_im[freq_idx];//q = 29 + R_im = current_base_R_ptr_im[freq_idx];//q = 29 + move32(); move32(); move32(); move32(); + avg_pwr_left[freq_idx] = L_add(L_shr(L_add(Mpy_32_32(L_re, L_re), Mpy_32_32(L_im, L_im)), 4), avg_pwr_left[freq_idx]);//q = 23 + avg_pwr_right[freq_idx] = L_add(L_shr(L_add(Mpy_32_32(R_re, R_re), Mpy_32_32(R_im, R_im)), 4), avg_pwr_right[freq_idx]);//q = 23 + /* Cross product (Re part) */ + C_re = L_add(Mpy_32_32(L_re, R_re), Mpy_32_32(L_im, R_im));//q = 27 + + IA_coherence[freq_idx] = L_add(C_re, IA_coherence[freq_idx]);//q = 27 + } + } + + /* Compute the averages and the IA coherence */ + FOR(freq_idx = 0; freq_idx < 2; freq_idx++) + { + Word16 sqrt_exp = 0; + Word32 var1; + avg_pwr_left[freq_idx] = Mpy_32_16_1(avg_pwr_left[freq_idx], hrtf_count_inverted); //q = 23 + avg_pwr_right[freq_idx] = Mpy_32_16_1(avg_pwr_right[freq_idx], hrtf_count_inverted); //q = 23 + IF(EQ_32(avg_pwr_left[freq_idx], avg_pwr_right[freq_idx])) + { + var1 = avg_pwr_left[freq_idx]; move32(); + sqrt_exp = 4; move16(); + } + ELSE + { + var1 = Sqrt32(Mpy_32_32(avg_pwr_left[freq_idx], avg_pwr_right[freq_idx]), &sqrt_exp); move32(); + } + Word16 temp; + IA_coherence[freq_idx] = BASOP_Util_Divide3232_Scale(Mpy_32_16_1(IA_coherence[freq_idx], hrtf_count_inverted), L_shl(var1, sqrt_exp), &temp); //q =15 + IA_coherence[freq_idx] = L_shl(IA_coherence[freq_idx], 27 - (15 - temp));//q = 27 + /* Limiting to (0...1) range in case of small numerical errors or negative values */ + IA_coherence[freq_idx] = min(IA_coherence[freq_idx], ONE_IN_Q27); + IA_coherence[freq_idx] = max(IA_coherence[freq_idx], 0); + } + + /* Computing weighted average of 2 nearest values (1 below + 1 above) for linear interpolation */ + weight_1st = L_sub(ONE_IN_Q31, relative_pos); //q = 31 + + pOut_avg_pwr_L[out_bin_idx] = L_add(Mpy_32_32(weight_1st, avg_pwr_left[0]), Mpy_32_32(relative_pos, avg_pwr_left[1])); //q = 23 + pOut_avg_pwr_R[out_bin_idx] = L_add(Mpy_32_32(weight_1st, avg_pwr_right[0]), Mpy_32_32(relative_pos, avg_pwr_right[1])); //q = 23 + out_i_a_coherence[out_bin_idx] = L_add(Mpy_32_32(weight_1st, IA_coherence[0]), Mpy_32_32(relative_pos, IA_coherence[1])); //q = 27 + } + + return; +} \ No newline at end of file diff --git a/lib_rend/ivas_reverb_utils.c b/lib_rend/ivas_reverb_utils.c index 3790b0662..528f6c433 100644 --- a/lib_rend/ivas_reverb_utils.c +++ b/lib_rend/ivas_reverb_utils.c @@ -37,7 +37,7 @@ #include "ivas_rom_rend.h" #include #include "wmc_auto.h" - +#include "prot_fx2.h" /*-----------------------------------------------------------------------------------------* * Local constants @@ -95,9 +95,46 @@ ivas_error ivas_reverb_prepare_cldfb_params( { fc[idx] = ( (float) idx + 0.5f ) * ( (float) MAX_SAMPLING_RATE / (float) ( 2 * CLDFB_NO_CHANNELS_MAX ) ); } +#ifdef IVAS_FLOAT_FIXED + Word32* pFc_input_fx = (Word32*)malloc(60 * sizeof(Word32*)); + Word32* pAcoustic_rt60_fx = (Word32*)malloc(60 * sizeof(Word32*)); + Word32* pAcoustic_dsr_fx = (Word32*)malloc(60 * sizeof(Word32*)); + + Word32* fc_fx = (Word32*)malloc(pInput_params->nBands * sizeof(Word32*)); + Word32* pOutput_t60_fx = (Word32*)malloc(pInput_params->nBands * sizeof(Word32*)); + Word16* pOutput_t60_e = (Word16*)malloc(pInput_params->nBands * sizeof(Word16*)); + Word32* pOutput_ene_fx = (Word32*)malloc(pInput_params->nBands * sizeof(Word32*)); + Word16* pOutput_ene_e = (Word16*)malloc(pInput_params->nBands * sizeof(Word16*)); + + for (int i = 0; i < 60; i++) + { + pFc_input_fx[i] = (Word32)pInput_params->pFc_input[i] * ONE_IN_Q16; + pAcoustic_rt60_fx[i] = (Word32)(pInput_params->pAcoustic_rt60[i]) * ONE_IN_Q26; + pAcoustic_dsr_fx[i] = (Word32)pInput_params->pAcoustic_dsr[i] * ONE_IN_Q30; + } - ivas_reverb_interpolate_acoustic_data( pInput_params->nBands, pInput_params->pFc_input, pInput_params->pAcoustic_rt60, pInput_params->pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX, fc, pOutput_t60, pOutput_ene ); + for (int i = 0; i < pInput_params->nBands; i++) + { + fc_fx[i] = (Word32)fc[i] * ONE_IN_Q16; + } + ivas_reverb_interpolate_acoustic_data_fx(pInput_params->nBands, pFc_input_fx, pAcoustic_rt60_fx, pAcoustic_dsr_fx, + CLDFB_NO_CHANNELS_MAX, fc_fx, pOutput_t60_fx, pOutput_ene_fx, pOutput_t60_e, pOutput_ene_e); + for (int i = 0; i < pInput_params->nBands; i++) { + pOutput_t60[i] = (float)fabs(me2f(pOutput_t60_fx[i], pOutput_t60_e[i])); + pOutput_ene[i] = (float)fabs(me2f(pOutput_ene_fx[i], pOutput_ene_e[i])); + } + free(pFc_input_fx); + free(pAcoustic_rt60_fx); + free(pAcoustic_dsr_fx); + free(fc_fx); + free(pOutput_t60_fx); + free(pOutput_t60_e); + free(pOutput_ene_fx); + free(pOutput_ene_e); +#else + ivas_reverb_interpolate_acoustic_data( pInput_params->nBands, pInput_params->pFc_input, pInput_params->pAcoustic_rt60, pInput_params->pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX, fc, pOutput_t60, pOutput_ene ); +#endif /* adjust DSR for the delay difference */ delay_diff = pInput_params->inputPreDelay - pInput_params->acousticPreDelay; ln_1e6_inverted = 1.0f / logf( 1e06f ); @@ -507,8 +544,45 @@ static ivas_error ivas_reverb_get_fastconv_hrtf_set_energies( { return error; } +#ifdef IVAS_FLOAT_FIXED + Word32* input_fc_fx = (Word32*)malloc(60 * sizeof(Word32*)); + Word32* avg_pwr_left_fft_fx = (Word32*)malloc(60 * sizeof(Word32*)); + Word32* avg_pwr_right_fft_fx = (Word32*)malloc(60 * sizeof(Word32*)); + + Word32* output_fc_fx = (Word32*)malloc(257 * sizeof(Word32*)); + Word32* avg_pwr_left_fx = (Word32*)malloc(257 * sizeof(Word32*)); + Word16* avg_pwr_left_e = (Word16*)malloc(257 * sizeof(Word16*)); + Word32* avg_pwr_right_fx = (Word32*)malloc(257 * sizeof(Word32*)); + Word16* avg_pwr_right_e = (Word16*)malloc(257 * sizeof(Word16*)); + + for (int i = 0; i < 60; i++) + { + input_fc_fx[i] = (Word32)input_fc[i] * (1 << 16); + avg_pwr_left_fft_fx[i] = (Word32)(avg_pwr_left_fft[i]) * ONE_IN_Q26; + avg_pwr_right_fft_fx[i] = (Word32)avg_pwr_right_fft[i] * ONE_IN_Q30; + } - ivas_reverb_interpolate_acoustic_data( FFT_SPECTRUM_SIZE, input_fc, avg_pwr_left_fft, avg_pwr_right_fft, CLDFB_NO_CHANNELS_MAX, output_fc, avg_pwr_left, avg_pwr_right ); + for (int i = 0; i < 257; i++) + { + output_fc_fx[i] = (Word32)input_fc[i] * ONE_IN_Q16; + } + ivas_reverb_interpolate_acoustic_data_fx(FFT_SPECTRUM_SIZE, input_fc_fx, avg_pwr_left_fft_fx, avg_pwr_right_fft_fx, + CLDFB_NO_CHANNELS_MAX, output_fc_fx, avg_pwr_left_fx, avg_pwr_right_fx, avg_pwr_left_e, avg_pwr_right_e); + for (int i = 0; i < 257; i++) { + avg_pwr_left[i] = (float)fabs(me2f(avg_pwr_left_fx[i], avg_pwr_left_e[i])); + avg_pwr_right[i] =(float)fabs(me2f(avg_pwr_right_fx[i], avg_pwr_right_e[i])); + } + free(input_fc_fx); + free(avg_pwr_left_fft_fx); + free(avg_pwr_right_fft_fx); + free(output_fc_fx); + free(avg_pwr_left_fx); + free(avg_pwr_left_e); + free(avg_pwr_right_fx); + free(avg_pwr_right_e); +#else + ivas_reverb_interpolate_acoustic_data( FFT_SPECTRUM_SIZE, input_fc, avg_pwr_left_fft, avg_pwr_right_fft, CLDFB_NO_CHANNELS_MAX, output_fc, avg_pwr_left, avg_pwr_right ); +#endif return IVAS_ERR_OK; } -- GitLab