LCOV - code coverage report
Current view: top level - lib_rend - ivas_reverb_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ ca3146eb9de8185ed0247945c643267826a32a94 Lines: 1002 1089 92.0 %
Date: 2025-08-26 01:31:27 Functions: 35 35 100.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : #include <stdint.h>
      34             : #include "options.h"
      35             : #include "prot_fx.h"
      36             : #include "ivas_prot_rend_fx.h"
      37             : #include "ivas_cnst.h"
      38             : #include "math.h"
      39             : #include "ivas_rom_rend.h"
      40             : #include <assert.h>
      41             : #include "wmc_auto.h"
      42             : #include "debug.h"
      43             : 
      44        2767 : static Word16 wrap_rad_fixed(
      45             :     Word32 angle /* Q13 */ )
      46             : {
      47        2767 :     Word32 L_tmp = angle;
      48        2767 :     move32();
      49             : 
      50             :     /* Wrap azimuth value */
      51        6965 :     WHILE( GT_32( L_tmp, EVS_PI_FX ) )
      52             :     {
      53        4198 :         L_tmp = L_sub( L_tmp, EVS_2PI_FX );
      54             :     }
      55        2767 :     WHILE( LE_32( L_tmp, -EVS_PI_FX ) )
      56             :     {
      57           0 :         L_tmp = L_add( L_tmp, EVS_2PI_FX );
      58             :     }
      59             : 
      60        2767 :     return extract_l( L_tmp );
      61             : }
      62             : 
      63             : /* The reverberator structure implemented here is described in detail in:
      64             :  * Vilkamo, J., Neugebauer, B., & Plogsties, J. (2012). Sparse frequency-domain reverberator.
      65             :  * Journal of the Audio Engineering Society, 59(12), 936-943. */
      66             : 
      67             : /*-------------------------------------------------------------------------
      68             :  * Local constants
      69             :  *------------------------------------------------------------------------*/
      70             : 
      71             : #define BIN_REND_RANDOM_SEED 1 /* random seed for generating reverb decorrelators */
      72             : 
      73             : #define CLDFB_SLOTS_PER_SECOND 800 /* Used for initializing reverb */
      74             : 
      75             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
      76             : #define REV_TIME_THRESHOLD               ( 13421773 )   /* 0.2f in Q26 */
      77             : #define Q26_REV_TIME_THRESHOLD_TIMES_0_5 ( 6710886 )    /* 0.2 * 0.5 in Q26 */
      78             : #define Q29_0_5_PER_REV_TIME_THRESHOLD   ( 1342177280 ) /* 0.2 / 0.5 in Q29 */
      79             : #endif
      80             : 
      81             : #define INNER_BLK_SIZE 80 /* size of data blocks used for more efficient delay line and IIR filter processing */
      82             : /* should be a divisor of the frame length at any sampling rate and an even number*/
      83             : #define FFT_FILTER_WND_FLAT_REGION     ( 0.40f ) /* flat section (==1) length of FFT filter window, in proportion to overlap */
      84             : #define FFT_FILTER_WND_TRANS_REGION    ( 0.15f ) /* transition (1->0) length of FFT filter window, in proportion to overlap */
      85             : #define FFT_FILTER_WND_FLAT_REGION_FX  ( 26214 ) /*Q16 flat section (==1) length of FFT filter window, in proportion to overlap */
      86             : #define FFT_FILTER_WND_TRANS_REGION_FX ( 9830 )  /*Q16 transition (1->0) length of FFT filter window, in proportion to overlap */
      87             : #define REF_LF_MIN                     ( 100.0f )
      88             : #define REF_LF_MAX                     ( 250.0f )
      89             : #define REF_HF_MIN                     ( 5000.0f )
      90             : #define REF_HF_MAX                     ( 7950.0f )
      91             : 
      92             : #define REF_LF_MIN_FX ( 100 )
      93             : #define REF_LF_MAX_FX ( 250 )
      94             : #define REF_HF_MIN_FX ( 5000 )
      95             : #define REF_HF_MAX_FX ( 7950 )
      96             : #define LF_BIAS       ( 0.5f )
      97             : 
      98             : #define DEFAULT_SRC_DIST                ( 1.5f ) /* default source distance [m] for reverb dmx factor computing */
      99             : #define DMX_GAIN                        ( 1410542208 )
     100             : #define IVAS_REVERB_FFT_SIZE_48K        ( 512 )
     101             : #define IVAS_REVERB_FFT_SIZE_32K        ( 512 )
     102             : #define IVAS_REVERB_FFT_SIZE_16K        ( 256 )
     103             : #define IVAS_REVERB_FFT_N_SUBBLOCKS_48K ( 1 )
     104             : #define IVAS_REVERB_FFT_N_SUBBLOCKS_32K ( 1 )
     105             : #define IVAS_REVERB_FFT_N_SUBBLOCKS_16K ( 1 )
     106             : 
     107             : #define MAX_NR_OUTPUTS ( 2 )
     108             : 
     109             : #ifdef FIX_1942_ASSERTION_LOWSHELF
     110             : #define M60Q9  ( -30720 ) //-60 in Q9
     111             : #define M120Q8 ( -30720 ) //-120 in Q8
     112             : #endif
     113             : 
     114             : const Word16 init_loop_delay[IVAS_REV_MAX_NR_BRANCHES] = { 37, 31, 29, 23, 19, 17, 13, 11 };
     115             : const Word16 default_loop_delay_48k[IVAS_REV_MAX_NR_BRANCHES] = { 2309, 1861, 1523, 1259, 1069, 919, 809, 719 };
     116             : const Word16 default_loop_delay_32k[IVAS_REV_MAX_NR_BRANCHES] = { 1531, 1237, 1013, 839, 709, 613, 541, 479 };
     117             : const Word16 default_loop_delay_16k[IVAS_REV_MAX_NR_BRANCHES] = { 769, 619, 509, 421, 353, 307, 269, 239 };
     118             : 
     119             : /*------------------------------------------------------------------------------------------*
     120             :  * Local Struct definition
     121             :  *------------------------------------------------------------------------------------------*/
     122             : typedef struct ivas_reverb_params_t
     123             : {
     124             :     Word16 pre_delay;                                                                                                                                                     /* Delay of the FDC reverb, first peak after pre_delay samples. Note that               */
     125             :                                                                                                                                                                           /*       there may be non-zero samples earlier due to the filters being                 */
     126             :                                                                                                                                                                           /*       linear-phase.                                                                  */
     127             :     Word16 nr_loops;                                                                                                                                                      /* Number of feedback loops (= L)                                                       */
     128             :     Word16 pLoop_delays[IVAS_REV_MAX_NR_BRANCHES]; /* Delay for each feedback loop in samples.                                             */                             /* Feedback [L][L] matrix that mixes the signals of the loops.                          */
     129             :     Word32 pLoop_feedback_matrix_fx[IVAS_REV_MAX_NR_BRANCHES * IVAS_REV_MAX_NR_BRANCHES];                                                                                 /* Feedback [L][L] matrix that mixes the signals of the loops.                          */
     130             :     Word16 nr_outputs;                                                                                                                                                    /* Nr of signals extracted from the loops (= S).                                        */
     131             :     /*       Currently this is fixed to 2.                                                  */                                                                            /* Mix [S][L] matrix from feedback loops to outputs.                                    */
     132             :     Word16 pLoop_extract_matrix_fx[MAX_NR_OUTPUTS * IVAS_REV_MAX_NR_BRANCHES]; /* Mix [S][L] matrix from feedback loops to outputs.                                    */ /* In Matlab: [S x L] - Currently S=2, later may be more than 2 for speaker playback.   */
     133             :     Word16 t60_filter_order;                                                                                                                                              /* Filter order (length of vector)                                                      */
     134             :     Word16 pT60_filter_coeff_fx[MAX_NR_OUTPUTS * IVAS_REV_MAX_NR_BRANCHES * IVAS_REV_MAX_IIR_FILTER_LENGTH];
     135             :     /* In Matlab: IIR: [(2 * L) x (<order> + 1)] (odd: b-vector, even: a-vector)            */
     136             :     /* In Matlab: FIR: [L       x <order>]                                                  */
     137             :     Word32 *pFc_fx;   /* Center frequencies for FFT filter design                                             */
     138             :     Word32 *pRt60_fx; /* RT60 values at these frequencies                                                     */
     139             :     Word16 *pRt60_e;  /* exponents for RT60 values at these frequencies                                                     */
     140             :     Word32 *pDsr_fx;  /* DSR values at these frequencies                                                      */
     141             :     Word16 *pDsr_e;   /* DSR values at these frequencies                                                      */
     142             : #ifndef FIX_1053_REVERB_RECONFIGURATION
     143             :     Word32 *pHrtf_avg_pwr_response_l_fx;    /* The HRTF set's average left  ear power response                                      */
     144             :     Word32 *pHrtf_avg_pwr_response_r_fx;    /* The HRTF set's average right ear power response                                      */
     145             :     Word32 *pHrtf_inter_aural_coherence_fx; /* The HRTF set's inter-aural coherence for diffuse sound                               */
     146             : #endif
     147             :     const Word32 *pHrtf_avg_pwr_response_l_const_fx;    /* The HRTF set's average left  ear power response                                      */
     148             :     const Word32 *pHrtf_avg_pwr_response_r_const_fx;    /* The HRTF set's average right ear power response                                      */
     149             :     const Word32 *pHrtf_inter_aural_coherence_const_fx; /* The HRTF set's inter-aural coherence for diffuse sound                               */
     150             : 
     151             :     Word16 do_corr_filter; /* Flag indicating whether correlation filters should be used.                          */
     152             :                            /*        Correlation only supported and needed for binaural playback (i.e.             */
     153             :                            /*        when nr_outputs != 2 correlation filtering is never supported).               */
     154             : } ivas_reverb_params_t;
     155             : 
     156             : /*------------------------------------------------------------------------------------------*
     157             :  * Static functions declarations
     158             :  *------------------------------------------------------------------------------------------*/
     159             : 
     160             : static ivas_error calc_jot_t60_coeffs_fx( Word16 *pH_dB_fx, Word16 pH_dB_exp, const UWord16 nrFrequencies, Word16 *pFrequencies_fx, Word16 *pCoeffA_fx, Word16 *pCoeffB_fx, const Word16 fNyquist_fx );
     161             : 
     162             : /*-------------------------------------------------------------------------
     163             :  * binRend_rand()
     164             :  *
     165             :  *
     166             :  *------------------------------------------------------------------------*/
     167             : 
     168     3498271 : static UWord16 binRend_rand(
     169             :     REVERB_STRUCT_HANDLE hReverb /* i/o: binaural reverb handle          */
     170             : )
     171             : {
     172     3498271 :     hReverb->binRend_RandNext = hReverb->binRend_RandNext * 1103515245 + 12345;
     173             : 
     174     3498271 :     return (UWord16) ( hReverb->binRend_RandNext / 65536 ) % 32768;
     175             : }
     176             : 
     177             : 
     178             : /*-------------------------------------------------------------------------
     179             :  * ivas_binaural_reverb_setPreDelay()
     180             :  *
     181             :  *
     182             :  *------------------------------------------------------------------------*/
     183             : 
     184         477 : static void ivas_binaural_reverb_setPreDelay_fx(
     185             :     REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle          */
     186             :     const Word16 delaySamples     /* i  : reverb pre-delay in CLDFB slots */
     187             : )
     188             : {
     189         477 :     IF( LT_16( delaySamples, 1 ) )
     190             :     {
     191           0 :         hReverb->preDelayBufferLength = 1;
     192           0 :         move16();
     193             : 
     194           0 :         return;
     195             :     }
     196             : 
     197         477 :     IF( GT_16( delaySamples, REVERB_PREDELAY_MAX ) )
     198             :     {
     199           4 :         hReverb->preDelayBufferLength = REVERB_PREDELAY_MAX;
     200           4 :         move16();
     201             : 
     202           4 :         return;
     203             :     }
     204             : 
     205         473 :     hReverb->preDelayBufferLength = delaySamples;
     206         473 :     move16();
     207             : 
     208         473 :     return;
     209             : }
     210             : 
     211             : 
     212             : /*-------------------------------------------------------------------------
     213             :  * ivas_binaural_reverb_setReverbTimes()
     214             :  *
     215             :  *
     216             :  *------------------------------------------------------------------------*/
     217             : 
     218             : 
     219         477 : static void ivas_binaural_reverb_setReverbTimes_fx(
     220             :     REVERB_STRUCT_HANDLE hReverb, /* i/o: binaural reverb handle                                  */
     221             :     const Word32 output_Fs,       /* i  : sampling_rate                                           */
     222             :     const Word32 *revTimes_fx,    /*Q26 i  : reverberation times T60 for each CLDFB bin in seconds   */
     223             :     const Word32 *revEnes_fx      /*Q31 i  : spectrum for reverberated sound at each CLDFB bin       */
     224             : )
     225             : {
     226             :     Word16 bin, ch, tap, sample;
     227             : 
     228             :     Word32 binCenterFreq_fx, diffuseFieldICC_fx, tmpVal_fx, attenuationFactorPerSample_fx, L_tmp;
     229             :     Word32 intendedEnergy_fx, actualizedEnergy_fx, energyBuildup_fx, currentEnergy_fx, attenuationFactorPerSampleSq_fx;
     230             :     Word16 tmp, tmp_exp, scale, tmpVal_exp, attenuationFactorPerSample_exp, attenuationFactorPerSampleSq_exp, energyBuildup_exp, currentEnergy_exp, intendedEnergy_exp, actualizedEnergy_exp;
     231             :     Word16 sine_inp, norm, div_exp1, div1, sine, binCenterFreq_exp;
     232         477 :     Word16 reverb_exp = 0;
     233         477 :     move16();
     234             : 
     235         477 :     hReverb->binRend_RandNext = (UWord16) BIN_REND_RANDOM_SEED;
     236         477 :     move16();
     237         477 :     hReverb->highestBinauralCoherenceBin = 0;
     238         477 :     move16();
     239             : 
     240       20747 :     FOR( bin = 0; bin < hReverb->numBins; bin++ )
     241             :     {
     242             :         /* Determine the diffuse field binaural coherence */
     243             :         Word16 exp;
     244       20270 :         tmp_exp = BASOP_Util_Add_MantExp( bin, 15, 1, 14, &tmp );
     245       20270 :         tmp = BASOP_Util_Divide3232_Scale( L_deposit_h( tmp ), L_deposit_h( hReverb->numBins ), &exp );
     246       20270 :         exp = add( exp, sub( tmp_exp, 15 ) );
     247       20270 :         L_tmp = Mpy_32_16_1( output_Fs, tmp ); /*- exp */
     248       20270 :         binCenterFreq_exp = add( 31, exp );
     249       20270 :         binCenterFreq_fx = L_shr( L_tmp, 1 ); // divide by 2
     250             : #ifdef FIX_1931_BIN_COHR_CROSS_MIX
     251       20270 :         norm = norm_l( binCenterFreq_fx );
     252       20270 :         binCenterFreq_fx = L_shl( binCenterFreq_fx, norm );
     253       20270 :         binCenterFreq_exp = sub( binCenterFreq_exp, norm );
     254             : #endif
     255       20270 :         IF( bin == 0 )
     256             :         {
     257         477 :             diffuseFieldICC_fx = ONE_IN_Q31;
     258         477 :             move32();
     259             :         }
     260       19793 :         ELSE IF( EQ_16( BASOP_Util_Cmp_Mant32Exp( binCenterFreq_fx, binCenterFreq_exp, 2700, 31 ), -1 ) )
     261             :         {
     262             :             /* binCenterFreq / 550.0f */
     263        2767 :             L_tmp = Mpy_32_32( binCenterFreq_fx, 3904516 /* 1 / 550 in Q31 */ );
     264        2767 :             norm = norm_l( L_tmp );
     265        2767 :             tmp = extract_h( L_shl( L_tmp, norm ) );
     266        2767 :             tmp = add( mult( EVS_PI_FX, tmp ), EPSILLON_FX ); // to avoid divide by 0 issue
     267        2767 :             tmp_exp = sub( add( binCenterFreq_exp, 2 ), norm );
     268             : 
     269        2767 :             sine_inp = wrap_rad_fixed( L_shl( tmp, sub( tmp_exp, 2 ) ) ); // Q13
     270             : 
     271        2767 :             sine = getSinWord16( sine_inp ); // Q15
     272        2767 :             div1 = BASOP_Util_Divide1616_Scale( sine, tmp, &scale );
     273        2767 :             div_exp1 = add( scale, sub( 0, tmp_exp ) );
     274        2767 :             div1 = shl( div1, div_exp1 ); /* Q15 */
     275             : 
     276             :             /* binCenterFreq / 2700.0f */
     277        2767 :             L_tmp = Mpy_32_32( binCenterFreq_fx, 795364 /* 1 / 2700 in Q31 */ );
     278             : #ifdef FIX_1931_BIN_COHR_CROSS_MIX
     279        2767 :             L_tmp = L_shl( L_tmp, binCenterFreq_exp ); /* Q31 */
     280             : #else
     281             :             norm = norm_l( L_tmp );
     282             :             L_tmp = L_shl( L_tmp, norm ); /* Q31 */
     283             : #endif
     284             :             /* ( 1.0f - binCenterFreq / 2700.0f ) */
     285        2767 :             L_tmp = L_sub( ONE_IN_Q31, L_tmp ); /* Q31 */
     286             : 
     287        2767 :             diffuseFieldICC_fx = Mpy_32_16_1( L_tmp, div1 ); /* Q31 */
     288             : 
     289        2767 :             hReverb->highestBinauralCoherenceBin = bin;
     290        2767 :             move16();
     291             :         }
     292             :         ELSE
     293             :         {
     294             : 
     295       17026 :             diffuseFieldICC_fx = 0;
     296       17026 :             move32();
     297             :         }
     298             : 
     299             :         /* Mixing gains to generate a diffuse-binaural sound based on incoherent sound */
     300             :         /* tmpVal = ( 1.0f - sqrtf( 1.0f - powf( diffuseFieldICC, 2.0 ) ) ) / 2.0f; */
     301       20270 :         L_tmp = Mpy_32_32( diffuseFieldICC_fx, diffuseFieldICC_fx ); // square
     302       20270 :         L_tmp = L_sub( ONE_IN_Q31, L_tmp );
     303       20270 :         scale = 0;
     304       20270 :         L_tmp = Sqrt32( L_tmp, &scale );
     305       20270 :         L_tmp = L_shl( L_tmp, scale ); /* Q31 */
     306       20270 :         tmpVal_fx = L_shr( L_sub( ONE_IN_Q31, L_tmp ), 1 );
     307       20270 :         tmpVal_exp = 0;
     308       20270 :         move16();
     309             : 
     310       20270 :         IF( diffuseFieldICC_fx > 0 )
     311             :         {
     312        1431 :             exp = tmpVal_exp;
     313        1431 :             move16();
     314        1431 :             L_tmp = Sqrt32( L_abs( tmpVal_fx ), &exp );
     315        1431 :             hReverb->binauralCoherenceCrossmixGains_fx[bin] = L_shl( L_tmp, exp ); // Q31
     316             :         }
     317             :         ELSE
     318             :         {
     319       18839 :             exp = tmpVal_exp;
     320       18839 :             move16();
     321       18839 :             L_tmp = Sqrt32( L_abs( tmpVal_fx ), &exp );
     322       18839 :             hReverb->binauralCoherenceCrossmixGains_fx[bin] = L_negate( L_shl( L_tmp, exp ) ); // Q31
     323             :         }
     324             : 
     325             :         /* hReverb->binauralCoherenceDirectGains[bin] = sqrtf( 1.0f - fabsf( tmpVal ) ); */
     326       20270 :         exp = tmpVal_exp;
     327       20270 :         move16();
     328       20270 :         L_tmp = L_sub( ONE_IN_Q31, L_abs( tmpVal_fx ) );
     329       20270 :         L_tmp = Sqrt32( L_abs( L_tmp ), &exp );
     330       20270 :         hReverb->binauralCoherenceDirectGains_fx[bin] = L_shl( L_tmp, exp ); // making as Q31
     331             : 
     332             :         /* Determine attenuation factor that generates the appropriate energy decay according to reverberation time */
     333       20270 :         L_tmp = Mpy_32_32( 1677721600, revTimes_fx[bin] ); // e10 --> 800 * 2^21, + e0
     334       20270 :         tmp = BASOP_Util_Divide3232_Scale( 1073741824, L_tmp, &scale );
     335       20270 :         scale = add( scale, sub( 1, 15 ) );      // revTimes_fx in Q26
     336       20270 :         L_tmp = Mpy_32_16_1( -1610612736, tmp ); // * -3
     337       20270 :         scale = add( 2, scale );
     338       20270 :         L_tmp = Mpy_32_32( 1783446563, L_tmp ); // scale + 2
     339       20270 :         attenuationFactorPerSample_fx = BASOP_util_Pow2( L_tmp, add( scale, 2 ), &attenuationFactorPerSample_exp );
     340             : 
     341             :         Word32 tmp_mul;
     342       20270 :         scale = norm_l( hReverb->loopBufLength[bin] );
     343       20270 :         tmp_mul = L_shl( hReverb->loopBufLength[bin], scale );
     344       20270 :         L_tmp = BASOP_Util_Log2( attenuationFactorPerSample_fx );                     // Q25
     345       20270 :         L_tmp = L_add( L_tmp, L_shl( (Word32) attenuationFactorPerSample_exp, 25 ) ); // Q25
     346       20270 :         L_tmp = Mpy_32_32( L_tmp, tmp_mul );
     347       20270 :         L_tmp = BASOP_util_Pow2( L_tmp, sub( 6 + 31, scale ), &exp );
     348       20270 :         hReverb->loopAttenuationFactor_fx[bin] = L_shl( L_tmp, exp ); // making as Q31
     349             : 
     350       20270 :         attenuationFactorPerSampleSq_fx = Mpy_32_32( attenuationFactorPerSample_fx, attenuationFactorPerSample_fx );
     351       20270 :         attenuationFactorPerSampleSq_exp = attenuationFactorPerSample_exp + attenuationFactorPerSample_exp;
     352             : 
     353             :         /* Design sparse decorrelation filters. The decorrelation filters, due to random procedures involved,
     354             :          * may affect the spectrum of the output. The spectral effect is therefore monitored and compensated for. */
     355             : 
     356       20270 :         intendedEnergy_fx = 0;
     357       20270 :         move32();
     358       20270 :         intendedEnergy_exp = 0;
     359       20270 :         move16();
     360       20270 :         actualizedEnergy_fx = 0;
     361       20270 :         move32();
     362       20270 :         actualizedEnergy_exp = 0;
     363       20270 :         move16();
     364             : 
     365       60810 :         FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
     366             :         {
     367             : 
     368       40540 :             energyBuildup_fx = 0;
     369       40540 :             move32();
     370       40540 :             energyBuildup_exp = 0;
     371       40540 :             move16();
     372       40540 :             currentEnergy_fx = ONE_IN_Q30;
     373       40540 :             move32();
     374       40540 :             currentEnergy_exp = 1;
     375       40540 :             move16();
     376             : 
     377       40540 :             tap = 0;
     378       40540 :             move16();
     379             : 
     380     2574672 :             FOR( sample = 0; sample < hReverb->loopBufLength[bin]; sample++ )
     381             :             {
     382     2534132 :                 intendedEnergy_fx = BASOP_Util_Add_Mant32Exp( intendedEnergy_fx, intendedEnergy_exp, currentEnergy_fx, currentEnergy_exp, &intendedEnergy_exp );
     383             :                 /* The randomization at the energy build up affects where the sparse taps are located */
     384             : 
     385     2534132 :                 UWord16 ret_binRend = binRend_rand( hReverb );
     386             : 
     387     2534132 :                 tmp = BASOP_Util_Divide3232_Scale( ret_binRend, PCM16_TO_FLT_FAC_FX, &tmp_exp );
     388     2534132 :                 L_tmp = BASOP_Util_Add_Mant32Exp( L_deposit_h( tmp ), tmp_exp, L_negate( 1073741824 ), 0, &exp );
     389     2534132 :                 L_tmp = Mpy_32_32( L_tmp, 214748364 ); // exp + 0
     390     2534132 :                 L_tmp = BASOP_Util_Add_Mant32Exp( L_tmp, exp, currentEnergy_fx, currentEnergy_exp, &exp );
     391     2534132 :                 energyBuildup_fx = BASOP_Util_Add_Mant32Exp( energyBuildup_fx, energyBuildup_exp, L_tmp, exp, &energyBuildup_exp );
     392     2534132 :                 IF( energyBuildup_fx >= 0 ) /* A new filter tap is added at this condition */
     393             :                 {
     394     2533789 :                     IF( ( BASOP_Util_Cmp_Mant32Exp( energyBuildup_fx, energyBuildup_exp, 1, 31 ) > 0 ) )
     395             :                     {
     396             :                         /* Four efficient phase operations: n*pi/2, n=0,1,2,3 */
     397      964139 :                         hReverb->tapPhaseShiftType[bin][ch][tap] = (Word16) ( binRend_rand( hReverb ) % 4 );
     398      964139 :                         move16();
     399             :                         /* Set the tapPointer to point to the determined sample at the loop buffer */
     400             : 
     401      964139 :                         hReverb->tapPointersReal_fx[bin][ch][tap] = &( hReverb->loopBufReal_fx[bin][sample] );
     402      964139 :                         hReverb->tapPointersImag_fx[bin][ch][tap] = &( hReverb->loopBufImag_fx[bin][sample] );
     403             : 
     404      964139 :                         energyBuildup_fx = BASOP_Util_Add_Mant32Exp( energyBuildup_fx, energyBuildup_exp, L_negate( 1073741824 ), 1, &energyBuildup_exp ); /* A tap is added, thus remove its energy from the buildup */
     405             : 
     406      964139 :                         tap = add( tap, 1 );
     407             : 
     408      964139 :                         actualizedEnergy_fx = BASOP_Util_Add_Mant32Exp( actualizedEnergy_fx, actualizedEnergy_exp, 1073741824, 1, &actualizedEnergy_exp );
     409             :                     }
     410             :                 }
     411             : 
     412     2534132 :                 currentEnergy_fx = BASOP_Util_Add_Mant32Exp( currentEnergy_fx, currentEnergy_exp, 0, 0, &currentEnergy_exp );
     413     2534132 :                 currentEnergy_fx = Mpy_32_32( currentEnergy_fx, attenuationFactorPerSampleSq_fx );
     414     2534132 :                 currentEnergy_exp = currentEnergy_exp + attenuationFactorPerSampleSq_exp;
     415             :             }
     416             : 
     417             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
     418             :             /* In some configurations with small T60s it is possible the number of taps randomizes to zero.
     419             :                Ensure at least 1 filter tap. */
     420       40540 :             IF( EQ_16( tap, 0 ) )
     421             :             {
     422           0 :                 hReverb->tapPhaseShiftType[bin][ch][0] = (Word16) ( binRend_rand( hReverb ) % 4 );
     423           0 :                 move16();
     424           0 :                 hReverb->tapPointersReal_fx[bin][ch][0] = &( hReverb->loopBufReal_fx[bin][0] );
     425           0 :                 hReverb->tapPointersImag_fx[bin][ch][0] = &( hReverb->loopBufImag_fx[bin][0] );
     426           0 :                 tap = 1;
     427           0 :                 move16();
     428           0 :                 actualizedEnergy_fx = ONE_IN_Q30;
     429           0 :                 move32();
     430           0 :                 actualizedEnergy_exp = 1;
     431           0 :                 move16();
     432             :             }
     433             : #endif
     434             : 
     435       40540 :             hReverb->taps[bin][ch] = tap; /* Number of taps determined at the above random procedure */
     436       40540 :             move16();
     437             :         }
     438             : 
     439             :         /* The decorrelator design and IIR attenuation rate affects the energy of reverb, which is compensated here */
     440       20270 :         reverb_exp = 0;
     441       20270 :         move16();
     442       20270 :         hReverb->reverbEqGains_fx[bin] = Sqrt32( revEnes_fx[bin], &reverb_exp ); /* Determined reverb spectrum */
     443       20270 :         move32();
     444       20270 :         hReverb->reverbEqGains_fx[bin] = BASOP_Util_Add_Mant32Exp( hReverb->reverbEqGains_fx[bin], reverb_exp, 0, 0, &reverb_exp );
     445       20270 :         move32();
     446             : 
     447       20270 :         tmp = BASOP_Util_Divide3232_Scale( intendedEnergy_fx, actualizedEnergy_fx, &tmp_exp );
     448       20270 :         tmp_exp = add( tmp_exp, sub( intendedEnergy_exp, actualizedEnergy_exp ) );
     449       20270 :         hReverb->reverbEqGains_fx[bin] = BASOP_Util_Add_Mant32Exp( hReverb->reverbEqGains_fx[bin], reverb_exp, 0, 0, &reverb_exp );
     450       20270 :         move32();
     451       20270 :         L_tmp = Sqrt32( L_deposit_h( tmp ), &tmp_exp );
     452       20270 :         hReverb->reverbEqGains_fx[bin] = Mpy_32_32( hReverb->reverbEqGains_fx[bin], L_tmp );
     453       20270 :         move32();
     454       20270 :         reverb_exp = add( reverb_exp, tmp_exp );
     455             : 
     456       20270 :         L_tmp = BASOP_Util_Add_Mant32Exp( 1073741824, 1, L_negate( attenuationFactorPerSampleSq_fx ), attenuationFactorPerSampleSq_exp, &tmp_exp );
     457       20270 :         L_tmp = Mpy_32_32( L_tmp, 1073741824 ); // tmp_exp + 1
     458       20270 :         tmp_exp = add( tmp_exp, 0 );
     459       20270 :         L_tmp = Sqrt32( L_tmp, &tmp_exp );
     460       20270 :         hReverb->reverbEqGains_fx[bin] = Mpy_32_32( L_tmp, hReverb->reverbEqGains_fx[bin] );
     461       20270 :         move32();
     462       20270 :         reverb_exp = add( reverb_exp, tmp_exp );
     463       20270 :         hReverb->reverbEqGains_fx[bin] = L_shl( hReverb->reverbEqGains_fx[bin], reverb_exp ); // making as Q31
     464       20270 :         move32();
     465             :     }
     466         477 :     return;
     467             : }
     468             : 
     469             : /*-----------------------------------------------------------------------------------------*
     470             :  * Function compute_feedback_matrix()
     471             :  *
     472             :  * Compute the N x N matrix for the mixing the N feedback loop outputs into the N inputs again
     473             :  *-----------------------------------------------------------------------------------------*/
     474             : 
     475         218 : static ivas_error compute_feedback_matrix_fx(
     476             :     Word32 *pFeedbackMatrix, // Q31
     477             :     const Word16 n )
     478             : {
     479             :     Word32 u;
     480             :     Word16 i, j, x;
     481             : 
     482         218 :     u = MATRIX_CONSTANT; // Q31
     483         218 :     move32();
     484             : 
     485         218 :     pFeedbackMatrix[0] = u;
     486         218 :     move32();
     487         872 :     FOR( x = 1; x < n; x += x )
     488             :     {
     489        2180 :         FOR( i = 0; i < x; i++ )
     490             :         {
     491        6104 :             FOR( j = 0; j < x; j++ )
     492             :             {
     493        4578 :                 pFeedbackMatrix[add( i_mult( add( i, x ), n ), j )] = pFeedbackMatrix[add( i_mult( i, n ), j )];
     494        4578 :                 move32();
     495        4578 :                 pFeedbackMatrix[i_mult( i, n ) + j + x] = pFeedbackMatrix[add( i_mult( i, n ), j )];
     496        4578 :                 move32();
     497        4578 :                 pFeedbackMatrix[add( add( i_mult( add( i, x ), n ), j ), x )] = L_negate( pFeedbackMatrix[add( i_mult( i, n ), j )] );
     498        4578 :                 move32();
     499             :             }
     500             :         }
     501             :     }
     502             : 
     503             : 
     504         218 :     return IVAS_ERR_OK;
     505             : }
     506             : 
     507             : 
     508             : /*-----------------------------------------------------------------------------------------*
     509             :  * Function compute_2_out_extract_matrix()
     510             :  *
     511             :  * Compute the N x 2 matrix for mixing the N Jot feedback loops to 2 outputs
     512             :  *-----------------------------------------------------------------------------------------*/
     513             : 
     514         218 : static void compute_2_out_extract_matrix_fx(
     515             :     Word16 *pExtractMatrix,
     516             :     const Word16 n )
     517             : {
     518             :     Word16 ff;
     519             :     Word16 i;
     520             : 
     521         218 :     ff = 1;
     522         218 :     move16();
     523             : 
     524        1962 :     FOR( i = 0; i < n; i++ )
     525             :     {
     526        1744 :         pExtractMatrix[i] = 1;
     527        1744 :         move16();
     528        1744 :         pExtractMatrix[add( i, n )] = ff;
     529        1744 :         move16();
     530        1744 :         ff = negate( ff );
     531             :     }
     532             : 
     533         218 :     return;
     534             : }
     535             : /*-----------------------------------------------------------------------------------------*
     536             :  * Function set_base_config()
     537             :  *
     538             :  * Set all jot reverb parameters that are independent of the input reverb configuration
     539             :  *-----------------------------------------------------------------------------------------*/
     540             : 
     541         218 : static ivas_error set_base_config_fx(
     542             :     ivas_reverb_params_t *pParams,
     543             :     const Word32 output_Fs )
     544             : {
     545             :     ivas_error error;
     546             :     Word16 loop_idx;
     547         218 :     const Word16 *selected_loop_delay = NULL;
     548             : 
     549         218 :     IF( pParams == NULL )
     550             :     {
     551           0 :         return IVAS_ERR_INTERNAL;
     552             :     }
     553             : 
     554         218 :     pParams->pre_delay = 0;
     555         218 :     move16();
     556         218 :     pParams->nr_outputs = BINAURAL_CHANNELS;
     557         218 :     move16();
     558         218 :     pParams->nr_loops = IVAS_REV_MAX_NR_BRANCHES;
     559         218 :     move16();
     560             : 
     561             :     /* set loop delays to default */
     562         218 :     IF( EQ_32( output_Fs, 48000 ) )
     563             :     {
     564         127 :         selected_loop_delay = default_loop_delay_48k; // Q0
     565             :     }
     566          91 :     ELSE IF( EQ_32( output_Fs, 32000 ) )
     567             :     {
     568          30 :         selected_loop_delay = default_loop_delay_32k; // Q0
     569             :     }
     570          61 :     ELSE IF( EQ_32( output_Fs, 16000 ) )
     571             :     {
     572          61 :         selected_loop_delay = default_loop_delay_16k; // Q0
     573             :     }
     574             : 
     575        1962 :     FOR( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
     576             :     {
     577        1744 :         pParams->pLoop_delays[loop_idx] = selected_loop_delay[loop_idx];
     578        1744 :         move16();
     579             :     }
     580             : 
     581             :     /* set feedback and output matrices */
     582         218 :     IF( NE_32( ( error = compute_feedback_matrix_fx( pParams->pLoop_feedback_matrix_fx, pParams->nr_loops ) ), IVAS_ERR_OK ) )
     583             :     {
     584           0 :         return error;
     585             :     }
     586             : 
     587         218 :     compute_2_out_extract_matrix_fx( pParams->pLoop_extract_matrix_fx, pParams->nr_loops );
     588             :     /* pre-set the various filters; they will be set later based on reverb configuration */
     589         218 :     pParams->t60_filter_order = 1; /* set to 1 in base config. */
     590         218 :     move16();
     591             : 
     592         218 :     IF( EQ_16( pParams->nr_outputs, 2 ) )
     593             :     {
     594         218 :         pParams->do_corr_filter = 1;
     595         218 :         move16();
     596             :     }
     597             :     ELSE
     598             :     {
     599           0 :         pParams->do_corr_filter = 0;
     600           0 :         move16();
     601             :     }
     602             : 
     603         218 :     return IVAS_ERR_OK;
     604             : }
     605             : 
     606             : /*-----------------------------------------------------------------------------------------*
     607             :  * Function calc_dmx_gain()
     608             :  *
     609             :  * Computes the downmix gain
     610             :  *-----------------------------------------------------------------------------------------*/
     611         163 : static Word32 calc_dmx_gain_fx( void )
     612             : {
     613         163 :     const Word32 gain = DMX_GAIN; // Q23
     614         163 :     move32();
     615         163 :     return gain;
     616             : }
     617             : /*-----------------------------------------------------------------------------------------*
     618             :  * Function calc_predelay()
     619             :  *
     620             :  * Calculate the predelay, taking shortest jot loop delay into account
     621             :  *-----------------------------------------------------------------------------------------*/
     622             : 
     623         218 : static void calc_predelay_fx(
     624             :     ivas_reverb_params_t *pParams,
     625             :     Word32 acoustic_predelay_sec,
     626             :     const Word32 output_Fs )
     627             : {
     628             :     Word16 predelay, fbdelay, output_frame;
     629         218 :     predelay = round_fx( L_shl( Mult_32_32( L_shl( output_Fs, 15 ), acoustic_predelay_sec ), 5 ) );
     630         218 :     output_frame = extract_l( Mult_32_16( output_Fs, INV_FRAME_PER_SEC_Q15 ) );
     631         218 :     fbdelay = pParams->pLoop_delays[sub( pParams->nr_loops, 1 )];
     632         218 :     move16();
     633         218 :     predelay = sub( predelay, fbdelay );
     634             : 
     635         218 :     if ( predelay < 0 )
     636             :     {
     637           0 :         predelay = 0;
     638           0 :         move16();
     639             :     }
     640             : 
     641         218 :     if ( LT_16( output_frame, predelay ) )
     642             :     {
     643           0 :         predelay = output_frame; // Q0
     644           0 :         move16();
     645             :     }
     646             : 
     647         218 :     pParams->pre_delay = predelay; // Q0
     648         218 :     move16();
     649         218 :     move16();
     650         218 :     move16();
     651         218 :     return;
     652             : }
     653             : 
     654             : /*-----------------------------------------------------------------------------------------*
     655             :  * Function compute_t60_coeffs()
     656             :  *
     657             :  * Calculate Jot reverb's T60 filter coefficients
     658             :  *-----------------------------------------------------------------------------------------*/
     659         218 : static ivas_error compute_t60_coeffs_fx(
     660             :     ivas_reverb_params_t *pParams,
     661             :     const Word16 nr_fc_fft_filter, /*Q0*/
     662             :     const Word32 output_Fs )
     663             : {
     664             :     Word16 bin_idx, loop_idx, tf_T60_len, len;
     665             :     ivas_error error;
     666             : #ifdef FIX_1942_ASSERTION_LOWSHELF
     667             :     Word16 loop_delay_sec_fx, tmp, tmp_e;
     668             : #else
     669             :     Word16 loop_delay_sec_fx, tmp;
     670             : #endif
     671         218 :     Word32 freq_Nyquist_fx = L_shr( output_Fs, 1 );
     672             :     Word16 target_gains_db_fx[RV_LENGTH_NR_FC]; // Q8
     673             :     Word16 norm_f_fx[RV_LENGTH_NR_FC];
     674             :     Word16 *pCoeffs_a_fx, *pCoeffs_b_fx;
     675             :     Word16 e;
     676             : #ifndef FIX_1942_ASSERTION_LOWSHELF
     677             :     const Word16 min120q8 = -30720; // -120 in Q8
     678             : #endif
     679         218 :     error = IVAS_ERR_OK;
     680         218 :     move32();
     681         218 :     tf_T60_len = nr_fc_fft_filter;
     682         218 :     move16();
     683         218 :     len = add( pParams->t60_filter_order, 1 );
     684             : 
     685       48436 :     FOR( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
     686             :     {
     687       48218 :         norm_f_fx[bin_idx] = BASOP_Util_Divide3232_Scale( pParams->pFc_fx[bin_idx], freq_Nyquist_fx, &e );
     688       48218 :         move16();
     689       48218 :         e = add( e, sub( 15, 31 ) );
     690       48218 :         norm_f_fx[bin_idx] = shl( norm_f_fx[bin_idx], sub( e, 1 ) ); // making Q14
     691       48218 :         move16();
     692             :     }
     693             : 
     694        1962 :     FOR( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
     695             :     {
     696        1744 :         loop_delay_sec_fx = BASOP_Util_Divide3232_Scale( pParams->pLoop_delays[loop_idx], output_Fs, &e );
     697        1744 :         loop_delay_sec_fx = shl( loop_delay_sec_fx, e ); // Q15
     698             : 
     699      387488 :         FOR( bin_idx = 0; bin_idx < tf_T60_len; bin_idx++ )
     700             :         {
     701      385744 :             IF( EQ_32( pParams->pRt60_fx[bin_idx], 0 ) )
     702             :             {
     703             :                 // If RT60 is 0, target gain is -120dB
     704             : #ifdef FIX_1942_ASSERTION_LOWSHELF
     705           0 :                 target_gains_db_fx[bin_idx] = M120Q8;
     706           0 :                 move16();
     707             : #else
     708             :                 target_gains_db_fx[bin_idx] = min120q8;
     709             : #endif
     710             :             }
     711             :             ELSE
     712             :             {
     713      385744 :                 tmp = BASOP_Util_Divide3232_Scale( L_deposit_h( loop_delay_sec_fx ), pParams->pRt60_fx[bin_idx], &e );
     714             : #ifdef FIX_1942_ASSERTION_LOWSHELF
     715      385744 :                 tmp_e = add( e, sub( 0, 5 ) ); // L_deposit_h( loop_delay_sec_fx ):Q0.31, pParams->pRt60_fx[bin_idx]:Q5.26
     716             : 
     717      385744 :                 tmp_e = add( tmp_e, 6 ); // + Q6.9(M60Q9)
     718      385744 :                 target_gains_db_fx[bin_idx] = mult( M60Q9, tmp );
     719             : 
     720             :                 // gain < - 120 ? -120: gain
     721      385744 :                 tmp_e = sub( tmp_e, 7 ); // - Q7.8(M120Q8)
     722      385744 :                 IF( GT_16( tmp_e, 0 ) )
     723             :                 {
     724           0 :                     IF( LT_16( target_gains_db_fx[bin_idx], shr( M120Q8, tmp_e ) ) )
     725             :                     {
     726           0 :                         target_gains_db_fx[bin_idx] = M120Q8; // Q8
     727           0 :                         move16();
     728             :                     }
     729             :                     ELSE
     730             :                     {
     731           0 :                         target_gains_db_fx[bin_idx] = shl_r( target_gains_db_fx[bin_idx], tmp_e ); // Q8, gain must be less than 128
     732             :                     }
     733             :                 }
     734             :                 ELSE
     735             :                 {
     736      385744 :                     target_gains_db_fx[bin_idx] = shl_r( target_gains_db_fx[bin_idx], tmp_e ); // Q8, gain must be less than 128
     737      385744 :                     IF( LT_16( target_gains_db_fx[bin_idx], M120Q8 ) )
     738             :                     {
     739           0 :                         target_gains_db_fx[bin_idx] = M120Q8; // Q8
     740           0 :                         move16();
     741             :                     }
     742             :                 }
     743             :             }
     744             : #else
     745             :                 IF( LT_16( e, -1 ) )
     746             :                 {
     747             :                     target_gains_db_fx[bin_idx] = min120q8;
     748             :                 }
     749             :                 ELSE
     750             :                 {
     751             :                     tmp = shr( tmp, sub( 5, e ) );                                 // scaling tmp to Q15
     752             :                     target_gains_db_fx[bin_idx] = mult( shr( min120q8, 1 ), tmp ); // Q8
     753             :                 }
     754             :             }
     755             :             // gain < - 120 ? -120: gain
     756             :             IF( LT_16( target_gains_db_fx[bin_idx], -30720 ) )
     757             :             {
     758             :                 target_gains_db_fx[bin_idx] = -30720;
     759             :                 move16();
     760             :             }
     761             : #endif
     762             :         }
     763             : 
     764        1744 :         pCoeffs_a_fx = &pParams->pT60_filter_coeff_fx[add( shl( i_mult( len, loop_idx ), 1 ), len )]; // Q14
     765        1744 :         pCoeffs_b_fx = &pParams->pT60_filter_coeff_fx[shl( i_mult( len, loop_idx ), 1 )];             // Q14
     766             : 
     767        1744 :         move16();
     768             : 
     769        1744 :         Word16 val = 7;
     770             : 
     771        1744 :         IF( NE_32( ( error = calc_jot_t60_coeffs_fx( target_gains_db_fx, val, tf_T60_len, norm_f_fx, pCoeffs_a_fx, pCoeffs_b_fx, extract_l( freq_Nyquist_fx ) ) ), IVAS_ERR_OK ) )
     772             :         {
     773           0 :             return error;
     774             :         }
     775             :     }
     776             : 
     777         218 :     len = shr( ( add( pParams->t60_filter_order, 1 ) ), 1 ); // Q0// /* == floor( (order+1) / 2) */
     778        1962 :     FOR( loop_idx = 0; loop_idx < pParams->nr_loops; loop_idx++ )
     779             :     {
     780        1744 :         pParams->pLoop_delays[loop_idx] = sub( pParams->pLoop_delays[loop_idx], len ); // Q0
     781        1744 :         move16();
     782             :     }
     783         218 :     return error;
     784             : }
     785             : 
     786             : 
     787             : /*-----------------------------------------------------------------------------------------*
     788             :  * Function calc_low_shelf_first_order_filter()
     789             :  *
     790             :  * Calculate 1st order low shelf filter
     791             :  *-----------------------------------------------------------------------------------------*/
     792             : 
     793             : 
     794        1744 : static void calc_low_shelf_first_order_filter_fx(
     795             :     Word16 *pNum, /* Q14 */
     796             :     Word16 *pDen, /* Q14 */
     797             :     const Word16 f0,
     798             :     const Word16 lin_gain_lf,
     799             :     const Word16 lin_gain_hf )
     800             : {
     801             :     Word16 sine_val, shift;
     802             :     Word16 cos_val, tmp, tan_val, tan_exp, gain_exp, exp, norm_num0, norm_num1, norm_den0, norm_den1;
     803             :     Word32 L_tmp;
     804             : 
     805        1744 :     tmp = mult( EVS_PI_BY_2_FX, f0 );
     806        1744 :     sine_val = getSinWord16( shl( tmp, 1 ) ); // Q15
     807             : 
     808        1744 :     tmp = mult( EVS_PI_BY_2_FX, f0 );
     809        1744 :     cos_val = getCosWord16( shl( tmp, 1 ) ); // Q14
     810             : 
     811        1744 :     tan_val = BASOP_Util_Divide1616_Scale( sine_val, cos_val, &tan_exp );
     812        1744 :     tan_exp = add( tan_exp, sub( 0, 1 ) );
     813             : 
     814             :     Word16 gain_fx;
     815        1744 :     gain_fx = BASOP_Util_Divide1616_Scale( lin_gain_lf, lin_gain_hf, &gain_exp );
     816             : 
     817        1744 :     IF( LT_16( gain_fx, 16384 ) )
     818             :     {
     819             : 
     820           7 :         tmp = mult( tan_val, gain_fx );
     821           7 :         norm_num0 = add( tan_exp, gain_exp );
     822           7 :         L_tmp = L_add( L_shl( 1, sub( 15, norm_num0 ) ), tmp );
     823           7 :         shift = norm_l( L_tmp );
     824           7 :         L_tmp = L_shl( L_tmp, shift );
     825           7 :         tmp = extract_h( L_tmp );
     826           7 :         pNum[0] = tmp;
     827           7 :         move16();
     828           7 :         norm_num0 = sub( norm_num0, sub( shift, 16 ) );
     829             : 
     830           7 :         tmp = mult( tan_val, gain_fx );
     831           7 :         norm_num1 = add( tan_exp, gain_exp );
     832           7 :         L_tmp = L_sub( tmp, L_shl( 1, sub( 15, norm_num1 ) ) );
     833           7 :         shift = norm_l( L_tmp );
     834           7 :         L_tmp = L_shl( L_tmp, shift );
     835           7 :         tmp = extract_h( L_tmp );
     836           7 :         pNum[1] = tmp;
     837           7 :         move16();
     838           7 :         norm_num1 = sub( norm_num1, sub( shift, 16 ) );
     839             : 
     840           7 :         L_tmp = L_add( L_shl( 1, sub( 15, tan_exp ) ), tan_val );
     841           7 :         shift = norm_l( L_tmp );
     842           7 :         L_tmp = L_shl( L_tmp, shift );
     843           7 :         tmp = extract_h( L_tmp );
     844           7 :         pDen[0] = tmp;
     845           7 :         move16();
     846           7 :         norm_den0 = sub( tan_exp, sub( shift, 16 ) );
     847             : 
     848           7 :         L_tmp = L_sub( tan_val, L_shl( 1, sub( 15, tan_exp ) ) );
     849           7 :         shift = norm_l( L_tmp );
     850           7 :         L_tmp = L_shl( L_tmp, shift );
     851           7 :         tmp = extract_h( L_tmp );
     852           7 :         pDen[1] = tmp;
     853           7 :         move16();
     854           7 :         norm_den1 = sub( tan_exp, sub( shift, 16 ) );
     855             :     }
     856             :     ELSE
     857             :     {
     858        1737 :         L_tmp = L_add( L_shl( 1, ( sub( 15, tan_exp ) ) ), tan_val );
     859        1737 :         shift = norm_l( L_tmp );
     860        1737 :         L_tmp = L_shl( L_tmp, shift );
     861        1737 :         tmp = extract_h( L_tmp );
     862        1737 :         pNum[0] = tmp;
     863        1737 :         move16();
     864        1737 :         norm_num0 = sub( tan_exp, sub( shift, 16 ) );
     865             : 
     866        1737 :         L_tmp = L_sub( tan_val, L_shl( 1, ( sub( 15, tan_exp ) ) ) );
     867        1737 :         shift = norm_l( L_tmp );
     868        1737 :         L_tmp = L_shl( L_tmp, shift );
     869        1737 :         tmp = extract_h( L_tmp );
     870        1737 :         pNum[1] = tmp;
     871        1737 :         move16();
     872        1737 :         norm_num1 = sub( tan_exp, sub( shift, 16 ) );
     873             : 
     874        1737 :         tmp = BASOP_Util_Divide1616_Scale( tan_val, gain_fx, &exp );
     875        1737 :         exp = add( exp, sub( tan_exp, gain_exp ) );
     876        1737 :         L_tmp = L_add( L_shl( 1, sub( 15, exp ) ), tmp );
     877        1737 :         shift = norm_l( L_tmp );
     878        1737 :         L_tmp = L_shl( L_tmp, shift );
     879        1737 :         tmp = extract_h( L_tmp );
     880        1737 :         pDen[0] = tmp;
     881        1737 :         move16();
     882        1737 :         norm_den0 = sub( exp, sub( shift, 16 ) );
     883             : 
     884        1737 :         tmp = BASOP_Util_Divide1616_Scale( tan_val, gain_fx, &exp );
     885        1737 :         exp = add( exp, sub( tan_exp, gain_exp ) );
     886        1737 :         L_tmp = L_sub( tmp, 1 * L_shl( 1, sub( 15, exp ) ) );
     887        1737 :         shift = norm_l( L_tmp );
     888        1737 :         L_tmp = L_shl( L_tmp, shift );
     889        1737 :         tmp = extract_h( L_tmp );
     890        1737 :         pDen[1] = tmp;
     891        1737 :         move16();
     892        1737 :         norm_den1 = sub( exp, sub( shift, 16 ) );
     893             :     }
     894             : 
     895             :     /* Normalize and adjust gain to match target amplitudes */
     896        1744 :     pNum[0] = mult( BASOP_Util_Divide1616_Scale( pNum[0], pDen[0], &exp ), lin_gain_hf );
     897        1744 :     move16();
     898        1744 :     norm_num0 = add( exp, sub( norm_num0, norm_den0 ) );
     899             : 
     900        1744 :     pNum[1] = mult( BASOP_Util_Divide1616_Scale( pNum[1], pDen[0], &exp ), lin_gain_hf );
     901        1744 :     move16();
     902        1744 :     norm_num1 = add( exp, sub( norm_num1, norm_den0 ) );
     903             : 
     904        1744 :     pDen[1] = BASOP_Util_Divide1616_Scale( pDen[1], pDen[0], &exp );
     905        1744 :     move16();
     906        1744 :     norm_den1 = add( exp, sub( norm_den1, norm_den0 ) );
     907             : 
     908        1744 :     pNum[0] = shr( pNum[0], sub( 1, norm_num0 ) ); // Q14
     909        1744 :     move16();
     910        1744 :     pNum[1] = shr( pNum[1], sub( 1, norm_num1 ) ); // Q14
     911        1744 :     move16();
     912        1744 :     pDen[1] = shr( pDen[1], sub( 1, norm_den1 ) ); // Q14
     913        1744 :     move16();
     914        1744 :     pDen[0] = shl( 1, 14 ); // Q14
     915        1744 :     move16();
     916        1744 :     return;
     917             : }
     918             : 
     919             : 
     920             : /*-----------------------------------------------------------------------------------------*
     921             :  * Function calc_jot_t60_coeffs()
     922             :  *
     923             :  * Calculate Jot reverb's T60 filters
     924             :  *-----------------------------------------------------------------------------------------*/
     925             : 
     926             : 
     927        1744 : static ivas_error calc_jot_t60_coeffs_fx(
     928             :     Word16 *pH_dB_fx,
     929             :     Word16 pH_dB_exp,
     930             :     const UWord16 nrFrequencies,
     931             :     Word16 *pFrequencies_fx,
     932             :     Word16 *pCoeffA_fx, /* Q14 */
     933             :     Word16 *pCoeffB_fx, /* Q14 */
     934             :     const Word16 fNyquist_fx )
     935             : {
     936             :     Word16 scale1, scale2, scale3, scale4;
     937        1744 :     Word16 ref_lf_min_norm_fx = BASOP_Util_Divide1616_Scale( REF_LF_MIN_FX, fNyquist_fx, &scale1 );
     938        1744 :     Word16 ref_lf_max_norm_fx = BASOP_Util_Divide1616_Scale( REF_LF_MAX_FX, fNyquist_fx, &scale2 );
     939        1744 :     Word16 ref_hf_min_norm_fx = BASOP_Util_Divide1616_Scale( REF_HF_MIN_FX, fNyquist_fx, &scale3 );
     940        1744 :     Word16 ref_hf_max_norm_fx = BASOP_Util_Divide1616_Scale( REF_HF_MAX_FX, fNyquist_fx, &scale4 );
     941             : 
     942        1744 :     ref_lf_min_norm_fx = shl( ref_lf_min_norm_fx, sub( scale1, 1 ) ); // Q14
     943        1744 :     ref_lf_max_norm_fx = shl( ref_lf_max_norm_fx, sub( scale2, 1 ) ); // Q14
     944        1744 :     ref_hf_min_norm_fx = shl( ref_hf_min_norm_fx, sub( scale3, 1 ) ); // Q14
     945        1744 :     ref_hf_max_norm_fx = shl( ref_hf_max_norm_fx, sub( scale4, 1 ) ); // Q14
     946             : 
     947             :     Word32 L_tmp;
     948             :     Word16 f0_fx, tmp_fx, lf_target_gain_dB_fx, hf_target_gain_dB_fx, mid_crossing_gain_dB_fx;
     949             :     Word16 lin_gain_lf_fx, lin_gain_hf_fx, shift, expl, exph;
     950        1744 :     Word16 f_idx, e = pH_dB_exp;
     951        1744 :     move16();
     952             :     UWord16 n_points_lf, n_points_hf;
     953             : 
     954        1744 :     lf_target_gain_dB_fx = 0;
     955        1744 :     move16();
     956        1744 :     hf_target_gain_dB_fx = 0;
     957        1744 :     move16();
     958        1744 :     Word32 minval_fx = 1455191552;
     959        1744 :     move32();
     960        1744 :     Word16 minval_e = 67, exp;
     961        1744 :     move16();
     962             : 
     963        1744 :     Word32 L_tmpl = 0, L_tmph = 0;
     964        1744 :     move32();
     965        1744 :     move32();
     966        1744 :     n_points_lf = 0;
     967        1744 :     move16();
     968        1744 :     n_points_hf = 0;
     969        1744 :     move16();
     970        1744 :     Word16 minidx_fx = sub( nrFrequencies, 1 );
     971             : 
     972      387488 :     FOR( f_idx = 0; f_idx < nrFrequencies; f_idx++ )
     973             :     {
     974      385744 :         test();
     975      385744 :         IF( GE_16( pFrequencies_fx[f_idx], ref_lf_min_norm_fx ) && LE_16( pFrequencies_fx[f_idx], ref_lf_max_norm_fx ) )
     976             :         {
     977        3200 :             L_tmpl = L_add( L_tmpl, pH_dB_fx[f_idx] );
     978        3200 :             n_points_lf = add( n_points_lf, 1 );
     979             :         }
     980      385744 :         test();
     981      385744 :         IF( GE_16( pFrequencies_fx[f_idx], ref_hf_min_norm_fx ) && LE_16( pFrequencies_fx[f_idx], ref_hf_max_norm_fx ) )
     982             :         {
     983       66440 :             L_tmph = L_add( L_tmph, pH_dB_fx[f_idx] );
     984       66440 :             n_points_hf = add( n_points_hf, 1 );
     985             :         }
     986             :     }
     987        1744 :     shift = norm_l( L_tmpl );
     988        1744 :     L_tmpl = L_shl( L_tmpl, shift );
     989        1744 :     tmp_fx = extract_h( L_tmpl );
     990        1744 :     expl = sub( e, sub( shift, 16 ) );
     991        1744 :     lf_target_gain_dB_fx = tmp_fx;
     992        1744 :     move16();
     993             : 
     994        1744 :     shift = norm_l( L_tmph );
     995        1744 :     L_tmph = L_shl( L_tmph, shift );
     996        1744 :     tmp_fx = extract_h( L_tmph );
     997        1744 :     exph = sub( e, sub( shift, 16 ) );
     998        1744 :     hf_target_gain_dB_fx = tmp_fx;
     999        1744 :     move16();
    1000             : 
    1001        1744 :     test();
    1002        1744 :     IF( ( n_points_lf == 0 ) || ( n_points_hf == 0 ) )
    1003             :     {
    1004           0 :         return IVAS_ERR_INTERNAL;
    1005             :     }
    1006             : 
    1007        1744 :     lf_target_gain_dB_fx = BASOP_Util_Divide1616_Scale( lf_target_gain_dB_fx, n_points_lf, &e );
    1008        1744 :     expl = add( e, sub( expl, 15 ) );
    1009             : 
    1010        1744 :     hf_target_gain_dB_fx = BASOP_Util_Divide1616_Scale( hf_target_gain_dB_fx, n_points_hf, &e );
    1011        1744 :     exph = add( e, sub( exph, 15 ) );
    1012             : 
    1013        1744 :     e = BASOP_Util_Add_MantExp( lf_target_gain_dB_fx, expl, negate( hf_target_gain_dB_fx ), exph, &tmp_fx );
    1014        1744 :     exp = BASOP_Util_Add_MantExp( hf_target_gain_dB_fx, exph, tmp_fx, e - 1, &mid_crossing_gain_dB_fx );
    1015             : 
    1016      384000 :     FOR( f_idx = 1; f_idx < nrFrequencies - 1; f_idx++ )
    1017             :     {
    1018             :         Word16 tmp1;
    1019      382256 :         e = BASOP_Util_Add_MantExp( pH_dB_fx[f_idx], pH_dB_exp, negate( mid_crossing_gain_dB_fx ), exp, &tmp_fx );
    1020      382256 :         tmp1 = abs_s( tmp_fx );
    1021             : 
    1022      382256 :         tmp_fx = BASOP_Util_Cmp_Mant32Exp( L_deposit_h( tmp1 ), e, minval_fx, minval_e );
    1023             : 
    1024      382256 :         IF( EQ_16( tmp_fx, -1 ) )
    1025             :         {
    1026       25199 :             minval_fx = L_deposit_h( tmp1 );
    1027       25199 :             minval_e = e;
    1028       25199 :             move16();
    1029       25199 :             minidx_fx = f_idx;
    1030       25199 :             move16();
    1031             :         }
    1032             :     }
    1033             : 
    1034        1744 :     f0_fx = pFrequencies_fx[minidx_fx];
    1035        1744 :     move16();
    1036             : 
    1037        1744 :     tmp_fx = mult( lf_target_gain_dB_fx, 5443 ); // expl
    1038        1744 :     L_tmp = BASOP_util_Pow2( L_deposit_h( tmp_fx ), expl, &e );
    1039        1744 :     lin_gain_lf_fx = extract_l( L_shr( L_tmp, sub( 16, e ) ) );
    1040             : 
    1041        1744 :     tmp_fx = mult( hf_target_gain_dB_fx, 5443 ); // exph
    1042        1744 :     L_tmp = BASOP_util_Pow2( L_deposit_h( tmp_fx ), exph, &e );
    1043        1744 :     lin_gain_hf_fx = extract_l( L_shr( L_tmp, sub( 16, e ) ) );
    1044             : 
    1045             : #ifdef FIX_1942_ASSERTION_LOWSHELF
    1046        1744 :     IF( EQ_16( lin_gain_hf_fx, 0 ) )
    1047             :     {
    1048           0 :         lin_gain_hf_fx = 1;
    1049           0 :         move16();
    1050             :     }
    1051             : #endif
    1052             :     /* call low-pass iir shelf */
    1053        1744 :     calc_low_shelf_first_order_filter_fx( pCoeffB_fx, pCoeffA_fx, f0_fx, lin_gain_lf_fx, lin_gain_hf_fx );
    1054        1744 :     return IVAS_ERR_OK;
    1055             : }
    1056             : 
    1057             : /*-----------------------------------------------------------------------------------------*
    1058             :  * Function initialize_reverb_filters()
    1059             :  *
    1060             :  * Set the number of branches (feedback loops) and Initializes the memory structure (pointers to data)
    1061             :  *-----------------------------------------------------------------------------------------*/
    1062         163 : static ivas_error initialize_reverb_filters_fx(
    1063             :     REVERB_HANDLE hReverb )
    1064             : {
    1065             :     ivas_error error;
    1066             : 
    1067         163 :     error = IVAS_ERR_OK;
    1068             : 
    1069             :     /* init correlation and coloration filters */
    1070         163 :     IF( NE_32( ( error = ivas_reverb_t2f_f2t_init( &hReverb->fft_filter_ols, hReverb->fft_size, hReverb->fft_subblock_size ) ), IVAS_ERR_OK ) )
    1071             :     {
    1072           0 :         return error;
    1073             :     }
    1074             : 
    1075         163 :     IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_correl_0, hReverb->fft_size ) ), IVAS_ERR_OK ) )
    1076             :     {
    1077           0 :         return error;
    1078             :     }
    1079             : 
    1080         163 :     IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_correl_1, hReverb->fft_size ) ), IVAS_ERR_OK ) )
    1081             :     {
    1082           0 :         return error;
    1083             :     }
    1084             : 
    1085         163 :     IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_color_0, hReverb->fft_size ) ), IVAS_ERR_OK ) )
    1086             :     {
    1087           0 :         return error;
    1088             :     }
    1089             : 
    1090         163 :     IF( NE_32( ( error = ivas_reverb_fft_filter_init( &hReverb->fft_filter_color_1, hReverb->fft_size ) ), IVAS_ERR_OK ) )
    1091             :     {
    1092           0 :         return error;
    1093             :     }
    1094             : 
    1095         163 :     return error;
    1096             : }
    1097             : 
    1098             : /*-----------------------------------------------------------------------------------------*
    1099             :  * Function set_t60_filter()
    1100             :  *
    1101             :  * Sets t60 number of taps and coefficients A and B
    1102             :  *-----------------------------------------------------------------------------------------*/
    1103             : 
    1104        1744 : static ivas_error set_t60_filter(
    1105             :     REVERB_HANDLE hReverb,
    1106             :     const UWord16 branch,
    1107             :     const UWord16 nr_taps,
    1108             :     const Word16 coefA[], /*Q14*/
    1109             :     const Word16 coefB[] /*Q14*/ )
    1110             : {
    1111        1744 :     IF( GE_32( branch, hReverb->nr_of_branches ) )
    1112             :     {
    1113           0 :         return IVAS_ERR_INTERNAL;
    1114             :     }
    1115             : 
    1116        1744 :     IF( GT_32( nr_taps, IVAS_REV_MAX_IIR_FILTER_LENGTH ) )
    1117             :     {
    1118           0 :         return IVAS_ERR_INTERNAL;
    1119             :     }
    1120             : 
    1121        1744 :     ivas_reverb_iir_filt_set( &( hReverb->t60[branch] ), nr_taps, coefA, coefB );
    1122             : 
    1123        1744 :     return IVAS_ERR_OK;
    1124             : }
    1125             : 
    1126             : /*-----------------------------------------------------------------------------------------*
    1127             :  * Function set_feedback_delay()
    1128             :  *
    1129             :  * Sets Delay of feedback branch in number of samples
    1130             :  *-----------------------------------------------------------------------------------------*/
    1131             : 
    1132        1304 : static ivas_error set_feedback_delay_fx(
    1133             :     REVERB_HANDLE hReverb,
    1134             :     const UWord16 branch,
    1135             :     const Word16 fb_delay /*Q0*/ )
    1136             : {
    1137        1304 :     IF( GE_32( branch, hReverb->nr_of_branches ) )
    1138             :     {
    1139           0 :         return IVAS_ERR_INTERNAL;
    1140             :     }
    1141             : 
    1142        1304 :     hReverb->delay_line[branch].Delay = fb_delay;
    1143        1304 :     move16();
    1144             : 
    1145        1304 :     return IVAS_ERR_OK;
    1146             : }
    1147             : /*-----------------------------------------------------------------------------------------*
    1148             :  * Function set_feedback_gain()
    1149             :  *
    1150             :  * Sets nr_of_branches feedback gain values in feedback matrix
    1151             :  *-----------------------------------------------------------------------------------------*/
    1152             : 
    1153        1304 : static ivas_error set_feedback_gain_fx(
    1154             :     REVERB_HANDLE hReverb,
    1155             :     const UWord16 branch,
    1156             :     const Word32 *pGain /*Q31*/ )
    1157             : {
    1158             :     UWord16 gain_idx;
    1159        1304 :     IF( GE_32( branch, hReverb->nr_of_branches ) )
    1160             :     {
    1161           0 :         return IVAS_ERR_INTERNAL;
    1162             :     }
    1163             : 
    1164       11736 :     FOR( gain_idx = 0; gain_idx < hReverb->nr_of_branches; gain_idx++ )
    1165             :     {
    1166       10432 :         hReverb->gain_matrix_fx[branch][gain_idx] = pGain[gain_idx]; // Q31
    1167       10432 :         move32();
    1168             :     }
    1169             : 
    1170        1304 :     return IVAS_ERR_OK;
    1171             : }
    1172             : /*-----------------------------------------------------------------------------------------*
    1173             :  * Function set_correl_fft_filter()
    1174             :  *
    1175             :  * Sets correlation filter complex gains
    1176             :  *-----------------------------------------------------------------------------------------*/
    1177             : 
    1178         436 : static ivas_error set_correl_fft_filter_fx(
    1179             :     REVERB_HANDLE hReverb,
    1180             :     const UWord16 channel,
    1181             :     rv_fftwf_type_complex_fx *pSpectrum )
    1182             : {
    1183         436 :     IF( GT_32( channel, 1 ) )
    1184             :     {
    1185           0 :         return IVAS_ERR_INTERNAL;
    1186             :     }
    1187             : 
    1188         436 :     IF( EQ_32( channel, 0 ) )
    1189             :     {
    1190         218 :         ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_correl_0.fft_spectrum_fx, hReverb->fft_filter_correl_0.fft_size );
    1191             :     }
    1192             :     ELSE
    1193             :     {
    1194         218 :         ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_correl_1.fft_spectrum_fx, hReverb->fft_filter_correl_1.fft_size );
    1195             :     }
    1196             : 
    1197         436 :     return IVAS_ERR_OK;
    1198             : }
    1199             : 
    1200             : 
    1201             : /*-----------------------------------------------------------------------------------------*
    1202             :  * Function set_color_fft_filter()
    1203             :  *
    1204             :  * Sets coloration filter complex gains
    1205             :  *-----------------------------------------------------------------------------------------*/
    1206             : 
    1207         436 : static ivas_error set_color_fft_filter_fx(
    1208             :     REVERB_HANDLE hReverb,
    1209             :     const UWord16 channel,
    1210             :     rv_fftwf_type_complex_fx *pSpectrum )
    1211             : {
    1212         436 :     IF( GT_32( channel, 1 ) )
    1213             :     {
    1214           0 :         return IVAS_ERR_INTERNAL;
    1215             :     }
    1216             : 
    1217         436 :     IF( EQ_32( channel, 0 ) )
    1218             :     {
    1219         218 :         ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_color_0.fft_spectrum_fx, hReverb->fft_filter_color_0.fft_size );
    1220             :     }
    1221             :     ELSE
    1222             :     {
    1223         218 :         ivas_reverb_fft_filter_ConvertFFTWF_2_FFTR_fx( pSpectrum, hReverb->fft_filter_color_1.fft_spectrum_fx, hReverb->fft_filter_color_1.fft_size );
    1224             :     }
    1225             : 
    1226         436 :     return IVAS_ERR_OK;
    1227             : }
    1228             : 
    1229             : 
    1230             : /*-----------------------------------------------------------------------------------------*
    1231             :  * Function set_mixer_level_fx()
    1232             :  *
    1233             :  * Sets Mixer level: to mix 2 output channels from 8 feedback branches
    1234             :  *-----------------------------------------------------------------------------------------*/
    1235             : 
    1236         326 : static ivas_error set_mixer_level_fx(
    1237             :     REVERB_HANDLE hReverb,
    1238             :     const UWord16 channel,
    1239             :     const Word16 level[] /*Q0*/ )
    1240             : {
    1241             :     UWord16 branch_idx;
    1242         326 :     IF( GE_32( channel, BINAURAL_CHANNELS ) )
    1243             :     {
    1244           0 :         return IVAS_ERR_INTERNAL;
    1245             :     }
    1246             : 
    1247        2934 :     FOR( branch_idx = 0; branch_idx < hReverb->nr_of_branches; branch_idx++ )
    1248             :     {
    1249        2608 :         hReverb->mixer_fx[channel][branch_idx] = level[branch_idx]; /*Q0*/
    1250        2608 :         move16();
    1251             :     }
    1252             : 
    1253         326 :     return IVAS_ERR_OK;
    1254             : }
    1255             : /*-----------------------------------------------------------------------------------------*
    1256             :  * Function clear_buffers_fx()
    1257             :  *
    1258             :  * Clears buffers of delay lines and filters
    1259             :  *-----------------------------------------------------------------------------------------*/
    1260             : 
    1261         163 : static void clear_buffers_fx(
    1262             :     REVERB_HANDLE hReverb )
    1263             : {
    1264             :     Word16 branch_idx;
    1265             :     ivas_rev_iir_filter_t *iirFilter;
    1266             :     ivas_rev_delay_line_t *delay_line;
    1267             : 
    1268        1467 :     FOR( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
    1269             :     {
    1270        1304 :         delay_line = &( hReverb->delay_line[branch_idx] );
    1271        1304 :         set32_fx( delay_line->pBuffer_fx, 0, delay_line->MaxDelay );
    1272        1304 :         delay_line->BufferPos = 0;
    1273        1304 :         move16();
    1274             : 
    1275        1304 :         iirFilter = &( hReverb->t60[branch_idx] );
    1276        1304 :         set32_fx( iirFilter->pBuffer_fx, 0, iirFilter->MaxTaps );
    1277             :     }
    1278             : 
    1279         163 :     ivas_reverb_t2f_f2t_ClearHistory( &hReverb->fft_filter_ols );
    1280             : 
    1281         163 :     return;
    1282             : }
    1283             : 
    1284             : /*-----------------------------------------------------------------------------------------*
    1285             :  * Function set_fft_and_datablock_sizes_fx()
    1286             :  *
    1287             :  * Sets frame size and fft-filter related sizes
    1288             :  *-----------------------------------------------------------------------------------------*/
    1289             : 
    1290         218 : static void set_fft_and_datablock_sizes_fx(
    1291             :     REVERB_HANDLE hReverb,
    1292             :     const Word16 subframe_len )
    1293             : {
    1294         218 :     hReverb->full_block_size = subframe_len;
    1295         218 :     IF( EQ_16( subframe_len, 240 /*L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES*/ ) )
    1296             :     {
    1297         127 :         hReverb->fft_size = IVAS_REVERB_FFT_SIZE_48K;
    1298         127 :         move16();
    1299         127 :         hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_48K;
    1300         127 :         move16();
    1301             :     }
    1302          91 :     ELSE IF( EQ_16( subframe_len, 160 /*L_FRAME32k / MAX_PARAM_SPATIAL_SUBFRAMES*/ ) )
    1303             :     {
    1304          30 :         hReverb->fft_size = IVAS_REVERB_FFT_SIZE_32K;
    1305          30 :         move16();
    1306          30 :         hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_32K;
    1307          30 :         move16();
    1308             :     }
    1309          61 :     ELSE IF( EQ_16( subframe_len, 80 /*L_FRAME16k / MAX_PARAM_SPATIAL_SUBFRAMES*/ ) )
    1310             :     {
    1311          61 :         hReverb->fft_size = IVAS_REVERB_FFT_SIZE_16K;
    1312          61 :         move16();
    1313          61 :         hReverb->num_fft_subblocks = IVAS_REVERB_FFT_N_SUBBLOCKS_16K;
    1314          61 :         move16();
    1315             :     }
    1316             :     ELSE
    1317             :     {
    1318           0 :         assert( 0 ); /* unsupported block size */
    1319             :     }
    1320             : 
    1321         218 :     hReverb->fft_subblock_size = (UWord16) idiv1616( subframe_len, hReverb->num_fft_subblocks );
    1322         218 :     move16();
    1323             : 
    1324         218 :     return;
    1325             : }
    1326             : 
    1327             : /*-----------------------------------------------------------------------------------------*
    1328             :  * Function set_reverb_acoustic_data_fx()
    1329             :  *
    1330             :  * Sets reverb acoustic data (room acoustics and HRTF), interpolating it to the filter grid
    1331             :  *-----------------------------------------------------------------------------------------*/
    1332             : 
    1333         218 : static void set_reverb_acoustic_data_fx(
    1334             :     ivas_reverb_params_t *pParams,
    1335             :     IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics,
    1336             :     const Word16 nr_fc_input,
    1337             :     const Word16 nr_fc_fft_filter )
    1338             : {
    1339             :     Word16 bin_idx;
    1340             :     Word32 ln_1e6_inverted_fx, delay_diff_fx, L_tmp;
    1341             :     Word32 exp_argument_fx, tmp;
    1342             :     Word16 pow_exp, exp_argument_e;
    1343             : 
    1344         218 :     Word32 *pFc_input_fx = pRoomAcoustics->pFc_input_fx;
    1345         218 :     Word32 *pAcoustic_rt60_fx = pRoomAcoustics->pAcoustic_rt60_fx;
    1346         218 :     Word32 *pAcoustic_dsr_fx = pRoomAcoustics->pAcoustic_dsr_fx;
    1347             : 
    1348         218 :     Word32 *pFc_fx = pParams->pFc_fx;
    1349         218 :     Word32 *pRt60_fx = pParams->pRt60_fx;
    1350         218 :     Word32 *pDsr_fx = pParams->pDsr_fx;
    1351             : 
    1352             :     /* interpolate input table data for T60 and DSR to the FFT filter grid */
    1353             : 
    1354         218 :     ivas_reverb_interp_on_freq_grid_fx( nr_fc_input, pFc_input_fx, pAcoustic_rt60_fx, nr_fc_fft_filter, pFc_fx, pRt60_fx ); // Q26
    1355         218 :     ivas_reverb_interp_on_freq_grid_fx( nr_fc_input, pFc_input_fx, pAcoustic_dsr_fx, nr_fc_fft_filter, pFc_fx, pDsr_fx );   // Q30
    1356             : 
    1357             :     ///* adjust DSR for the delay difference */
    1358             : 
    1359         218 :     delay_diff_fx = L_sub( pRoomAcoustics->inputPreDelay_fx, pRoomAcoustics->acousticPreDelay_fx ); // Q27
    1360             : 
    1361         218 :     ln_1e6_inverted_fx = 155440049; // Q31 /* 1.0f / logf( 1e06f ) */
    1362         218 :     move32();
    1363             : 
    1364       48436 :     FOR( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
    1365             :     {
    1366       48218 :         L_tmp = Mpy_32_32( pRt60_fx[bin_idx], ln_1e6_inverted_fx ); // Q26
    1367             : 
    1368       48218 :         exp_argument_fx = BASOP_Util_Divide3232_Scale_newton( delay_diff_fx, L_tmp, &exp_argument_e );
    1369       48218 :         exp_argument_fx = L_shr_sat( exp_argument_fx, sub( 6, exp_argument_e ) ); // Q26
    1370             : 
    1371             :         /* Limit exponent to approx +/-100 dB in case of incoherent value of delay_diff, to prevent overflow */
    1372       48218 :         IF( GT_32( exp_argument_fx, 1543503872 ) ) // 23 in Q26
    1373             :         {
    1374           0 :             exp_argument_fx = 1543503872;
    1375             :         }
    1376       48218 :         IF( LT_32( exp_argument_fx, -1543503872 ) ) // 23 in Q26
    1377             :         {
    1378           0 :             exp_argument_fx = -1543503872;
    1379             :         }
    1380             : 
    1381       48218 :         tmp = Mpy_32_32( 96817114, exp_argument_fx ); // Q21
    1382             : 
    1383       48218 :         L_tmp = BASOP_util_Pow2( tmp, 10, &pow_exp );
    1384       48218 :         L_tmp = Mpy_32_32( L_tmp, pDsr_fx[bin_idx] );
    1385       48218 :         L_tmp = L_shl_sat( L_tmp, add( 1, pow_exp ) ); // Q31
    1386             : 
    1387       48218 :         pDsr_fx[bin_idx] = L_tmp;
    1388       48218 :         move32();
    1389             :     }
    1390         218 :     return;
    1391             : }
    1392             : 
    1393             : 
    1394             : /*-----------------------------------------------------------------------------------------*
    1395             :  * Function setup_FDN_branches_fx()
    1396             :  *
    1397             :  * Sets up feedback delay network system
    1398             :  *-----------------------------------------------------------------------------------------*/
    1399             : 
    1400         163 : static ivas_error setup_FDN_branches_fx(
    1401             :     REVERB_HANDLE hReverb,
    1402             :     ivas_reverb_params_t *pParams )
    1403             : {
    1404             :     Word16 nr_coefs, branch_idx, channel_idx;
    1405             :     ivas_error error;
    1406             : #ifndef FIX_1053_REVERB_RECONFIGURATION
    1407             :     Word16 *pCoef_a, *pCoef_b;
    1408             : #endif
    1409         163 :     error = IVAS_ERR_OK;
    1410             : 
    1411             :     /* initialize feedback branches */
    1412        1467 :     FOR( branch_idx = 0; branch_idx < IVAS_REV_MAX_NR_BRANCHES; branch_idx++ )
    1413             :     {
    1414        1304 :         ivas_rev_delay_line_init( &( hReverb->delay_line[branch_idx] ), hReverb->loop_delay_buffer_fx[branch_idx], init_loop_delay[branch_idx], pParams->pLoop_delays[branch_idx] );
    1415        1304 :         ivas_reverb_iir_filt_init( &( hReverb->t60[branch_idx] ), IVAS_REV_MAX_IIR_FILTER_LENGTH );
    1416        1304 :         hReverb->mixer_fx[0][branch_idx] = 0;
    1417        1304 :         move16();
    1418        1304 :         hReverb->mixer_fx[1][branch_idx] = 0;
    1419        1304 :         move16();
    1420             :     }
    1421         163 :     clear_buffers_fx( hReverb );
    1422         163 :     nr_coefs = add( pParams->t60_filter_order, 1 );
    1423             : 
    1424         163 :     IF( LT_16( IVAS_REV_MAX_IIR_FILTER_LENGTH, nr_coefs ) )
    1425             :     {
    1426           0 :         return IVAS_ERR_INTERNAL;
    1427             :     }
    1428             :     ELSE
    1429             :     {
    1430        1467 :         FOR( branch_idx = 0; branch_idx < pParams->nr_loops; branch_idx++ )
    1431             :         {
    1432             : #ifndef FIX_1053_REVERB_RECONFIGURATION
    1433             :             pCoef_b = &pParams->pT60_filter_coeff_fx[shl( i_mult( nr_coefs, branch_idx ), 1 )];                  /*Q14*/
    1434             :             pCoef_a = &pParams->pT60_filter_coeff_fx[add( shl( i_mult( nr_coefs, branch_idx ), 1 ), nr_coefs )]; /*Q14*/
    1435             : 
    1436             :             IF( NE_32( ( error = set_t60_filter( hReverb, branch_idx, nr_coefs, pCoef_a, pCoef_b ) ), IVAS_ERR_OK ) )
    1437             :             {
    1438             :                 return error;
    1439             :             }
    1440             : #endif
    1441        1304 :             IF( NE_32( ( error = set_feedback_delay_fx( hReverb, branch_idx, pParams->pLoop_delays[branch_idx] ) ), IVAS_ERR_OK ) )
    1442             :             {
    1443           0 :                 return error;
    1444             :             }
    1445        1304 :             IF( NE_32( ( error = set_feedback_gain_fx( hReverb, branch_idx, &( pParams->pLoop_feedback_matrix_fx[i_mult( branch_idx, pParams->nr_loops )] ) ) ), IVAS_ERR_OK ) )
    1446             :             {
    1447           0 :                 return error;
    1448             :             }
    1449             :         }
    1450             :     }
    1451             : 
    1452         489 :     FOR( channel_idx = 0; channel_idx < pParams->nr_outputs; channel_idx++ )
    1453             :     {
    1454         326 :         IF( NE_32( ( error = set_mixer_level_fx( hReverb, channel_idx, &( pParams->pLoop_extract_matrix_fx[i_mult( channel_idx, pParams->nr_loops )] ) ) ), IVAS_ERR_OK ) )
    1455             :         {
    1456           0 :             return error;
    1457             :         }
    1458             :     }
    1459             : 
    1460         163 :     return error;
    1461             : }
    1462             : 
    1463             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    1464             : /*-------------------------------------------------------------------------
    1465             :  * ivas_reverb_open_fx()
    1466             :  *
    1467             :  * Allocate and initialize FDN reverberation handle
    1468             :  *------------------------------------------------------------------------*/
    1469             : #else
    1470             : /*-------------------------------------------------------------------------
    1471             :  * ivas_reverb_open_fx()
    1472             :  *
    1473             :  * Allocate and initialize Crend reverberation handle
    1474             :  *------------------------------------------------------------------------*/
    1475             : #endif
    1476         218 : ivas_error ivas_reverb_open_fx(
    1477             :     REVERB_HANDLE *hReverb,                        /* i/o: Reverberator handle               */
    1478             :     const HRTFS_STATISTICS_HANDLE hHrtfStatistics, /* i  : HRTF statistics handle            */
    1479             :     RENDER_CONFIG_HANDLE hRenderConfig,            /* i  : Renderer configuration handle     */
    1480             :     const Word32 output_Fs )
    1481             : {
    1482             :     ivas_error error;
    1483             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    1484         218 :     REVERB_HANDLE pState = *hReverb;
    1485             :     UWord16 nr_coefs, branch_idx;
    1486             :     Word16 *pCoef_a, *pCoef_b;
    1487             : #else
    1488             :     REVERB_HANDLE pState = NULL;
    1489             : #endif
    1490             :     Word16 bin_idx, subframe_len, output_frame, predelay_bf_len, loop_idx, i;
    1491             :     ivas_reverb_params_t params;
    1492             :     Word32 pColor_target_l_fx[RV_LENGTH_NR_FC];
    1493             :     Word32 pColor_target_r_fx[RV_LENGTH_NR_FC];
    1494             :     Word32 pTime_window_fx[RV_FILTER_MAX_FFT_SIZE];
    1495             :     Word32 freq_step_fx;
    1496             :     Word16 fft_hist_size, transition_start, transition_length;
    1497             :     Word16 nr_fc_input, nr_fc_fft_filter;
    1498             :     rv_fftwf_type_complex_fx pFft_wf_filter_ch0_fx[RV_LENGTH_NR_FC];
    1499             :     rv_fftwf_type_complex_fx pFft_wf_filter_ch1_fx[RV_LENGTH_NR_FC];
    1500             : 
    1501         218 :     error = IVAS_ERR_OK;
    1502         218 :     output_frame = extract_l( Mult_32_16( output_Fs, INV_FRAME_PER_SEC_Q15 ) );
    1503         218 :     subframe_len = shr( output_frame, 2 ); /*output_frame / MAX_PARAM_SPATIAL_SUBFRAMES*/
    1504         218 :     predelay_bf_len = output_frame;
    1505         218 :     move16();
    1506         218 :     nr_fc_input = hRenderConfig->roomAcoustics.nBands;
    1507             : 
    1508             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    1509         218 :     IF( *hReverb == NULL )
    1510             :     {
    1511         163 :         IF( ( pState = (REVERB_HANDLE) malloc( sizeof( REVERB_DATA ) ) ) == NULL )
    1512             :         {
    1513           0 :             return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for FDN Reverberator" );
    1514             :         }
    1515             :     }
    1516             : #else
    1517             :     /* Allocate main reverb. handle */
    1518             :     IF( ( pState = (REVERB_HANDLE) malloc( sizeof( REVERB_DATA ) ) ) == NULL )
    1519             :     {
    1520             :         return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Crend Reverberator " );
    1521             :     }
    1522             : #endif
    1523         218 :     IF( NE_32( ( error = set_base_config_fx( &params, output_Fs ) ), IVAS_ERR_OK ) )
    1524             :     {
    1525           0 :         return error;
    1526             :     }
    1527             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    1528         218 :     IF( *hReverb == NULL )
    1529             :     {
    1530             :         /* Allocate memory for feedback delay lines */
    1531        1467 :         FOR( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
    1532             :         {
    1533        1304 :             IF( ( pState->loop_delay_buffer_fx[loop_idx] = (Word32 *) malloc( params.pLoop_delays[loop_idx] * sizeof( Word32 ) ) ) == NULL )
    1534             :             {
    1535           0 :                 return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for FDN Reverberator" );
    1536             :             }
    1537             :         }
    1538             : 
    1539             :         /* Allocate memory for the pre-delay line */
    1540         163 :         IF( ( pState->pPredelay_buffer_fx = (Word32 *) malloc( output_frame * sizeof( Word32 ) ) ) == NULL )
    1541             :         {
    1542           0 :             return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for CREND Reverberator" );
    1543             :         }
    1544             :     }
    1545             : #else
    1546             :     /* Allocate memory for feedback delay lines */
    1547             :     FOR( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
    1548             :     {
    1549             :         IF( ( pState->loop_delay_buffer_fx[loop_idx] = (Word32 *) malloc( params.pLoop_delays[loop_idx] * sizeof( Word32 ) ) ) == NULL )
    1550             :         {
    1551             :             return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for CREND Reverberator" );
    1552             :         }
    1553             :     }
    1554             : 
    1555             :     /* Allocate memory for the pre-delay delay line */
    1556             :     IF( ( pState->pPredelay_buffer_fx = (Word32 *) malloc( output_frame * sizeof( Word32 ) ) ) == NULL )
    1557             :     {
    1558             :         return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for CREND Reverberator" );
    1559             :     }
    1560             : #endif
    1561         218 :     pState->nr_of_branches = IVAS_REV_MAX_NR_BRANCHES;
    1562         218 :     move16();
    1563         218 :     set_fft_and_datablock_sizes_fx( pState, subframe_len );
    1564             : 
    1565         218 :     nr_fc_fft_filter = add( extract_l( L_shr( pState->fft_size, 1 ) ), 1 );
    1566             : 
    1567             :     /* === 'Control logic': compute the reverb processing parameters from the              === */
    1568             :     /* === room, source and listener acoustic information provided in the reverb config    === */
    1569             :     /* Setting up shared temporary buffers for fc, RT60, DSR, etc.                             */
    1570             : #ifndef FIX_1053_REVERB_RECONFIGURATION
    1571             :     params.pHrtf_avg_pwr_response_l_fx = &pFft_wf_filter_ch0_fx[0][0];
    1572             :     params.pHrtf_avg_pwr_response_r_fx = params.pHrtf_avg_pwr_response_l_fx + nr_fc_fft_filter;
    1573             : #endif
    1574         218 :     params.pRt60_fx = &pFft_wf_filter_ch1_fx[0][0];
    1575         218 :     params.pDsr_fx = params.pRt60_fx + nr_fc_fft_filter;
    1576         218 :     params.pFc_fx = &pState->fft_filter_color_0.fft_spectrum_fx[0];
    1577             : #ifndef FIX_1053_REVERB_RECONFIGURATION
    1578             :     params.pHrtf_inter_aural_coherence_fx = &pState->fft_filter_color_1.fft_spectrum_fx[0];
    1579             : #endif
    1580         218 :     set32_fx( pState->fft_filter_color_1.fft_spectrum_fx, 0, RV_FILTER_MAX_FFT_SIZE );
    1581             :     /* Note: these temp buffers can only be used before the final step of the FFT filter design :     */
    1582             :     /* before calls to ivas_reverb_calc_correl_filters(...) or to ivas_reverb_calc_color_filters(...) */
    1583             : 
    1584             :     /* set the uniform frequency grid for FFT filtering                                               */
    1585         218 :     freq_step_fx = L_mult0( extract_l( L_shr( output_Fs, 2 ) ), div_s( 1, ( nr_fc_fft_filter - 1 ) ) ); /*Q14:0.5f * output_Fs / ( nr_fc_fft_filter - 1 )*/
    1586       48436 :     FOR( bin_idx = 0; bin_idx < nr_fc_fft_filter; bin_idx++ )
    1587             :     {
    1588       48218 :         params.pFc_fx[bin_idx] = W_extract_l( W_mult0_32_32( freq_step_fx, bin_idx ) ); /*Q16*/
    1589             :     }
    1590             : 
    1591         218 :     test();
    1592             : 
    1593             :     /* set up reverb acoustic data on the basis of HRTF data and renderer config  */
    1594         218 :     Scale_sig32( params.pFc_fx, nr_fc_fft_filter, 2 );
    1595             : 
    1596         218 :     set_reverb_acoustic_data_fx( &params, &hRenderConfig->roomAcoustics, nr_fc_input, nr_fc_fft_filter );
    1597             : 
    1598         218 :     params.pHrtf_avg_pwr_response_l_const_fx = hHrtfStatistics->average_energy_l;
    1599         218 :     params.pHrtf_avg_pwr_response_r_const_fx = hHrtfStatistics->average_energy_r;
    1600         218 :     params.pHrtf_inter_aural_coherence_const_fx = hHrtfStatistics->inter_aural_coherence;
    1601             : 
    1602             : 
    1603             :     /* set reverb acoustic configuration based on renderer config  */
    1604             : #ifndef FIX_587_DEFAULT_REVERB
    1605             :     pState->pConfig.roomAcoustics.override = hRenderConfig->roomAcoustics.override;
    1606             :     move16();
    1607             : #endif
    1608         218 :     pState->pConfig.roomAcoustics.nBands = hRenderConfig->roomAcoustics.nBands;
    1609         218 :     move16();
    1610             : 
    1611         218 :     IF( EQ_16( hRenderConfig->roomAcoustics.use_er, 1 ) )
    1612             :     {
    1613           7 :         pState->pConfig.roomAcoustics.use_er = hRenderConfig->roomAcoustics.use_er;
    1614           7 :         move16();
    1615           7 :         pState->pConfig.roomAcoustics.lowComplexity = hRenderConfig->roomAcoustics.lowComplexity;
    1616           7 :         move32();
    1617             :     }
    1618             : 
    1619             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    1620         218 :     IF( *hReverb == NULL )
    1621             :     {
    1622         163 :         pState->dmx_gain_fx = calc_dmx_gain_fx();
    1623             :     }
    1624             : #else
    1625             :     /*  set up input downmix  */
    1626             :     pState->dmx_gain_fx = calc_dmx_gain_fx();
    1627             : #endif
    1628             : 
    1629             :     /*  set up predelay - must be after set_base_config() and before compute_t60_coeffs() */
    1630         218 :     calc_predelay_fx( &params, hRenderConfig->roomAcoustics.acousticPreDelay_fx, output_Fs );
    1631             : 
    1632             :     /*  set up jot reverb 60 filters - must be set up after set_reverb_acoustic_data() */
    1633             : 
    1634         218 :     IF( NE_32( ( error = compute_t60_coeffs_fx( &params, nr_fc_fft_filter, output_Fs ) ), IVAS_ERR_OK ) )
    1635             :     {
    1636           0 :         return error;
    1637             :     }
    1638             :     /* Compute target levels (gains) for the coloration filters */
    1639         218 :     Word32 *pHrtf_avg_pwr_response_l_const = (Word32 *) malloc( nr_fc_fft_filter * sizeof( Word32 * ) );
    1640         218 :     Word32 *pHrtf_avg_pwr_response_r_const = (Word32 *) malloc( nr_fc_fft_filter * sizeof( Word32 * ) );
    1641         218 :     Word16 lenT60_filter_coeff = add( params.t60_filter_order, 1 );
    1642         218 :     lenT60_filter_coeff = add( i_mult( shl( lenT60_filter_coeff, 1 ), sub( params.nr_loops, 1 ) ), add( lenT60_filter_coeff, 2 ) );
    1643         218 :     Word32 *pT60_filter_coeff = (Word32 *) malloc( ( lenT60_filter_coeff ) * sizeof( Word32 * ) );
    1644             : 
    1645             : 
    1646       48436 :     FOR( i = 0; i < nr_fc_fft_filter; i++ )
    1647             :     {
    1648       48218 :         pHrtf_avg_pwr_response_l_const[i] = params.pHrtf_avg_pwr_response_l_const_fx[i]; /*Q28*/
    1649       48218 :         move32();
    1650       48218 :         pHrtf_avg_pwr_response_r_const[i] = params.pHrtf_avg_pwr_response_r_const_fx[i]; /*Q23+5*/
    1651       48218 :         move32();
    1652             :     }
    1653        7194 :     FOR( i = 0; i < lenT60_filter_coeff; i++ )
    1654             :     {
    1655        6976 :         pT60_filter_coeff[i] = L_shl_sat( params.pT60_filter_coeff_fx[i], 17 );
    1656        6976 :         move32();
    1657             :     }
    1658         218 :     ivas_reverb_calc_color_levels_fx( output_Fs, nr_fc_fft_filter, params.nr_loops, params.pFc_fx, params.pDsr_fx, pHrtf_avg_pwr_response_l_const, pHrtf_avg_pwr_response_r_const,
    1659             :                                       params.pLoop_delays, pT60_filter_coeff, pColor_target_l_fx, pColor_target_r_fx );
    1660             : 
    1661         218 :     free( pHrtf_avg_pwr_response_l_const );
    1662         218 :     free( pHrtf_avg_pwr_response_r_const );
    1663         218 :     free( pT60_filter_coeff );
    1664             : 
    1665             :     /* Defining appropriate windowing parameters for FFT filters to prevent aliasing */
    1666         218 :     fft_hist_size = sub( pState->fft_size, pState->fft_subblock_size );
    1667             : 
    1668         218 :     transition_start = round_fx( L_mult0( FFT_FILTER_WND_FLAT_REGION_FX, fft_hist_size ) );
    1669         218 :     transition_length = round_fx( L_mult0( FFT_FILTER_WND_TRANS_REGION_FX, fft_hist_size ) );
    1670             : 
    1671             :     /* Compute the window used for FFT filters */
    1672         218 :     ivas_reverb_define_window_fft_fx( pTime_window_fx, transition_start, transition_length, nr_fc_fft_filter );
    1673             : 
    1674             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    1675             :     /* === Copy parameters from ivas_reverb_params_t into DSP blocks   === */
    1676             :     /* === to be used for subsequent audio signal processing           === */
    1677         218 :     if ( *hReverb == NULL )
    1678             :     {
    1679         163 :         pState->do_corr_filter = params.do_corr_filter;
    1680         163 :         move16();
    1681             : 
    1682             :         /* clear & init jot reverb fft filters */
    1683         163 :         IF( NE_32( ( error = initialize_reverb_filters_fx( pState ) ), IVAS_ERR_OK ) )
    1684             :         {
    1685           0 :             return error;
    1686             :         }
    1687             :     }
    1688             : #else
    1689             :     /* === Now, copy parameters from ivas_reverb_params_t into DSP blocks   === */
    1690             :     /* === to be used for subsequent audio signal processing                === */
    1691             : 
    1692             :     pState->do_corr_filter = params.do_corr_filter;
    1693             :     move16();
    1694             : 
    1695             :     /* clear & init jot reverb fft filters */
    1696             :     IF( NE_32( ( error = initialize_reverb_filters_fx( pState ) ), IVAS_ERR_OK ) )
    1697             :     {
    1698             :         return error;
    1699             :     }
    1700             : #endif
    1701             : 
    1702         218 :     Word16 q_pFft_wf_filter_ch0_fx = 23, q_pFft_wf_filter_ch1_fx = 23;
    1703         218 :     move16();
    1704         218 :     move16();
    1705             : 
    1706             : 
    1707         218 :     IF( pState->do_corr_filter )
    1708             :     {
    1709             :         /* Computing correlation filters on the basis of target IA coherence */
    1710       96218 :         FOR( i = 0; i < shl( sub( nr_fc_fft_filter, 1 ), 1 ); i++ )
    1711             :         {
    1712       96000 :             pTime_window_fx[i] = L_shr( pTime_window_fx[i], 1 ); /*Scaling signal down to 30*/
    1713       96000 :             move32();
    1714             :         }
    1715             : 
    1716         218 :         Word32 *pHrtf_inter_aural_coherence_const = (Word32 *) malloc( nr_fc_fft_filter * sizeof( Word32 ) );
    1717       48436 :         FOR( i = 0; i < nr_fc_fft_filter; i++ )
    1718             :         {
    1719       48218 :             pHrtf_inter_aural_coherence_const[i] = L_shl( params.pHrtf_inter_aural_coherence_const_fx[i], 4 ); /*Scaling up to Q30*/
    1720       48218 :             move32();
    1721             :         }
    1722         218 :         ivas_reverb_calc_correl_filters_fx( pHrtf_inter_aural_coherence_const, pTime_window_fx, pState->fft_size, pFft_wf_filter_ch0_fx, pFft_wf_filter_ch1_fx, &q_pFft_wf_filter_ch0_fx, &q_pFft_wf_filter_ch1_fx );
    1723             : 
    1724         218 :         free( pHrtf_inter_aural_coherence_const );
    1725             : 
    1726       48436 :         FOR( i = 0; i < nr_fc_fft_filter; i++ )
    1727             :         {
    1728       48218 :             pFft_wf_filter_ch0_fx[i][0] = L_shl( pFft_wf_filter_ch0_fx[i][0], sub( 31, q_pFft_wf_filter_ch0_fx ) ); // Scale to Q31
    1729       48218 :             move32();
    1730       48218 :             pFft_wf_filter_ch0_fx[i][1] = L_shl( pFft_wf_filter_ch0_fx[i][1], sub( 31, q_pFft_wf_filter_ch0_fx ) ); // Scale to Q31
    1731       48218 :             move32();
    1732             :         }
    1733       48436 :         FOR( i = 0; i < nr_fc_fft_filter; i++ )
    1734             :         {
    1735       48218 :             pFft_wf_filter_ch1_fx[i][0] = L_shl( pFft_wf_filter_ch1_fx[i][0], sub( 31, q_pFft_wf_filter_ch1_fx ) ); // Scale to Q31
    1736       48218 :             move32();
    1737       48218 :             pFft_wf_filter_ch1_fx[i][1] = L_shl( pFft_wf_filter_ch1_fx[i][1], sub( 31, q_pFft_wf_filter_ch1_fx ) ); // Scale to Q31
    1738       48218 :             move32();
    1739             :         }
    1740             :         /* Copying the computed FFT correlation filters to the fft_filter components */
    1741         218 :         IF( NE_32( ( error = set_correl_fft_filter_fx( pState, 0, pFft_wf_filter_ch0_fx ) ), IVAS_ERR_OK ) )
    1742             :         {
    1743           0 :             return error;
    1744             :         }
    1745             : 
    1746         218 :         IF( NE_32( ( error = set_correl_fft_filter_fx( pState, 1, pFft_wf_filter_ch1_fx ) ), IVAS_ERR_OK ) )
    1747             :         {
    1748           0 :             return error;
    1749             :         }
    1750             :     }
    1751             : 
    1752             :     /* Computing coloration filters on the basis of target responses */
    1753             : 
    1754         218 :     ivas_reverb_calc_color_filters_fx( pColor_target_l_fx, pColor_target_r_fx, pTime_window_fx, pState->fft_size, pFft_wf_filter_ch0_fx, pFft_wf_filter_ch1_fx, &q_pFft_wf_filter_ch0_fx, &q_pFft_wf_filter_ch1_fx );
    1755       48436 :     FOR( i = 0; i < nr_fc_fft_filter; i++ )
    1756             :     {
    1757       48218 :         pFft_wf_filter_ch0_fx[i][0] = L_shl( pFft_wf_filter_ch0_fx[i][0], sub( 31, q_pFft_wf_filter_ch0_fx ) );
    1758       48218 :         move32();
    1759       48218 :         pFft_wf_filter_ch0_fx[i][1] = L_shl( pFft_wf_filter_ch0_fx[i][1], sub( 31, q_pFft_wf_filter_ch0_fx ) );
    1760       48218 :         move32();
    1761             :     }
    1762       48436 :     FOR( i = 0; i < nr_fc_fft_filter; i++ )
    1763             :     {
    1764       48218 :         pFft_wf_filter_ch1_fx[i][0] = L_shl( pFft_wf_filter_ch1_fx[i][0], sub( 31, q_pFft_wf_filter_ch1_fx ) );
    1765       48218 :         move32();
    1766       48218 :         pFft_wf_filter_ch1_fx[i][1] = L_shl( pFft_wf_filter_ch1_fx[i][1], sub( 31, q_pFft_wf_filter_ch1_fx ) );
    1767       48218 :         move32();
    1768             :     }
    1769             : #ifndef FIX_1053_REVERB_RECONFIGURATION
    1770             :     Scale_sig32( params.pHrtf_inter_aural_coherence_fx, nr_fc_fft_filter, 4 ); /*Scaling ( *hReverb )->fft_filter_color_0.fft_spectrum_fx to Q31*/
    1771             :     Scale_sig32( params.pFc_fx, nr_fc_fft_filter, 17 );                        /*Scaling ( *hReverb )->fft_filter_color_1.fft_spectrum_fx to Q31*/
    1772             : #endif
    1773             : 
    1774             :     /* Copying the computed FFT colorations filters to the fft_filter components */
    1775         218 :     IF( NE_32( ( error = set_color_fft_filter_fx( pState, 0, pFft_wf_filter_ch0_fx ) ), IVAS_ERR_OK ) )
    1776             :     {
    1777           0 :         return error;
    1778             :     }
    1779             : 
    1780         218 :     IF( NE_32( ( error = set_color_fft_filter_fx( pState, 1, pFft_wf_filter_ch1_fx ) ), IVAS_ERR_OK ) )
    1781             :     {
    1782           0 :         return error;
    1783             :     }
    1784             : 
    1785             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    1786         218 :     if ( *hReverb == NULL )
    1787             :     {
    1788             :         /* init predelay */
    1789         163 :         ivas_rev_delay_line_init( &( pState->predelay_line ), pState->pPredelay_buffer_fx, params.pre_delay, predelay_bf_len );
    1790             : 
    1791             :         /* set up feedback delay network */
    1792         163 :         if ( ( error = setup_FDN_branches_fx( pState, &params ) ) != IVAS_ERR_OK )
    1793             :         {
    1794           0 :             return error;
    1795             :         }
    1796             :     }
    1797             :     else
    1798             :     {
    1799          55 :         pState->predelay_line.Delay = params.pre_delay;
    1800             :     }
    1801             : 
    1802         218 :     nr_coefs = params.t60_filter_order + 1;
    1803             : 
    1804        1962 :     for ( branch_idx = 0; branch_idx < params.nr_loops; branch_idx++ )
    1805             :     {
    1806        1744 :         pCoef_a = &params.pT60_filter_coeff_fx[2 * nr_coefs * branch_idx + nr_coefs];
    1807        1744 :         pCoef_b = &params.pT60_filter_coeff_fx[2 * nr_coefs * branch_idx];
    1808             : 
    1809        1744 :         if ( ( error = set_t60_filter( pState, branch_idx, nr_coefs, pCoef_a, pCoef_b ) ) != IVAS_ERR_OK )
    1810             :         {
    1811           0 :             return error;
    1812             :         }
    1813             :     }
    1814             : #else
    1815             :     /* init predelay */
    1816             :     ivas_rev_delay_line_init( &( pState->predelay_line ), pState->pPredelay_buffer_fx, params.pre_delay, predelay_bf_len );
    1817             : 
    1818             :     /* set up feedback delay network */
    1819             :     IF( NE_32( ( error = setup_FDN_branches_fx( pState, &params ) ), IVAS_ERR_OK ) )
    1820             :     {
    1821             :         return error;
    1822             :     }
    1823             : #endif
    1824         218 :     *hReverb = pState;
    1825             : 
    1826         218 :     return error;
    1827             : }
    1828             : /*-------------------------------------------------------------------------
    1829             :  * ivas_reverb_close()
    1830             :  *
    1831             :  * Deallocate Crend reverberation handle
    1832             :  *------------------------------------------------------------------------*/
    1833             : 
    1834        4506 : void ivas_reverb_close(
    1835             :     REVERB_HANDLE *hReverb_in /* i/o: Reverberator handle       */
    1836             : )
    1837             : {
    1838             :     REVERB_HANDLE hReverb;
    1839             :     Word16 loop_idx;
    1840             : 
    1841        4506 :     hReverb = *hReverb_in;
    1842             : 
    1843        4506 :     test();
    1844        4506 :     IF( hReverb_in == NULL || *hReverb_in == NULL )
    1845             :     {
    1846        4343 :         return;
    1847             :     }
    1848             : 
    1849        1467 :     FOR( loop_idx = 0; loop_idx < IVAS_REV_MAX_NR_BRANCHES; loop_idx++ )
    1850             :     {
    1851        1304 :         IF( hReverb->loop_delay_buffer_fx[loop_idx] != NULL )
    1852             :         {
    1853        1304 :             free( hReverb->loop_delay_buffer_fx[loop_idx] );
    1854        1304 :             hReverb->loop_delay_buffer_fx[loop_idx] = NULL;
    1855             :         }
    1856             :     }
    1857             : 
    1858         163 :     free( hReverb->pPredelay_buffer_fx );
    1859         163 :     hReverb->pPredelay_buffer_fx = NULL;
    1860             : 
    1861         163 :     free( *hReverb_in );
    1862         163 :     *hReverb_in = NULL;
    1863             : 
    1864         163 :     return;
    1865             : }
    1866             : /*-----------------------------------------------------------------------------------------*
    1867             :  * Function post_fft_filter()
    1868             :  *
    1869             :  *
    1870             :  *-----------------------------------------------------------------------------------------*/
    1871             : 
    1872      376823 : static void post_fft_filter_fx(
    1873             :     REVERB_HANDLE hReverb,
    1874             :     Word32 *input_L_fx,
    1875             :     Word32 *input_R_fx,
    1876             :     Word32 *buffer_L_fx,
    1877             :     Word32 *buffer_R_fx )
    1878             : {
    1879             : 
    1880      376823 :     IF( hReverb->do_corr_filter )
    1881             :     {
    1882      376823 :         ivas_reverb_t2f_f2t_in_fx( &hReverb->fft_filter_ols, input_L_fx, input_R_fx, buffer_L_fx, buffer_R_fx );
    1883      376823 :         ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_correl_0, buffer_L_fx );
    1884      376823 :         ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_correl_1, buffer_R_fx );
    1885      376823 :         ivas_reverb_fft_filter_CrossMix_fx( buffer_L_fx, buffer_R_fx, hReverb->fft_filter_correl_0.fft_size );
    1886             :     }
    1887             :     ELSE
    1888             :     {
    1889           0 :         ivas_reverb_t2f_f2t_in_fx( &hReverb->fft_filter_ols, input_L_fx, input_R_fx, buffer_L_fx, buffer_R_fx );
    1890             :     }
    1891      376823 :     ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_color_0, buffer_L_fx );
    1892      376823 :     ivas_reverb_fft_filter_ComplexMul_fx( &hReverb->fft_filter_color_1, buffer_R_fx );
    1893      376823 :     ivas_reverb_t2f_f2t_out_fx( &hReverb->fft_filter_ols, buffer_L_fx, buffer_R_fx, input_L_fx, input_R_fx );
    1894             : 
    1895      376823 :     return;
    1896             : }
    1897             : /*-----------------------------------------------------------------------------------------*
    1898             :  * Function reverb_block()
    1899             :  *
    1900             :  * Input a block (mono) and calculate the 2 output blocks.
    1901             :  *-----------------------------------------------------------------------------------------*/
    1902             : 
    1903      376823 : static void reverb_block_fx(
    1904             :     REVERB_HANDLE hReverb,
    1905             :     Word32 *pInput_fx, /*Q11*/
    1906             :     Word32 *pOut0_fx,
    1907             :     Word32 *pOut1_fx )
    1908             : 
    1909             : {
    1910      376823 :     UWord16 nr_branches = hReverb->nr_of_branches;
    1911      376823 :     UWord16 bsize = hReverb->full_block_size;
    1912      376823 :     UWord16 inner_bsize = INNER_BLK_SIZE;
    1913             :     UWord16 i, j, k, ns, branch_idx, blk_idx, start_sample_idx;
    1914             :     Word32 *pFFT_buf[2], FFT_buf_1[RV_FILTER_MAX_FFT_SIZE], FFT_buf_2[RV_FILTER_MAX_FFT_SIZE];
    1915             :     Word32 pFeedback_input_fx[INNER_BLK_SIZE];
    1916             :     Word32 pTemp_fx[INNER_BLK_SIZE];
    1917             :     Word32 *ppOutput_fx[IVAS_REV_MAX_NR_BRANCHES];
    1918             :     Word32 Output_fx[IVAS_REV_MAX_NR_BRANCHES][INNER_BLK_SIZE];
    1919             :     Word16 shift;
    1920      376823 :     move16();
    1921      376823 :     move16();
    1922      376823 :     move16();
    1923             : 
    1924      376823 :     pFFT_buf[0] = &FFT_buf_1[0];
    1925      376823 :     pFFT_buf[1] = &FFT_buf_2[0];
    1926             : 
    1927     3391407 :     FOR( branch_idx = 0; branch_idx < nr_branches; branch_idx++ )
    1928             :     {
    1929     3014584 :         ppOutput_fx[branch_idx] = (Word32 *) Output_fx + i_mult( branch_idx, inner_bsize );
    1930             :     }
    1931             : 
    1932     1493759 :     FOR( k = 0; k < bsize; k += inner_bsize )
    1933             :     {
    1934     1116936 :         Word32 *pO0 = &pOut0_fx[k];
    1935     1116936 :         Word32 *pO1 = &pOut1_fx[k];
    1936    90471816 :         FOR( i = 0; i < inner_bsize; i++ )
    1937             :         {
    1938    89354880 :             pO0[i] = 0;
    1939    89354880 :             move16();
    1940    89354880 :             pO1[i] = 0;
    1941    89354880 :             move16();
    1942             :         }
    1943             : 
    1944             :         /* feedback network: */
    1945    10052424 :         FOR( i = 0; i < nr_branches; i++ )
    1946             :         {
    1947     8935488 :             Word32 *pOutput_i_fx = &ppOutput_fx[i][0];
    1948     8935488 :             Word16 mixer_0_i = hReverb->mixer_fx[0][i];
    1949     8935488 :             move16();
    1950     8935488 :             Word16 mixer_1_i = hReverb->mixer_fx[1][i];
    1951     8935488 :             move16();
    1952             :             /* output and feedback are same, get sample from delay line ... */
    1953     8935488 :             ivas_rev_delay_line_get_sample_blk_fx( &( hReverb->delay_line[i] ), inner_bsize, pTemp_fx );
    1954     8935488 :             ivas_reverb_iir_filt_2taps_feed_blk_fx( &( hReverb->t60[i] ), inner_bsize, pTemp_fx, ppOutput_fx[i] );
    1955   723774528 :             FOR( ns = 0; ns < inner_bsize; ns++ )
    1956             :             {
    1957   714839040 :                 pO0[ns] = L_add_sat( imult3216( pOutput_i_fx[ns], mixer_0_i ), pO0[ns] ); /* mixer ch 0 */
    1958   714839040 :                 move32();
    1959   714839040 :                 pO1[ns] = L_add_sat( imult3216( pOutput_i_fx[ns], mixer_1_i ), pO1[ns] ); /* mixer ch 1 */
    1960   714839040 :                 move32();
    1961             :             }
    1962             :         }
    1963             : 
    1964    10052424 :         FOR( i = 0; i < nr_branches; i++ )
    1965             :         {
    1966     8935488 :             Word32 *pIn = &pInput_fx[k];
    1967             : 
    1968   723774528 :             FOR( ns = 0; ns < inner_bsize; ns++ )
    1969             :             {
    1970   714839040 :                 pFeedback_input_fx[ns] = L_shr( pIn[ns], 3 ); // to make the Qfactor similar to pOutput
    1971   714839040 :                 move32();
    1972             :             }
    1973             : 
    1974    80419392 :             FOR( j = 0; j < nr_branches; j++ )
    1975             :             {
    1976    71483904 :                 Word32 gain_matrix_j_i = hReverb->gain_matrix_fx[j][i]; // Q31
    1977    71483904 :                 move32();
    1978    71483904 :                 Word32 *pOutput = &ppOutput_fx[j][0];
    1979  5790196224 :                 FOR( ns = 0; ns < inner_bsize; ns++ )
    1980             :                 {
    1981  5718712320 :                     pFeedback_input_fx[ns] = ( L_add_sat( Mpy_32_32( gain_matrix_j_i, pOutput[ns] ), pFeedback_input_fx[ns] ) );
    1982  5718712320 :                     move32();
    1983             :                 }
    1984             :             }
    1985             : 
    1986     8935488 :             ivas_rev_delay_line_feed_sample_blk_fx( &( hReverb->delay_line[i] ), inner_bsize, pFeedback_input_fx );
    1987             :         }
    1988             :     }
    1989             : 
    1990      376823 :     shift = s_min( L_norm_arr( pOut0_fx, hReverb->fft_filter_ols.block_size ), L_norm_arr( pOut1_fx, hReverb->fft_filter_ols.block_size ) );
    1991             : 
    1992      376823 :     IF( LT_16( shift, hReverb->fft_filter_ols.prev_shift ) )
    1993             :     {
    1994        1279 :         scale_sig32( pOut0_fx, hReverb->fft_filter_ols.block_size, shift );
    1995        1279 :         scale_sig32( pOut1_fx, hReverb->fft_filter_ols.block_size, shift );
    1996        1279 :         scale_sig32( hReverb->fft_filter_ols.fft_history_L_fx, hReverb->fft_filter_ols.hist_size, sub( shift, hReverb->fft_filter_ols.prev_shift ) );
    1997        1279 :         scale_sig32( hReverb->fft_filter_ols.fft_history_R_fx, hReverb->fft_filter_ols.hist_size, sub( shift, hReverb->fft_filter_ols.prev_shift ) );
    1998             : 
    1999        1279 :         hReverb->fft_filter_ols.prev_shift = shift;
    2000        1279 :         move16();
    2001             :     }
    2002             :     ELSE
    2003             :     {
    2004      375544 :         scale_sig32( pOut0_fx, hReverb->fft_filter_ols.block_size, hReverb->fft_filter_ols.prev_shift );
    2005      375544 :         scale_sig32( pOut1_fx, hReverb->fft_filter_ols.block_size, hReverb->fft_filter_ols.prev_shift );
    2006             : 
    2007      375544 :         shift = hReverb->fft_filter_ols.prev_shift;
    2008      375544 :         move16();
    2009             :     }
    2010             : 
    2011             :     Word16 r_shift;
    2012      376823 :     r_shift = add( find_guarded_bits_fx( hReverb->fft_filter_ols.fft_size ), 1 );
    2013             :     // Applying guard bits for the DoRTFT inside the post_fft_filter function
    2014    89731703 :     FOR( k = 0; k < hReverb->fft_filter_ols.block_size; k++ )
    2015             :     {
    2016    89354880 :         pOut0_fx[k] = (Word32) L_shr( pOut0_fx[k], ( r_shift ) );
    2017    89354880 :         move32();
    2018    89354880 :         pOut1_fx[k] = (Word32) L_shr( pOut1_fx[k], ( r_shift ) );
    2019    89354880 :         move32();
    2020             :     }
    2021             :     /* Applying FFT filter to each sub-frame */
    2022      753646 :     FOR( blk_idx = 0; blk_idx < hReverb->num_fft_subblocks; blk_idx++ )
    2023             :     {
    2024      376823 :         start_sample_idx = imult1616( blk_idx, hReverb->fft_subblock_size );
    2025      376823 :         post_fft_filter_fx( hReverb, pOut0_fx + start_sample_idx, pOut1_fx + start_sample_idx, pFFT_buf[0], pFFT_buf[1] );
    2026             :     }
    2027             : 
    2028    89731703 :     FOR( k = 0; k < hReverb->fft_filter_ols.block_size; k++ )
    2029             :     {
    2030    89354880 :         pOut0_fx[k] = (Word32) L_shl( pOut0_fx[k], sub( 1, shift ) );
    2031    89354880 :         move32();
    2032    89354880 :         pOut1_fx[k] = (Word32) L_shl( pOut1_fx[k], sub( 1, shift ) );
    2033    89354880 :         move32();
    2034             :     }
    2035             : 
    2036      376823 :     return;
    2037             : }
    2038             : /*-----------------------------------------------------------------------------------------*
    2039             :  * Function downmix_input_block()
    2040             :  *
    2041             :  * Downmix input to mono, taking also DSR gain into account
    2042             :  *-----------------------------------------------------------------------------------------*/
    2043             : 
    2044      376823 : static ivas_error downmix_input_block_fx(
    2045             :     const REVERB_HANDLE hReverb,
    2046             :     Word32 *pcm_in[], /* i Q11 : the input PCM audio   */
    2047             :     const AUDIO_CONFIG input_audio_config,
    2048             :     Word32 *pPcm_out, /* o Q11 : the output PCM audio   */
    2049             :     const Word16 input_offset )
    2050             : {
    2051             :     Word16 i, s, nchan_transport;
    2052      376823 :     Word32 dmx_gain_fx = hReverb->dmx_gain_fx;
    2053      376823 :     move32();
    2054      376823 :     SWITCH( input_audio_config )
    2055             :     {
    2056      317303 :         case IVAS_AUDIO_CONFIG_STEREO:
    2057             :         case IVAS_AUDIO_CONFIG_5_1:
    2058             :         case IVAS_AUDIO_CONFIG_7_1:
    2059             :         case IVAS_AUDIO_CONFIG_5_1_2:
    2060             :         case IVAS_AUDIO_CONFIG_5_1_4:
    2061             :         case IVAS_AUDIO_CONFIG_7_1_4:
    2062             :         case IVAS_AUDIO_CONFIG_ISM1:
    2063             :         case IVAS_AUDIO_CONFIG_ISM2:
    2064             :         case IVAS_AUDIO_CONFIG_ISM3:
    2065             :         case IVAS_AUDIO_CONFIG_ISM4:
    2066             :         {
    2067      317303 :             nchan_transport = audioCfg2channels( input_audio_config );
    2068    75515383 :             FOR( s = 0; s < hReverb->full_block_size; s++ )
    2069             :             {
    2070    75198080 :                 Word32 temp = pcm_in[0][add( input_offset, s )];
    2071    75198080 :                 move32();
    2072   203219840 :                 FOR( i = 1; i < nchan_transport; i++ )
    2073             :                 {
    2074   128021760 :                     temp = L_add( temp, pcm_in[i][add( input_offset, s )] );
    2075             :                 }
    2076    75198080 :                 pPcm_out[s] = W_extract_h( W_shl( W_mult0_32_32( dmx_gain_fx, temp ), 9 ) ); // ( Q23 + Q11 + Q9 ) - 32 = Q11
    2077    75198080 :                 move32();
    2078             :             }
    2079      317303 :             BREAK;
    2080             :         }
    2081       59520 :         case IVAS_AUDIO_CONFIG_MONO: /* ~'ZOA_1' */
    2082             :         case IVAS_AUDIO_CONFIG_FOA:
    2083             :         case IVAS_AUDIO_CONFIG_HOA2:
    2084             :         case IVAS_AUDIO_CONFIG_HOA3:
    2085             :         {
    2086    14216320 :             FOR( s = 0; s < hReverb->full_block_size; s++ )
    2087             :             {
    2088    14156800 :                 pPcm_out[s] = Mpy_32_32( dmx_gain_fx, L_shl_sat( pcm_in[0][input_offset + s], 8 ) ); //(Q23 + Q11 + Q8) - 31 = Q11
    2089    14156800 :                 move32();
    2090             :             }
    2091       59520 :             BREAK;
    2092             :         }
    2093           0 :         default:
    2094           0 :             return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported input format for reverb" );
    2095             :     }
    2096             : 
    2097      376823 :     return IVAS_ERR_OK;
    2098             : }
    2099             : /*-----------------------------------------------------------------------------------------*
    2100             :  * Function predelay_block()
    2101             :  *
    2102             :  * Perform a predelay
    2103             :  *-----------------------------------------------------------------------------------------*/
    2104             : 
    2105      376823 : static void predelay_block_fx(
    2106             :     const REVERB_HANDLE hReverb,
    2107             :     Word32 *pInput, /*Q11*/
    2108             :     Word32 *pOutput /*Q11*/ )
    2109             : {
    2110             :     UWord16 i, idx, n_samples, blk_size;
    2111      376823 :     UWord16 max_blk_size = (UWord16) hReverb->predelay_line.Delay;
    2112      376823 :     IF( LT_32( max_blk_size, 2 ) )
    2113             :     {
    2114           0 :         IF( max_blk_size == 0 ) /* zero-length delay line: just copy the data from input to output */
    2115             :         {
    2116           0 :             FOR( i = 0; i < hReverb->full_block_size; i++ )
    2117             :             {
    2118           0 :                 pOutput[i] = pInput[i]; // Q11
    2119           0 :                 move32();
    2120             :             }
    2121             :         }
    2122             :         ELSE /* 1-sample length delay line: feed the data sample-by-sample */
    2123             :         {
    2124           0 :             FOR( i = 0; i < hReverb->full_block_size; i++ )
    2125             :             {
    2126           0 :                 pOutput[i] = ivas_rev_delay_line_get_sample_fx( &( hReverb->predelay_line ) ); // Q11
    2127           0 :                 move32();
    2128           0 :                 ivas_rev_delay_line_feed_sample_fx( &( hReverb->predelay_line ), pInput[i] );
    2129             :             }
    2130             :         }
    2131             :     }
    2132             :     ELSE /* multiple-sample length delay line: use block processing */
    2133             :     {
    2134      376823 :         idx = 0;
    2135      376823 :         move16();
    2136      376823 :         n_samples = hReverb->full_block_size;
    2137     2260938 :         WHILE( n_samples > 0 )
    2138             :         {
    2139     1884115 :             blk_size = n_samples;
    2140     1884115 :             move16();
    2141     1884115 :             if ( GT_16( blk_size, max_blk_size ) )
    2142             :             {
    2143     1507292 :                 blk_size = max_blk_size;
    2144     1507292 :                 move16();
    2145             :             }
    2146     1884115 :             ivas_rev_delay_line_get_sample_blk_fx( &( hReverb->predelay_line ), blk_size, &pOutput[idx] );
    2147     1884115 :             ivas_rev_delay_line_feed_sample_blk_fx( &( hReverb->predelay_line ), blk_size, &pInput[idx] );
    2148     1884115 :             idx = (UWord16) UL_addNsD( idx, blk_size );
    2149     1884115 :             move16();
    2150     1884115 :             n_samples = (UWord16) UL_subNsD( n_samples, blk_size );
    2151     1884115 :             move16();
    2152             :         }
    2153             :     }
    2154             : 
    2155      376823 :     return;
    2156             : }
    2157             : /*-----------------------------------------------------------------------------------------*
    2158             :  * Function mix_output_block()
    2159             :  *
    2160             :  * mix one block of *pInL and *pInR samples into *pOutL and *pOutL respectively
    2161             :  *-----------------------------------------------------------------------------------------*/
    2162             : 
    2163      103880 : static void mix_output_block_fx(
    2164             :     const REVERB_HANDLE hReverb,
    2165             :     const Word32 *pInL,
    2166             :     const Word32 *pInR,
    2167             :     Word32 *pOutL,
    2168             :     Word32 *pOutR )
    2169             : {
    2170             :     UWord16 i;
    2171             : 
    2172    24100680 :     FOR( i = 0; i < hReverb->full_block_size; i++ )
    2173             :     {
    2174    23996800 :         pOutL[i] = L_add( pInL[i], ( L_shr( pOutL[i], 2 ) ) );
    2175    23996800 :         move32();
    2176    23996800 :         pOutR[i] = L_add( pInR[i], ( L_shr( pOutR[i], 2 ) ) );
    2177    23996800 :         move32();
    2178             :     }
    2179             : 
    2180      103880 :     return;
    2181             : }
    2182             : /*-----------------------------------------------------------------------------------------*
    2183             :  * ivas_reverb_process()
    2184             :  *
    2185             :  * Process the input PCM audio into output PCM audio, applying reverb
    2186             :  *-----------------------------------------------------------------------------------------*/
    2187             : 
    2188      376823 : ivas_error ivas_reverb_process_fx(
    2189             :     const REVERB_HANDLE hReverb,           /* i  : Reverberator handle                */
    2190             :     const AUDIO_CONFIG input_audio_config, /* i  : reverb. input audio configuration  */
    2191             :     const Word16 mix_signals,              /* i  : add reverb to output signal        */
    2192             :     Word32 *pcm_in_fx[],                   /* i Q11 : the PCM audio to apply reverb on   */
    2193             :     Word32 *pcm_out_fx[],                  /* o Q11 : the PCM audio with reverb applied  */
    2194             :     const Word16 i_ts                      /* i  : subframe index                     */
    2195             : )
    2196             : {
    2197             :     Word32 tmp0_fx[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp1_fx[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES], tmp2_fx[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
    2198             :     ivas_error error;
    2199             : 
    2200      376823 :     IF( NE_32( ( error = downmix_input_block_fx( hReverb, pcm_in_fx, input_audio_config, tmp1_fx, i_ts * hReverb->full_block_size ) ), IVAS_ERR_OK ) )
    2201             :     {
    2202           0 :         return error;
    2203             :     }
    2204             : 
    2205      376823 :     predelay_block_fx( hReverb, tmp1_fx, tmp0_fx );
    2206             : 
    2207      376823 :     reverb_block_fx( hReverb, tmp0_fx, tmp1_fx, tmp2_fx );
    2208             : 
    2209      376823 :     IF( mix_signals )
    2210             :     {
    2211      103880 :         mix_output_block_fx( hReverb, tmp1_fx, tmp2_fx, &pcm_out_fx[0][i_ts * hReverb->full_block_size], &pcm_out_fx[1][i_ts * hReverb->full_block_size] );
    2212             :     }
    2213             :     ELSE
    2214             :     {
    2215      272943 :         MVR2R_WORD32( tmp1_fx, &pcm_out_fx[0][i_mult( i_ts, hReverb->full_block_size )], hReverb->full_block_size );
    2216      272943 :         MVR2R_WORD32( tmp2_fx, &pcm_out_fx[1][i_mult( i_ts, hReverb->full_block_size )], hReverb->full_block_size );
    2217             :     }
    2218             : 
    2219      376823 :     return IVAS_ERR_OK;
    2220             : }
    2221             : 
    2222             : /*-------------------------------------------------------------------------
    2223             :  * ivas_binaural_reverb_processSubFrame()
    2224             :  *
    2225             :  * Compute the reverberation - room effect
    2226             :  *------------------------------------------------------------------------*/
    2227             : 
    2228             : 
    2229             : /*-------------------------------------------------------------------------
    2230             :  * ivas_binaural_reverb_processSubFrame_fx()
    2231             :  *
    2232             :  * Compute the reverberation - room effect
    2233             :  *------------------------------------------------------------------------*/
    2234             : 
    2235      219612 : void ivas_binaural_reverb_processSubframe_fx(
    2236             :     REVERB_STRUCT_HANDLE hReverb,                                      /* i/o: binaural reverb handle      */
    2237             :     const Word16 numInChannels,                                        /* i  : num inputs to be processed  */
    2238             :     const Word16 numSlots,                                             /* i  : number of slots to be processed    */
    2239             :     Word32 inReal[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX],  /* i (Q_in) : input CLDFB data real, Comment: This change swaps two first dimensions as first dimension is not constant. */
    2240             :     Word32 inImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX],  /* i (Q_in) : input CLDFB data imag       */
    2241             :     Word32 outReal[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* o (Q_in) : output CLDFB data real      */
    2242             :     Word32 outImag[][CLDFB_SLOTS_PER_SUBFRAME][CLDFB_NO_CHANNELS_MAX]  /* o (Q_in) : output CLDFB data imag      */
    2243             : )
    2244             : {
    2245             :     /* Declare the required variables */
    2246             :     Word16 idx, bin, ch, sample, invertSampleIndex, tapIdx, *phaseShiftTypePr;
    2247             :     Word32 **tapRealPr_fx, **tapImagPr_fx;
    2248      219612 :     push_wmops( "binaural_reverb" );
    2249             : 
    2250             :     /* 1) Rotate the data in the loop buffer of the reverberator.
    2251             :      * Notice that the audio at the loop buffers is at time-inverted order
    2252             :      * for convolution purposes later on. */
    2253    10225032 :     FOR( bin = 0; bin < hReverb->numBins; bin++ )
    2254             :     {
    2255             :         /* Move the data forwards by blockSize (i.e. by the frame size of 16 CLDFB slots) */
    2256    10005420 :         Copy32( hReverb->loopBufReal_fx[bin], hReverb->loopBufReal_fx[bin] + numSlots, hReverb->loopBufLength[bin] );
    2257    10005420 :         Copy32( hReverb->loopBufImag_fx[bin], hReverb->loopBufImag_fx[bin] + numSlots, hReverb->loopBufLength[bin] );
    2258             : 
    2259             :         /* Add the data from the end of the loop to the beginning, with an attenuation factor
    2260             :          * according to RT60. This procedure generates an IIR decaying response. The response
    2261             :          * is decorrelated later on. */
    2262    10005420 :         v_multc_fixed( hReverb->loopBufReal_fx[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor_fx[bin], hReverb->loopBufReal_fx[bin], numSlots );
    2263    10005420 :         v_multc_fixed( hReverb->loopBufImag_fx[bin] + hReverb->loopBufLength[bin], hReverb->loopAttenuationFactor_fx[bin], hReverb->loopBufImag_fx[bin], numSlots );
    2264             :     }
    2265             : 
    2266             :     /* 2) Apply the determined pre-delay to the input audio, and add the delayed audio to the loop. */
    2267      219612 :     idx = hReverb->preDelayBufferIndex;
    2268     1093585 :     FOR( sample = 0; sample < numSlots; sample++ )
    2269             :     {
    2270      873973 :         invertSampleIndex = sub( sub( numSlots, sample ), 1 );
    2271             : 
    2272    40657573 :         FOR( bin = 0; bin < hReverb->numBins; bin++ )
    2273             :         {
    2274             :             /* Add from pre-delay buffer a sample to the loop buffer, in a time-inverted order.
    2275             :              * Also apply the spectral gains determined for the reverberation */
    2276    39783600 :             Word32 temp_1 = Mpy_32_32( hReverb->preDelayBufferReal_fx[idx][bin], hReverb->reverbEqGains_fx[bin] );              /*Q_in*/
    2277    39783600 :             Word32 temp_2 = Mpy_32_32( hReverb->preDelayBufferImag_fx[idx][bin], hReverb->reverbEqGains_fx[bin] );              /*Q_in*/
    2278    39783600 :             hReverb->loopBufReal_fx[bin][invertSampleIndex] = L_add( hReverb->loopBufReal_fx[bin][invertSampleIndex], temp_1 ); /*Q_in*/
    2279    39783600 :             move32();
    2280    39783600 :             hReverb->loopBufImag_fx[bin][invertSampleIndex] = L_add( hReverb->loopBufImag_fx[bin][invertSampleIndex], temp_2 ); /*Q_in*/
    2281    39783600 :             move32();
    2282    39783600 :             hReverb->preDelayBufferReal_fx[idx][bin] = 0;
    2283    39783600 :             move32();
    2284    39783600 :             hReverb->preDelayBufferImag_fx[idx][bin] = 0;
    2285    39783600 :             move32();
    2286             :         }
    2287             : 
    2288             :         /* Add every second input channel as is to the pre-delay buffer, and every second input channel with
    2289             :          * 90 degrees phase shift to reduce energy imbalances between coherent and incoherent sounds */
    2290     2643727 :         FOR( ch = 0; ch < numInChannels; ch++ )
    2291             :         {
    2292     1769754 :             IF( s_and( ch, 1 ) )
    2293             :             {
    2294      880053 :                 v_add_fixed_no_hdrm( hReverb->preDelayBufferReal_fx[idx], inReal[ch][sample], hReverb->preDelayBufferReal_fx[idx], hReverb->numBins );
    2295      880053 :                 v_add_fixed_no_hdrm( hReverb->preDelayBufferImag_fx[idx], inImag[ch][sample], hReverb->preDelayBufferImag_fx[idx], hReverb->numBins );
    2296             :             }
    2297             :             ELSE
    2298             :             {
    2299      889701 :                 v_sub_fixed_no_hdrm( hReverb->preDelayBufferReal_fx[idx], inImag[ch][sample], hReverb->preDelayBufferReal_fx[idx], hReverb->numBins );
    2300      889701 :                 v_add_fixed_no_hdrm( hReverb->preDelayBufferImag_fx[idx], inReal[ch][sample], hReverb->preDelayBufferImag_fx[idx], hReverb->numBins );
    2301             :             }
    2302             :         }
    2303      873973 :         idx = add( idx, 1 ) % hReverb->preDelayBufferLength;
    2304      873973 :         move16();
    2305             :     }
    2306      219612 :     hReverb->preDelayBufferIndex = idx;
    2307      219612 :     move16();
    2308             : 
    2309             :     /* 3) Perform the filtering/decorrelating, using complex and sparse FIR filtering */
    2310    10225032 :     FOR( bin = 0; bin < hReverb->numBins; bin++ )
    2311             :     {
    2312    30016260 :         FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
    2313             :         {
    2314             :             /* These tap pointers have been determined to point to the loop buffer at sparse locations */
    2315    20010840 :             tapRealPr_fx = hReverb->tapPointersReal_fx[bin][ch];
    2316    20010840 :             tapImagPr_fx = hReverb->tapPointersImag_fx[bin][ch];
    2317             : 
    2318    20010840 :             phaseShiftTypePr = hReverb->tapPhaseShiftType[bin][ch];
    2319             : 
    2320             :             /* Flush output */
    2321    20010840 :             set32_fx( hReverb->outputBufferReal_fx[bin][ch], 0, numSlots );
    2322    20010840 :             set32_fx( hReverb->outputBufferImag_fx[bin][ch], 0, numSlots );
    2323             : 
    2324             :             /* Add from temporally decaying sparse tap locations the audio to the output. */
    2325   489931624 :             FOR( tapIdx = 0; tapIdx < hReverb->taps[bin][ch]; tapIdx++ )
    2326             :             {
    2327   469920784 :                 SWITCH( phaseShiftTypePr[tapIdx] )
    2328             :                 {
    2329   115301180 :                     case 0: /* 0 degrees phase */
    2330   115301180 :                         v_add_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
    2331   115301180 :                         v_add_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
    2332   115301180 :                         BREAK;
    2333   122777730 :                     case 1: /* 90 degrees phase */
    2334   122777730 :                         v_sub_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
    2335   122777730 :                         v_add_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
    2336   122777730 :                         BREAK;
    2337   118016723 :                     case 2: /* 180 degrees phase */
    2338   118016723 :                         v_sub_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
    2339   118016723 :                         v_sub_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
    2340   118016723 :                         BREAK;
    2341   113825151 :                     default: /* 270 degrees phase */
    2342   113825151 :                         v_add_fixed_no_hdrm( hReverb->outputBufferReal_fx[bin][ch], tapImagPr_fx[tapIdx], hReverb->outputBufferReal_fx[bin][ch], numSlots );
    2343   113825151 :                         v_sub_fixed_no_hdrm( hReverb->outputBufferImag_fx[bin][ch], tapRealPr_fx[tapIdx], hReverb->outputBufferImag_fx[bin][ch], numSlots );
    2344   113825151 :                         BREAK;
    2345             :                 }
    2346             :             }
    2347             :         }
    2348             : 
    2349             :         /* Generate diffuse field binaural coherence by mixing the incoherent reverberated channels with pre-defined gains */
    2350    10005420 :         IF( LE_16( bin, hReverb->highestBinauralCoherenceBin ) )
    2351             :         {
    2352     1487634 :             IF( hReverb->useBinauralCoherence )
    2353             :             {
    2354     7408805 :                 FOR( sample = 0; sample < numSlots; sample++ )
    2355             :                 {
    2356             :                     Word32 leftRe_fx, rightRe_fx, leftIm_fx, rightIm_fx;
    2357             : 
    2358     5921171 :                     leftRe_fx = Madd_32_32( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferReal_fx[bin][0][sample] ),
    2359     5921171 :                                             hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferReal_fx[bin][1][sample] ); // Q_in
    2360     5921171 :                     rightRe_fx = Madd_32_32( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferReal_fx[bin][1][sample] ),
    2361     5921171 :                                              hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferReal_fx[bin][0][sample] ); // Q_in
    2362     5921171 :                     leftIm_fx = Madd_32_32( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferImag_fx[bin][0][sample] ),
    2363     5921171 :                                             hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferImag_fx[bin][1][sample] ); // Q_in
    2364     5921171 :                     rightIm_fx = Madd_32_32( Mpy_32_32( hReverb->binauralCoherenceDirectGains_fx[bin], hReverb->outputBufferImag_fx[bin][1][sample] ),
    2365     5921171 :                                              hReverb->binauralCoherenceCrossmixGains_fx[bin], hReverb->outputBufferImag_fx[bin][0][sample] ); // Q_in
    2366             : 
    2367     5921171 :                     hReverb->outputBufferReal_fx[bin][0][sample] = leftRe_fx; // Q_in
    2368     5921171 :                     move32();
    2369     5921171 :                     hReverb->outputBufferReal_fx[bin][1][sample] = rightRe_fx; // Q_in
    2370     5921171 :                     move32();
    2371     5921171 :                     hReverb->outputBufferImag_fx[bin][0][sample] = leftIm_fx; // Q_in
    2372     5921171 :                     move32();
    2373     5921171 :                     hReverb->outputBufferImag_fx[bin][1][sample] = rightIm_fx; // Q_in
    2374     5921171 :                     move32();
    2375             :                 }
    2376             :             }
    2377             :         }
    2378             :     }
    2379             : 
    2380             :     /* 4) Write data to output */
    2381      658836 :     FOR( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
    2382             :     {
    2383     2187170 :         FOR( sample = 0; sample < numSlots; sample++ )
    2384             :         {
    2385             :             /* Audio was in the temporally inverted order for convolution, re-invert audio to output */
    2386     1747946 :             invertSampleIndex = sub( sub( numSlots, sample ), 1 );
    2387             : 
    2388    81315146 :             FOR( bin = 0; bin < hReverb->numBins; bin++ )
    2389             :             {
    2390    79567200 :                 outReal[ch][sample][bin] = hReverb->outputBufferReal_fx[bin][ch][invertSampleIndex]; // Q_in
    2391    79567200 :                 move32();
    2392    79567200 :                 outImag[ch][sample][bin] = hReverb->outputBufferImag_fx[bin][ch][invertSampleIndex]; // Q_in
    2393    79567200 :                 move32();
    2394             :             }
    2395    27057506 :             FOR( ; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
    2396             :             {
    2397    25309560 :                 outReal[ch][sample][bin] = 0;
    2398    25309560 :                 move32();
    2399    25309560 :                 outImag[ch][sample][bin] = 0;
    2400    25309560 :                 move32();
    2401             :             }
    2402             :         }
    2403             :     }
    2404             : 
    2405      219612 :     pop_wmops();
    2406      219612 :     return;
    2407             : }
    2408             : 
    2409             : /*-------------------------------------------------------------------------
    2410             :  * ivas_binaural_reverb_open()
    2411             :  *
    2412             :  * Allocate and initialize binaural room reverberator handle
    2413             :  *------------------------------------------------------------------------*/
    2414         477 : static ivas_error ivas_binaural_reverb_open_fx(
    2415             :     REVERB_STRUCT_HANDLE *hReverbPr,    /* i/o: binaural reverb handle                                  */
    2416             :     const Word16 numBins,               /* i  : Q0 number of CLDFB bins                                    */
    2417             :     const Word16 numCldfbSlotsPerFrame, /* i  : Q0 number of CLDFB slots per frame                         */
    2418             :     const Word32 sampling_rate,         /* i  : Q0 sampling rate                                           */
    2419             :     const Word32 *revTimes_fx,          /* i  : Q26 reverberation times T60 for each CLDFB bin in seconds   */
    2420             :     const Word32 *revEnes_fx,           /* i  : Q31 spectrum for reverberated sound at each CLDFB bin       */
    2421             :     const Word16 preDelay               /* i  : Q0 reverb pre-delay in CLDFB slots                         */
    2422             : )
    2423             : {
    2424             :     Word16 bin, chIdx, k, len, scale, tmp;
    2425             :     REVERB_STRUCT_HANDLE hReverb;
    2426             : 
    2427         477 :     IF( ( *hReverbPr = (REVERB_STRUCT_HANDLE) malloc( sizeof( REVERB_STRUCT ) ) ) == NULL )
    2428             :     {
    2429           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2430             :     }
    2431             : 
    2432         477 :     hReverb = *hReverbPr;
    2433             : 
    2434         477 :     hReverb->useBinauralCoherence = 1;
    2435         477 :     move16();
    2436         477 :     hReverb->preDelayBufferLength = 1;
    2437         477 :     move16();
    2438         477 :     hReverb->preDelayBufferIndex = 0;
    2439         477 :     move16();
    2440             : 
    2441         477 :     hReverb->numBins = numBins;
    2442         477 :     move16();
    2443         477 :     hReverb->blockSize = numCldfbSlotsPerFrame;
    2444         477 :     move16();
    2445             : 
    2446       10494 :     FOR( k = 0; k < REVERB_PREDELAY_MAX + 1; k++ )
    2447             :     {
    2448       10017 :         set32_fx( hReverb->preDelayBufferReal_fx[k], 0, hReverb->numBins );
    2449       10017 :         set32_fx( hReverb->preDelayBufferImag_fx[k], 0, hReverb->numBins );
    2450             :     }
    2451             : 
    2452       20747 :     FOR( bin = 0; bin < hReverb->numBins; bin++ )
    2453             :     {
    2454             :         /* Loop Buffer */
    2455             : 
    2456       20270 :         tmp = BASOP_Util_Divide1616_Scale( 500, add( bin, 1 ), &scale );
    2457       20270 :         tmp = shr( tmp, sub( 15, scale ) );
    2458       20270 :         hReverb->loopBufLengthMax[bin] = add( tmp, sub( CLDFB_NO_CHANNELS_MAX, bin ) );
    2459             :         // hReverb->loopBufLengthMax[bin] = (Word16) ( 500 / ( 1 + bin ) + ( CLDFB_NO_CHANNELS_MAX - bin ) );
    2460             : 
    2461       20270 :         len = add( hReverb->loopBufLengthMax[bin], hReverb->blockSize );
    2462             : 
    2463       20270 :         IF( ( hReverb->loopBufReal_fx[bin] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
    2464             :         {
    2465           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2466             :         }
    2467             : 
    2468       20270 :         if ( ( hReverb->loopBufImag_fx[bin] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
    2469             :         {
    2470           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2471             :         }
    2472       20270 :         set32_fx( hReverb->loopBufReal_fx[bin], 0, len );
    2473       20270 :         set32_fx( hReverb->loopBufImag_fx[bin], 0, len );
    2474             : 
    2475             :         /* Determine loop buffer length. The following formula is manually tuned to generate sufficiently long
    2476             :          * but not excessively long loops to generate reverberation. */
    2477             :         /* Note: the resulted length is very sensitive to the precision of the constants below (e.g. 1.45 vs. 1.45f) */
    2478             :         // hReverb->loopBufLength[bin] = (int16_t) ( 1.45 * (int16_t) ( revTimes[bin] * 150.0 ) + 1 );
    2479       20270 :         Word32 L_tmp_BufLength = L_shl( L_shr( Mpy_32_32( revTimes_fx[bin], 1258291200 /*150.0 in Q23*/ ), 18 ), 18 );
    2480       20270 :         L_tmp_BufLength = L_add( Mpy_32_32( 1556925645 /*1.45 in Q30*/, L_tmp_BufLength ), ONE_IN_Q17 );
    2481       20270 :         hReverb->loopBufLength[bin] = (Word16) L_shr( L_tmp_BufLength, 17 ); /*Q0*/
    2482       20270 :         move16();
    2483       20270 :         hReverb->loopBufLength[bin] = s_min( hReverb->loopBufLength[bin], hReverb->loopBufLengthMax[bin] );
    2484             : 
    2485             :         /* Sparse Filter Tap Locations */
    2486       60810 :         FOR( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
    2487             :         {
    2488       40540 :             len = hReverb->loopBufLength[bin];
    2489       40540 :             move16();
    2490             : 
    2491       40540 :             IF( ( hReverb->tapPhaseShiftType[bin][chIdx] = (Word16 *) malloc( len * sizeof( Word16 ) ) ) == NULL )
    2492             :             {
    2493           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2494             :             }
    2495       40540 :             set16_fx( hReverb->tapPhaseShiftType[bin][chIdx], 0, len );
    2496             : 
    2497       40540 :             IF( ( hReverb->tapPointersReal_fx[bin][chIdx] = (Word32 **) malloc( len * sizeof( Word32 * ) ) ) == NULL )
    2498             :             {
    2499           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2500             :             }
    2501             : 
    2502       40540 :             IF( ( hReverb->tapPointersImag_fx[bin][chIdx] = (Word32 **) malloc( len * sizeof( Word32 * ) ) ) == NULL )
    2503             :             {
    2504           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2505             :             }
    2506             : 
    2507       40540 :             len = hReverb->blockSize;
    2508       40540 :             move16();
    2509       40540 :             IF( ( hReverb->outputBufferReal_fx[bin][chIdx] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
    2510             :             {
    2511           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2512             :             }
    2513             : 
    2514       40540 :             IF( ( hReverb->outputBufferImag_fx[bin][chIdx] = (Word32 *) malloc( len * sizeof( Word32 ) ) ) == NULL )
    2515             :             {
    2516           0 :                 return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Binaural Reverberator\n" ) );
    2517             :             }
    2518       40540 :             set32_fx( hReverb->outputBufferReal_fx[bin][chIdx], 0, len );
    2519       40540 :             set32_fx( hReverb->outputBufferImag_fx[bin][chIdx], 0, len );
    2520             :         }
    2521             :     }
    2522             : 
    2523         477 :     ivas_binaural_reverb_setReverbTimes_fx( hReverb, sampling_rate, revTimes_fx, revEnes_fx );
    2524             : 
    2525             :     /*free(revTimes_fx);
    2526             :     free(revEnes_fx);*/
    2527             : 
    2528         477 :     ivas_binaural_reverb_setPreDelay_fx( hReverb, preDelay );
    2529             : 
    2530         477 :     return IVAS_ERR_OK;
    2531             : }
    2532             : 
    2533             : /*-------------------------------------------------------------------------
    2534             :  * ivas_binaural_reverb_init()
    2535             :  *
    2536             :  * Allocate and initialize binaural room reverberator handle
    2537             :  * for CLDFB renderers
    2538             :  *------------------------------------------------------------------------*/
    2539         477 : ivas_error ivas_binaural_reverb_init(
    2540             :     REVERB_STRUCT_HANDLE *hReverbPr,                      /* i/o: binaural reverb handle               */
    2541             :     const HRTFS_STATISTICS_HANDLE hHrtfStatistics,        /* i  : HRTF statistics handle               */
    2542             :     const Word16 numBins,                                 /* i  : number of CLDFB bins                 */
    2543             :     const Word16 numCldfbSlotsPerFrame,                   /* i  : number of CLDFB slots per frame      */
    2544             :     const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *roomAcoustics, /* i/o: room acoustics parameters            */
    2545             :     const Word32 sampling_rate,                           /* i  : sampling rate                        */
    2546             :     const Word32 *defaultTimes,                           /* i  : default reverberation times          */
    2547             :     const Word32 *defaultEne                              /* i  : default reverberation energies       */
    2548             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
    2549             :     ,
    2550             :     Word32 *earlyEne /* i/o: Early part energies to be modified      */
    2551             : #endif
    2552             : )
    2553             : {
    2554             :     ivas_error error;
    2555             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
    2556             :     Word16 preDelay, bin;
    2557             :     Word32 revTimes[CLDFB_NO_CHANNELS_MAX];
    2558             :     Word32 revEne[CLDFB_NO_CHANNELS_MAX];
    2559             : #else
    2560             :     const Word32 *revTimes;
    2561             :     const Word32 *revEne;
    2562             :     Word32 t60[CLDFB_NO_CHANNELS_MAX];
    2563             :     Word32 ene[CLDFB_NO_CHANNELS_MAX];
    2564             :     Word16 preDelay;
    2565             : #endif
    2566             :     Word32 temp32;
    2567             : 
    2568         477 :     error = IVAS_ERR_OK;
    2569             : 
    2570             : #ifdef FIX_587_DEFAULT_REVERB
    2571         477 :     IF( roomAcoustics != NULL )
    2572             : #else
    2573             :     if ( ( roomAcoustics != NULL ) && roomAcoustics->override )
    2574             : #endif
    2575             :     {
    2576             : #ifndef FIX_1139_REV_COLORATION_SHORT_T60
    2577             :         revTimes = t60;
    2578             :         revEne = ene;
    2579             : #endif
    2580             : 
    2581             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
    2582         245 :         IF( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, revTimes, revEne ) ) != IVAS_ERR_OK )
    2583             : #else
    2584             :         if ( ( error = ivas_reverb_prepare_cldfb_params( roomAcoustics, hHrtfStatistics, sampling_rate, t60, ene ) ) != IVAS_ERR_OK )
    2585             : #endif
    2586             :         {
    2587           0 :             return error;
    2588             :         }
    2589             : 
    2590         245 :         temp32 = Mult_32_16( roomAcoustics->acousticPreDelay_fx, ( ( IVAS_48k / CLDFB_NO_CHANNELS_MAX ) >> 1 ) ); // Q11
    2591         245 :         preDelay = extract_l( L_shr( L_add( temp32, L_shl( 1, 10 ) ), 11 ) );                                     // Q0
    2592             :     }
    2593             :     ELSE
    2594             :     {
    2595             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
    2596       14152 :         FOR( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
    2597             :         {
    2598       13920 :             revTimes[bin] = defaultTimes[bin];
    2599       13920 :             move32();
    2600       13920 :             revEne[bin] = defaultEne[bin];
    2601       13920 :             move32();
    2602             :         }
    2603             : #else
    2604             :         revTimes = defaultTimes;
    2605             :         revEne = defaultEne;
    2606             : #endif
    2607         232 :         preDelay = 10;
    2608             :     }
    2609             : 
    2610             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
    2611       29097 :     FOR( bin = 0; bin < CLDFB_NO_CHANNELS_MAX; bin++ )
    2612             :     {
    2613             :         /* Adjust the room effect parameters when the reverberation time is less than a threshold value, to avoid
    2614             :            spectral artefacts with the synthetic reverberator. */
    2615       28620 :         IF( LT_32( revTimes[bin], REV_TIME_THRESHOLD ) )
    2616             :         {
    2617             :             Word32 adjustedEarlyEne; /* Q28 to match earlyEne */
    2618             :             Word32 adjustedLateEne;  /* Q31 to match revEne */
    2619             :             Word32 adjustedRevTime;  /* Q26 to match revTime */
    2620             :             Word32 energyModifier;   /* Q30 as range is [0,1] */
    2621             :             Word16 scale;
    2622             : 
    2623             :             /* Adjust reverberation times, higher towards a threshold */
    2624             :             /* Float code equivalent is:
    2625             :              * revTimeModifier = fmaxf( 0.0f, 1.0f - ( revTimes[bin] / REV_TIME_THRESHOLD ) );
    2626             :              * adjustedRevTime = ( 1.0f - revTimeModifier ) * revTimes[bin];
    2627             :              * adjustedRevTime += revTimeModifier * ( revTimes[bin] + REV_TIME_THRESHOLD ) * 0.5f; */
    2628        6410 :             adjustedRevTime = L_shl( revTimes[bin], 5 ); /* Store revTimes[bin] in Q31 for multiplication as it is under REV_TIME_THRESHOLD, i.e., smaller than 1 */
    2629             :             /* Do revTimes[bin]^2 in Q31, result in Q31, multiply with constant in Q29, shift result from Q29 to Q26 for addition and result. */
    2630        6410 :             adjustedRevTime = L_add( L_shr( Mpy_32_32( Mpy_32_32( adjustedRevTime, adjustedRevTime ), Q29_0_5_PER_REV_TIME_THRESHOLD ), 3 ), Q26_REV_TIME_THRESHOLD_TIMES_0_5 );
    2631             : 
    2632        6410 :             energyModifier = L_sub( adjustedRevTime, revTimes[bin] ); /* Q26 */
    2633        6410 :             IF( GT_32( energyModifier, 0 ) )                          /* Very close to threshold, numeric accuracy is not sufficient and energyModifier would be negative. Correct way is to not adjust here. */
    2634             :             {
    2635        6410 :                 energyModifier = BASOP_Util_Divide3232_Scale_newton( energyModifier, adjustedRevTime, &scale ); /* Inputs in Q26 */
    2636        6410 :                 energyModifier = L_shl_sat( energyModifier, sub( scale, 1 ) );                                  /* Store in Q30 as range is [0,1]  */
    2637             : 
    2638             :                 /* Adjust early and late energies, by moving late energy to early energy */
    2639        6410 :                 IF( earlyEne != NULL )
    2640             :                 {
    2641        5379 :                     adjustedEarlyEne = L_shr( Mpy_32_32( revEne[bin], energyModifier ), 2 ); /* Q31 * Q30 mult, shift from Q30 to Q28 */
    2642        5379 :                     adjustedEarlyEne = L_add( adjustedEarlyEne, earlyEne[bin] );             /* Q28 */
    2643             :                 }
    2644             : 
    2645        6410 :                 adjustedLateEne = L_sub( ONE_IN_Q30, energyModifier );                       /* Q30 */
    2646        6410 :                 adjustedLateEne = L_shl_sat( Mpy_32_32( adjustedLateEne, revEne[bin] ), 1 ); /* Q30 * Q31 mult, shift back to Q31 */
    2647             : 
    2648             :                 /* Store adjusted room effect parameters to be used in reverb processing */
    2649        6410 :                 revTimes[bin] = adjustedRevTime;
    2650        6410 :                 move32();
    2651        6410 :                 revEne[bin] = adjustedLateEne;
    2652        6410 :                 move32();
    2653        6410 :                 IF( earlyEne != NULL )
    2654             :                 {
    2655        5379 :                     earlyEne[bin] = adjustedEarlyEne;
    2656        5379 :                     move32();
    2657             :                 }
    2658             :             }
    2659             :         }
    2660             :     }
    2661             : #endif
    2662             : 
    2663         477 :     error = ivas_binaural_reverb_open_fx( hReverbPr, numBins, numCldfbSlotsPerFrame, sampling_rate, revTimes, revEne, preDelay );
    2664             : 
    2665         477 :     return error;
    2666             : }
    2667             : /*-------------------------------------------------------------------------
    2668             :  * ivas_binaural_reverb_close_fx()
    2669             :  *
    2670             :  * Close binaural room reverberator handle
    2671             :  *------------------------------------------------------------------------*/
    2672             : 
    2673         477 : void ivas_binaural_reverb_close_fx(
    2674             :     REVERB_STRUCT_HANDLE *hReverb /* i/o: binaural reverb handle */
    2675             : )
    2676             : {
    2677             :     Word16 bin, chIdx;
    2678             : 
    2679         477 :     test();
    2680         477 :     IF( hReverb == NULL || *hReverb == NULL )
    2681             :     {
    2682           0 :         return;
    2683             :     }
    2684             : 
    2685       20747 :     FOR( bin = 0; bin < ( *hReverb )->numBins; bin++ )
    2686             :     {
    2687       60810 :         FOR( chIdx = 0; chIdx < BINAURAL_CHANNELS; chIdx++ )
    2688             :         {
    2689       40540 :             free( ( *hReverb )->tapPhaseShiftType[bin][chIdx] );
    2690       40540 :             free( ( *hReverb )->tapPointersReal_fx[bin][chIdx] );
    2691       40540 :             free( ( *hReverb )->tapPointersImag_fx[bin][chIdx] );
    2692       40540 :             free( ( *hReverb )->outputBufferReal_fx[bin][chIdx] );
    2693       40540 :             free( ( *hReverb )->outputBufferImag_fx[bin][chIdx] );
    2694             :         }
    2695       20270 :         free( ( *hReverb )->loopBufReal_fx[bin] );
    2696       20270 :         free( ( *hReverb )->loopBufImag_fx[bin] );
    2697             :     }
    2698             : 
    2699         477 :     free( ( *hReverb ) );
    2700         477 :     ( *hReverb ) = NULL;
    2701             : 
    2702         477 :     return;
    2703             : }

Generated by: LCOV version 1.14