LCOV - code coverage report
Current view: top level - lib_rend - ivas_objectRenderer_hrFilt_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main @ cede165d26d1b794bfc5f5f6f9ec19d4d64a9a3b Lines: 381 398 95.7 %
Date: 2025-11-01 03:16:20 Functions: 10 10 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 <assert.h>
      35             : #include "options.h"
      36             : #include "prot_fx.h"
      37             : #include <math.h>
      38             : #include "ivas_prot_rend_fx.h"
      39             : #include "ivas_rom_rend.h"
      40             : #include "ivas_cnst.h"
      41             : #include "wmc_auto.h"
      42             : 
      43             : /*---------------------------------------------------------------------*
      44             :  * Local function prototypes
      45             :  *---------------------------------------------------------------------*/
      46             : 
      47             : static void getPeriodicBSplineSampVec_fx( Word32 *BfVec_fx, Word16 *AzIdx, const Word16 NumBFs, const Word32 t_fx, Word16 *num_az_idx, const Word32 knot_interval_fx, const Word32 azimKSeq_0_fx, const Word16 azimSegSamples, const Word32 *azimBsShape_fx, const Word16 subSampFactor );
      48             : static void getStandardBSplineSampVec_fx( Word32 *BfVec_fx, Word16 *NzIdx, Word16 *num_idx, const Word16 NumBFs, const Word32 t_fx, const Word32 *KSeq_fx, const Word16 SegSamples, const Word16 *BsLen, const Word16 *BsStart, const Word32 *BsShape_fx );
      49             : static void GenerateFilter_fx( const Word32 elev, Word32 azim, ModelParams_t *model, ModelEval_t *modelEval );
      50             : static void GenerateITD_fx( const Word32 elev, Word32 azim, ModelParamsITD_t *model, ModelEval_t *modelEval );
      51             : static void SkipSmallest_ValueIndex_fx( Word16 *use_inds, const ValueIndex_t *VI, const Word16 N, const Word16 n_smallest );
      52             : 
      53             : 
      54             : /*-------------------------------------------------------------------*
      55             :  * TDREND_REND_RenderSourceHRFilt()
      56             :  *
      57             :  * Renders each object using the HR filters
      58             :  --------------------------------------------------------------------*/
      59             : 
      60     1431193 : ivas_error TDREND_REND_RenderSourceHRFilt_fx(
      61             :     TDREND_SRC_t *Src_p,                         /* i/o: The source to be rendered                          */
      62             :     Word32 *hrf_left_delta_fx,                   /* i/o: Left filter interpolation delta                    */
      63             :     Word16 *hrf_left_delta_e,                    /* i/o: Left filter interpolation delta exp                */
      64             :     Word32 *hrf_right_delta_fx,                  /* i/o: Right filter interpolation delta                   */
      65             :     Word16 *hrf_right_delta_e,                   /* i/o: Right filter interpolation delta exp               */
      66             :     const Word16 intp_count,                     /* i  : Interpolation count                                */
      67             :     Word32 output_buf_fx[][L_SPATIAL_SUBFR_48k], /* o  : Output buffer same Q as Src_p->InputFrame_p_fx Q11 */
      68             :     const Word16 subframe_length                 /* i  : Subframe length in use                             */
      69             : )
      70             : {
      71             :     Word32 LeftOutputFrame_fx[L_SPATIAL_SUBFR_48k];  // will have same Q as Src_p->InputFrame_p_fx
      72             :     Word32 RightOutputFrame_fx[L_SPATIAL_SUBFR_48k]; // will have same Q as Src_p->InputFrame_p_fx
      73             :     Word16 left_filter_e;
      74             :     Word16 right_filter_e;
      75             : 
      76     1431193 :     TDREND_Apply_ITD_fx( Src_p->InputFrame_p_fx, LeftOutputFrame_fx, RightOutputFrame_fx,
      77     1431193 :                          &Src_p->previtd, Src_p->itd, Src_p->mem_itd_fx, subframe_length );
      78             : 
      79     1431193 :     left_filter_e = s_max( Src_p->hrf_left_prev_e, *hrf_left_delta_e );
      80     1431193 :     right_filter_e = s_max( Src_p->hrf_right_prev_e, *hrf_right_delta_e );
      81             : 
      82             :     /* Scaling prev and delta HRF filter values to common Q-factor */
      83     1431193 :     Scale_sig32( Src_p->hrf_left_prev_fx, Src_p->filterlength, sub( Src_p->hrf_left_prev_e, left_filter_e ) );
      84     1431193 :     Scale_sig32( hrf_left_delta_fx, Src_p->filterlength, sub( *hrf_left_delta_e, left_filter_e ) );
      85     1431193 :     Scale_sig32( Src_p->hrf_right_prev_fx, Src_p->filterlength, sub( Src_p->hrf_right_prev_e, right_filter_e ) );
      86     1431193 :     Scale_sig32( hrf_right_delta_fx, Src_p->filterlength, sub( *hrf_right_delta_e, left_filter_e ) );
      87     1431193 :     Src_p->hrf_left_prev_e = left_filter_e;
      88     1431193 :     move16();
      89     1431193 :     *hrf_left_delta_e = left_filter_e;
      90     1431193 :     move16();
      91     1431193 :     Src_p->hrf_right_prev_e = right_filter_e;
      92     1431193 :     move16();
      93     1431193 :     *hrf_right_delta_e = right_filter_e;
      94     1431193 :     move16();
      95             : 
      96     1431193 :     TDREND_firfilt_fx( LeftOutputFrame_fx, Src_p->hrf_left_prev_fx, left_filter_e, hrf_left_delta_fx, intp_count, Src_p->mem_hrf_left_fx, subframe_length, Src_p->filterlength, Src_p->Gain_fx, Src_p->prevGain_fx );
      97     1431193 :     TDREND_firfilt_fx( RightOutputFrame_fx, Src_p->hrf_right_prev_fx, right_filter_e, hrf_right_delta_fx, intp_count, Src_p->mem_hrf_right_fx, subframe_length, Src_p->filterlength, Src_p->Gain_fx, Src_p->prevGain_fx );
      98             : 
      99     1431193 :     Src_p->prevGain_fx = Src_p->Gain_fx;
     100     1431193 :     move32();
     101             : 
     102             :     /* Copy to accumulative output frame */
     103     1431193 :     v_add_32( LeftOutputFrame_fx, output_buf_fx[0], output_buf_fx[0], subframe_length );  // Same Q as Src_p->InputFrame_p_fx Q11
     104     1431193 :     v_add_32( RightOutputFrame_fx, output_buf_fx[1], output_buf_fx[1], subframe_length ); // Same Q as Src_p->InputFrame_p_fx Q11
     105             : 
     106     1431193 :     return IVAS_ERR_OK;
     107             : }
     108             : 
     109             : 
     110             : /*-------------------------------------------------------------------*
     111             :  * GetFilterFromAngle()
     112             :  *
     113             :  * Obtain an HR filter corresponding to the input angle pair.
     114             :  * This version uses the HR filter model.
     115             :  --------------------------------------------------------------------*/
     116             : 
     117      928342 : void GetFilterFromAngle_fx(
     118             :     TDREND_HRFILT_FiltSet_t *HrFiltSet_p, /* i/o: HR filter set structure      */
     119             :     const Word32 Elev_fx,                 /* i  : Elevation, degrees       Q22 */
     120             :     Word32 Azim_fx,                       /* i  : Azimuth, degrees         Q22 */
     121             :     const Word16 filterlength,            /* i  : Filter length                */
     122             :     Word32 *hrf_left_fx,                  /* o  : Left HR filter               */
     123             :     Word16 *hrf_left_e,                   /* o  : Left HR filter exponent      */
     124             :     Word32 *hrf_right_fx,                 /* o  : Right HR filter              */
     125             :     Word16 *hrf_right_e,                  /* o  : Right HR filter exponent     */
     126             :     Word16 *itd                           /* o  : ITD value                 Q0 */
     127             : )
     128             : {
     129      928342 :     GenerateFilter_fx( Elev_fx, Azim_fx, &HrFiltSet_p->ModelParams, &HrFiltSet_p->ModelEval );
     130             : 
     131      928342 :     Copy32( HrFiltSet_p->ModelEval.hrfModL_fx, hrf_left_fx, filterlength );
     132      928342 :     *hrf_left_e = HrFiltSet_p->ModelEval.hrfModL_e;
     133      928342 :     move16();
     134      928342 :     Copy32( HrFiltSet_p->ModelEval.hrfModR_fx, hrf_right_fx, filterlength );
     135      928342 :     *hrf_right_e = HrFiltSet_p->ModelEval.hrfModR_e;
     136      928342 :     move16();
     137             : 
     138             :     /* 4. Evaluate the ITD */
     139      928342 :     IF( HrFiltSet_p->ModelParams.UseItdModel )
     140             :     {
     141      928342 :         GenerateITD_fx( Elev_fx, Azim_fx, &HrFiltSet_p->ModelParamsITD, &HrFiltSet_p->ModelEval );
     142      928342 :         *itd = extract_l( HrFiltSet_p->ModelEval.itdMod_fx ); // Q0
     143      928342 :         move16();
     144             :     }
     145             :     ELSE
     146             :     {
     147           0 :         *itd = 0;
     148           0 :         move16();
     149             :     }
     150             : 
     151      928342 :     return;
     152             : }
     153             : 
     154             : 
     155             : /* o  : Output value   Q0 */
     156     6937995 : static Word32 round_hrFilt_fx(
     157             :     Word32 num, /* i  : Input value       */
     158             :     Word16 q    /* i  : Input q-factor    */
     159             : )
     160             : {
     161             :     Word32 half;
     162     6937995 :     if ( q == 0 )
     163             :     {
     164         292 :         return num;
     165             :     }
     166     6937703 :     half = L_shl( 1, sub( q, 1 ) );
     167             : 
     168     6937703 :     half = L_shr( half, 1 ); // one guard bit
     169     6937703 :     num = L_shr( num, 1 );   // one guard bit
     170             : 
     171     6937703 :     q = sub( q, 1 );
     172             : 
     173     6937703 :     IF( num >= 0 )
     174             :     {
     175     6476907 :         num = L_add( num, half );
     176             :     }
     177             :     ELSE
     178             :     {
     179      460796 :         num = L_sub( num, half );
     180             :     }
     181   156691739 :     WHILE( q != 0 )
     182             :     {
     183   149754036 :         num = ( num / 2 ); // using "/ 2" here because it rounds towards 0, whereas L_shr rounds towards -inf.
     184   149754036 :         q = sub( q, 1 );
     185             :     }
     186     6937703 :     return num;
     187             : }
     188             : 
     189             : /*-------------------------------------------------------------------*
     190             :  * GenerateFilter()
     191             :  *
     192             :  * Generate an HR filter using the B Spline model.
     193             :  --------------------------------------------------------------------*/
     194             : 
     195      928342 : static void GenerateFilter_fx(
     196             :     const Word32 elev,     /* i  : Elevation angle, degrees   Q22 */
     197             :     Word32 azim,           /* i  : Azimuth angle, degrees     Q22 */
     198             :     ModelParams_t *model,  /* i  : Model parameters structure     */
     199             :     ModelEval_t *modelEval /* i/o: Model evaluation structure     */
     200             : )
     201             : {
     202             :     Word16 qp, p, k, i;
     203             :     Word16 AzIdx[HRTF_MODEL_BSPLINE_NUM_COEFFS][HRTF_MODEL_BSPLINE_NUM_COEFFS], EvIdx[HRTF_MODEL_BSPLINE_NUM_COEFFS]; /* non-zero basis functions */
     204             :     Word16 num_az_idx[HRTF_MODEL_BSPLINE_NUM_COEFFS];
     205             :     Word16 num_ev_idx;
     206             :     Word16 BM_idx[HRTF_MODEL_BSPLINE_NUM_COEFFS_SQ];
     207             :     Word32 knot_interval;
     208             :     Word32 ETotL, ETotR, ESynL, ESynR;
     209             :     Word16 ETotL_e, ETotR_e, ESynL_e, ESynR_e;
     210             :     Word32 ScaleL, ScaleR;
     211             :     Word16 ScaleL_e, ScaleR_e;
     212             :     Word16 iSec;
     213             :     Word16 tmp_e;
     214             :     Word32 tmp32;
     215             :     Word16 BMEnergiesR_e, BMEnergiesL_e;
     216             :     Word16 tmp_hrfModR_e, tmp_hrfModL_e;
     217             : 
     218      928342 :     getStandardBSplineSampVec_fx( modelEval->elevBfVec_fx, EvIdx, &num_ev_idx, model->elevDim3, elev, model->elevKSeq_fx,
     219      928342 :                                   model->elevSegSamples, model->elevBsLen, model->elevBsStart, model->elevBsShape_fx );
     220             : 
     221     4163487 :     FOR( p = 0; p < num_ev_idx; p++ )
     222             :     {
     223             :         /* Wrap the requested azimuth to the range of the BSplines */
     224     3235145 :         azim = L_add( azim, model->azimKSeq_fx[p][0] );
     225     3235145 :         WHILE( GT_32( azim, DEG_360_IN_Q22 ) )
     226             :         {
     227           0 :             azim = L_sub( azim, DEG_360_IN_Q22 ); // Q22
     228             :         }
     229     3235145 :         IF( azim < 0 )
     230             :         {
     231      458157 :             azim = L_add( azim, DEG_360_IN_Q22 ); // Q22
     232             :         }
     233     3235145 :         azim = L_sub( azim, model->azimKSeq_fx[p][0] ); // Q22
     234             : 
     235     3235145 :         IF( EQ_16( model->azimDim3[EvIdx[p]], 1 ) ) /* Constant basis function */
     236             :         {
     237       10518 :             num_az_idx[p] = 1;
     238       10518 :             move16();
     239       10518 :             AzIdx[p][0] = 0;
     240       10518 :             move16();
     241       10518 :             modelEval->azimBfVec_fx[p][0] = ONE_IN_Q30;
     242       10518 :             move32();
     243             :         }
     244             :         ELSE
     245             :         {
     246     3224627 :             k = EvIdx[p];
     247     3224627 :             move16();
     248             : 
     249     3224627 :             knot_interval = L_deposit_h( BASOP_Util_Divide3216_Scale( L_sub( model->azimKSeq_fx[k][model->azimDim3[k]], model->azimKSeq_fx[k][0] ), model->azimDim3[k], &tmp_e ) );
     250     3224627 :             tmp_e = add( tmp_e, 9 - 15 );
     251     3224627 :             knot_interval = L_shr( knot_interval, sub( 9, tmp_e ) ); // variable Q to Q22
     252             : 
     253     3224627 :             getPeriodicBSplineSampVec_fx( modelEval->azimBfVec_fx[p], AzIdx[p], model->azimDim3[k], azim, &num_az_idx[p],
     254     3224627 :                                           knot_interval, model->azimKSeq_fx[k][0], model->azimSegSamples[model->azimShapeIdx[k]],
     255     3224627 :                                           model->azimBsShape_fx[model->azimShapeIdx[k]], model->azimShapeSampFactor[k] );
     256             :         }
     257             :     }
     258             : 
     259             :     /* Compute BM */
     260      928342 :     qp = 0;
     261      928342 :     move16();
     262     4163487 :     FOR( p = 0; p < num_ev_idx; p++ )
     263             :     {
     264     3235145 :         Word32 expt = L_shl_sat( modelEval->elevBfVec_fx[p], 1 );
     265    15707556 :         FOR( i = 0; i < num_az_idx[p]; i++ )
     266             :         {
     267    12472411 :             modelEval->BM_fx[qp + i] = Mpy_32_32( expt, modelEval->azimBfVec_fx[p][i] ); /*Q30 - ( Q30 * 2 - 31 )*/ // Q30
     268    12472411 :             move32();
     269    12472411 :             BM_idx[qp + i] = add( model->azim_start_idx[EvIdx[p]], AzIdx[p][i] );
     270    12472411 :             move16();
     271             :         }
     272     3235145 :         qp = add( qp, num_az_idx[p] );
     273             :     }
     274             : 
     275      928342 :     Word16 expL = add( model->AlphaL_e, 1 );
     276      928342 :     Word16 expR = add( model->AlphaR_e, 1 );
     277      928342 :     BMEnergiesL_e = add( model->EL_e, 2 );
     278      928342 :     BMEnergiesR_e = add( model->ER_e, 2 );
     279             : 
     280             :     /* Compute HR filters, approximate optimized model evaluation */
     281     3713368 :     FOR( iSec = 0; iSec < HRTF_MODEL_N_SECTIONS; iSec++ )
     282             :     {
     283     2785026 :         Word64 temp1 = 0;
     284     2785026 :         move64();
     285     2785026 :         Word64 temp2 = 0;
     286     2785026 :         move64();
     287             :         /* Energy is precalculated part updated with square of BM value. Store index for sorting */
     288    40202259 :         FOR( i = 0; i < qp; i++ )
     289             :         {
     290    37417233 :             modelEval->BMEnergiesL[i].val_fx = Mpy_32_32( Mpy_32_32( modelEval->BM_fx[i], modelEval->BM_fx[i] ) /*Q29*/, model->EL_fx[( iSec * model->AlphaN ) + BM_idx[i]] ); // exp: model->EL_e + 2
     291    37417233 :             modelEval->BMEnergiesR[i].val_fx = Mpy_32_32( Mpy_32_32( modelEval->BM_fx[i], modelEval->BM_fx[i] ) /*Q29*/, model->ER_fx[( iSec * model->AlphaN ) + BM_idx[i]] ); // exp: model->ER_e + 2
     292    37417233 :             move32();
     293    37417233 :             move32();
     294    37417233 :             modelEval->BMEnergiesL[i].i = i;
     295    37417233 :             move16();
     296    37417233 :             modelEval->BMEnergiesR[i].i = i;
     297    37417233 :             move16();
     298    37417233 :             temp1 = W_add( temp1, modelEval->BMEnergiesL[i].val_fx ); // BMEnergiesL_e
     299    37417233 :             temp2 = W_add( temp2, modelEval->BMEnergiesR[i].val_fx ); // BMEnergiesR_e
     300             :         }
     301     2785026 :         ETotL_e = W_norm( temp1 );
     302     2785026 :         ETotL_e = sub( ETotL_e, 32 );
     303     2785026 :         ETotL = W_shl_sat_l( temp1, ETotL_e );
     304     2785026 :         ETotL_e = sub( BMEnergiesL_e, ETotL_e );
     305             : 
     306     2785026 :         ETotR_e = W_norm( temp2 );
     307     2785026 :         ETotR_e = sub( ETotR_e, 32 );
     308     2785026 :         ETotR = W_shl_sat_l( temp2, ETotR_e );
     309     2785026 :         ETotR_e = sub( BMEnergiesR_e, ETotR_e );
     310             : 
     311             :         /* Number of basis components actually used. */
     312     2785026 :         p = s_min( HRTF_MODEL_N_CPTS_VAR[iSec], qp );
     313     2785026 :         SkipSmallest_ValueIndex_fx( modelEval->UseIndsL, modelEval->BMEnergiesL, qp, sub( qp, p ) );
     314     2785026 :         SkipSmallest_ValueIndex_fx( modelEval->UseIndsR, modelEval->BMEnergiesR, qp, sub( qp, p ) );
     315             : 
     316     2785026 :         temp1 = 0;
     317     2785026 :         move64();
     318     2785026 :         temp2 = 0;
     319     2785026 :         move64();
     320             : 
     321             :         /* Account for lost energy */
     322    35173643 :         FOR( i = 0; i < p; i++ )
     323             :         {
     324    32388617 :             temp1 = W_add( temp1, modelEval->BMEnergiesL[modelEval->UseIndsL[i]].val_fx ); // BMEnergiesL_e
     325    32388617 :             temp2 = W_add( temp2, modelEval->BMEnergiesR[modelEval->UseIndsR[i]].val_fx ); // BMEnergiesR_e
     326             :         }
     327     2785026 :         ESynL_e = W_norm( temp1 );
     328     2785026 :         ESynL_e = sub( ESynL_e, 32 );
     329     2785026 :         ESynL = W_shl_sat_l( temp1, ESynL_e );
     330     2785026 :         ESynL_e = sub( BMEnergiesL_e, ESynL_e );
     331     2785026 :         ESynL = BASOP_Util_Add_Mant32Exp( ESynL, ESynL_e, EPSILON_FX_M, EPSILON_FX_E, &ESynL_e );
     332             : 
     333     2785026 :         ESynR_e = W_norm( temp2 );
     334     2785026 :         ESynR_e = sub( ESynR_e, 32 );
     335     2785026 :         ESynR = W_shl_sat_l( temp2, ESynR_e );
     336     2785026 :         ESynR_e = sub( BMEnergiesR_e, ESynR_e );
     337     2785026 :         ESynR = BASOP_Util_Add_Mant32Exp( ESynR, ESynR_e, EPSILON_FX_M, EPSILON_FX_E, &ESynR_e );
     338             : 
     339             : 
     340     2785026 :         tmp32 = L_deposit_h( BASOP_Util_Divide3232_Scale( ETotL, ESynL, &ScaleL_e ) );
     341     2785026 :         ScaleL_e = add( ScaleL_e, sub( ETotL_e, ESynL_e ) );
     342     2785026 :         ScaleL = Sqrt32( tmp32, &ScaleL_e );
     343     2785026 :         ScaleL_e = sub( ScaleL_e, 1 );
     344             : 
     345     2785026 :         tmp32 = L_deposit_h( BASOP_Util_Divide3232_Scale( ETotR, ESynR, &ScaleR_e ) );
     346     2785026 :         ScaleR_e = add( ScaleR_e, sub( ETotR_e, ESynR_e ) );
     347     2785026 :         ScaleR = Sqrt32( tmp32, &ScaleR_e );
     348     2785026 :         ScaleR_e = sub( ScaleR_e, 1 );
     349             : 
     350             :         /* Build using only the most energetic components. */
     351   119328644 :         FOR( k = model->iSecFirst[iSec]; k <= model->iSecLast[iSec]; k++ )
     352             :         {
     353   116543618 :             temp1 = 0;
     354   116543618 :             move64();
     355   116543618 :             temp2 = 0;
     356   116543618 :             move64();
     357             : 
     358  1470377203 :             FOR( i = 0; i < p; i++ )
     359             :             {
     360  1353833585 :                 temp1 = W_add( temp1, Mpy_32_32( modelEval->BM_fx[modelEval->BMEnergiesL[modelEval->UseIndsL[i]].i], model->AlphaL_fx[BM_idx[modelEval->BMEnergiesL[modelEval->UseIndsL[i]].i] + ( model->AlphaN * k )] ) ); // add(model->AlphaL_e, 1)
     361  1353833585 :                 temp2 = W_add( temp2, Mpy_32_32( modelEval->BM_fx[modelEval->BMEnergiesR[modelEval->UseIndsR[i]].i], model->AlphaR_fx[BM_idx[modelEval->BMEnergiesR[modelEval->UseIndsR[i]].i] + ( model->AlphaN * k )] ) ); // add(model->AlphaR_e, 1)
     362             :             }
     363             : 
     364   116543618 :             tmp_hrfModL_e = W_norm( temp1 );
     365   116543618 :             tmp_hrfModL_e = sub( tmp_hrfModL_e, 32 );
     366   116543618 :             modelEval->hrfModL_fx[k] = W_shl_sat_l( temp1, tmp_hrfModL_e );
     367   116543618 :             move32();
     368   116543618 :             tmp_hrfModL_e = sub( expL, tmp_hrfModL_e );
     369   116543618 :             if ( temp1 == 0 )
     370             :             {
     371     1643439 :                 tmp_hrfModL_e = 0;
     372     1643439 :                 move16();
     373             :             }
     374             : 
     375   116543618 :             tmp_hrfModR_e = W_norm( temp2 );
     376   116543618 :             tmp_hrfModR_e = sub( tmp_hrfModR_e, 32 );
     377   116543618 :             modelEval->hrfModR_fx[k] = W_shl_sat_l( temp2, tmp_hrfModR_e );
     378   116543618 :             move32();
     379   116543618 :             tmp_hrfModR_e = sub( expR, tmp_hrfModR_e );
     380             : 
     381   116543618 :             if ( temp2 == 0 )
     382             :             {
     383     1652009 :                 tmp_hrfModR_e = 0;
     384     1652009 :                 move16();
     385             :             }
     386             : 
     387             :             /* Account for lost energy */
     388   116543618 :             modelEval->hrfModL_fx[k] = Mpy_32_32( modelEval->hrfModL_fx[k], ScaleL );
     389   116543618 :             move32();
     390   116543618 :             modelEval->hrfModR_fx[k] = Mpy_32_32( modelEval->hrfModR_fx[k], ScaleR );
     391   116543618 :             move32();
     392             : 
     393             :             /* NOTE: Assuming that finally, hrfMod values will be <= 1. Hence making it Q30 */
     394   116543618 :             modelEval->hrfModL_fx[k] = L_shl( modelEval->hrfModL_fx[k], add( tmp_hrfModL_e, ScaleL_e ) ); // assuming Q30
     395   116543618 :             modelEval->hrfModR_fx[k] = L_shl( modelEval->hrfModR_fx[k], add( tmp_hrfModR_e, ScaleR_e ) ); // assuming Q30
     396   116543618 :             move32();
     397   116543618 :             move32();
     398             :         }
     399             :     }
     400             : 
     401      928342 :     modelEval->hrfModL_e = 1; /*Q30*/
     402      928342 :     move16();
     403      928342 :     modelEval->hrfModR_e = 1; /*Q30*/
     404      928342 :     move16();
     405             : 
     406      928342 :     return;
     407             : }
     408             : 
     409             : 
     410             : /*-------------------------------------------------------------------*
     411             :  * GenerateITD()
     412             :  *
     413             :  * Generates an ITD value from the B Spline model.
     414             :  --------------------------------------------------------------------*/
     415             : 
     416      928342 : static void GenerateITD_fx(
     417             :     const Word32 elev_fx,    /* i  : Elevation angle, degrees       Q22 */
     418             :     Word32 azim_fx,          /* i  : Azimuth angle, degrees         Q22 */
     419             :     ModelParamsITD_t *model, /* i  : ITD Model parameters structure     */
     420             :     ModelEval_t *modelEval   /* i/o: Model evaluation structure         */
     421             : )
     422             : {
     423             :     Word16 qp, p, i;
     424             :     Word32 index;
     425             :     Word16 AlphaN;
     426             :     Word16 elev_offset;
     427             :     Word32 azim_itd_fx;
     428             :     Word16 AzIdx[HRTF_MODEL_BSPLINE_NUM_COEFFS], EvIdx[HRTF_MODEL_BSPLINE_NUM_COEFFS]; /* non-zero basis functions */
     429             :     Word16 num_az_idx, num_ev_idx;
     430             :     Word16 BM_idx[HRTF_MODEL_BSPLINE_NUM_COEFFS_SQ];
     431             :     Word16 itdMod_e;
     432      928342 :     set16_fx( AzIdx, 0, HRTF_MODEL_BSPLINE_NUM_COEFFS );
     433             : 
     434             :     /* Wrap the requested azimuth to the range of the BSplines */
     435      928342 :     azim_fx = L_add( azim_fx, model->azimKSeq_fx[0] );
     436      928342 :     WHILE( GT_32( azim_fx, DEG_360_IN_Q22 ) )
     437             :     {
     438           0 :         azim_fx = L_sub( azim_fx, DEG_360_IN_Q22 ); // Q22
     439             :     }
     440      928342 :     if ( azim_fx < 0 )
     441             :     {
     442      458157 :         azim_fx = L_add( azim_fx, DEG_360_IN_Q22 ); // Q22
     443             :     }
     444      928342 :     azim_fx = L_sub( azim_fx, model->azimKSeq_fx[0] ); // Q22
     445             : 
     446      928342 :     IF( NE_32( L_abs( elev_fx ), DEG_90_IN_Q22 ) )
     447             :     {
     448      928342 :         getStandardBSplineSampVec_fx( modelEval->elevBfVecITD_fx, EvIdx, &num_ev_idx, model->elevDim3, elev_fx, model->elevKSeq_fx,
     449      928342 :                                       model->elevSegSamples, model->elevBsLen, model->elevBsStart, model->elevBsShape_fx );
     450             : 
     451      928342 :         azim_itd_fx = azim_fx;
     452      928342 :         move32();
     453      928342 :         if ( GT_32( azim_fx, DEG_180_IN_Q22 ) )
     454             :         {
     455             :             /* Flip spline functions around 180 deg */
     456      457845 :             azim_itd_fx = L_sub( DEG_360_IN_Q22, azim_fx ); // Q22
     457             :         }
     458      928342 :         getStandardBSplineSampVec_fx( modelEval->azimBfVecITD_fx, AzIdx, &num_az_idx, shr( add( model->azimDim3, 1 ), 1 ), azim_itd_fx, model->azimKSeq_fx,
     459      928342 :                                       model->azimSegSamples, model->azimBsLen, model->azimBsStart, model->azimBsShape_fx );
     460      928342 :         IF( GT_32( azim_fx, DEG_180_IN_Q22 ) )
     461             :         {
     462             :             /* Flip spline functions around 180 deg */
     463     2289225 :             FOR( i = 0; i < HRTF_MODEL_BSPLINE_NUM_COEFFS; i++ )
     464             :             {
     465     1831380 :                 AzIdx[i] = sub( sub( model->azimDim3, 1 ), AzIdx[i] );
     466     1831380 :                 move16();
     467             :             }
     468             :         }
     469             :     }
     470             :     ELSE
     471             :     {
     472           0 :         num_az_idx = 1;
     473           0 :         move16();
     474           0 :         num_ev_idx = 1;
     475           0 :         move16();
     476             : 
     477           0 :         modelEval->elevBfVecITD_fx[0] = ONE_IN_Q30;
     478           0 :         move32();
     479             : 
     480           0 :         IF( LT_32( elev_fx, 0 ) )
     481             :         {
     482           0 :             EvIdx[0] = 0;
     483           0 :             move16();
     484             :         }
     485             :         ELSE
     486             :         {
     487           0 :             EvIdx[0] = sub( model->elevDim3, 1 );
     488           0 :             move16();
     489             :         }
     490             :     }
     491             : 
     492             :     /* Compute BM_ITD */
     493      928342 :     elev_offset = 0;
     494      928342 :     move16();
     495      928342 :     if ( EQ_32( model->elevKSeq_fx[0], -DEG_90_IN_Q22 ) )
     496             :     {
     497      928342 :         elev_offset = sub( 1, model->azimDim3 );
     498             :     }
     499      928342 :     qp = 0;
     500      928342 :     move16();
     501     4329970 :     FOR( p = 0; p < num_ev_idx; p++ )
     502             :     {
     503     3401628 :         test();
     504     3401628 :         test();
     505     3401628 :         test();
     506     3401628 :         test();
     507     3401628 :         IF( EvIdx[p] == 0 && EQ_32( model->elevKSeq_fx[EvIdx[p]], -DEG_90_IN_Q22 ) )
     508             :         {
     509        3946 :             modelEval->BM_ITD_fx[qp] = modelEval->elevBfVecITD_fx[p]; // Q30
     510        3946 :             move32();
     511        3946 :             BM_idx[qp] = imult1616( EvIdx[p], model->azimDim3 );
     512        3946 :             move16();
     513        3946 :             qp = add( qp, 1 );
     514             :         }
     515     3397682 :         ELSE IF( EQ_16( EvIdx[p], sub( model->elevDim3, 1 ) ) && EQ_32( model->elevKSeq_fx[sub( EvIdx[p], 2 )], DEG_90_IN_Q22 ) )
     516             :         {
     517             :             /* NB: -2 in if() condition above as number of knot points is numBF-2 */
     518        3987 :             modelEval->BM_ITD_fx[qp] = modelEval->elevBfVecITD_fx[p]; // Q30
     519        3987 :             move32();
     520        3987 :             BM_idx[qp] = add( imult1616( EvIdx[p], model->azimDim3 ), elev_offset );
     521        3987 :             move16();
     522        3987 :             qp = add( qp, 1 );
     523             :         }
     524             :         ELSE
     525             :         {
     526     3393695 :             Word16 temp_e = add( imult1616( EvIdx[p], model->azimDim3 ), elev_offset );
     527    16513326 :             FOR( i = 0; i < num_az_idx; i++ )
     528             :             {
     529    13119631 :                 modelEval->BM_ITD_fx[qp + i] = L_shl( Mpy_32_32( modelEval->elevBfVecITD_fx[p], modelEval->azimBfVecITD_fx[i] ), 1 ); // Q30
     530    13119631 :                 move32();
     531    13119631 :                 BM_idx[qp + i] = add( temp_e, AzIdx[i] );
     532    13119631 :                 move16();
     533             :             }
     534     3393695 :             qp = add( qp, num_az_idx );
     535             :         }
     536             :     }
     537             : 
     538             :     /* Compute ITD */
     539      928342 :     AlphaN = add( imult1616( model->elevDim3, model->azimDim3 ), elev_offset );
     540      928342 :     if ( EQ_32( model->elevKSeq_fx[sub( model->elevDim3, 3 )], DEG_90_IN_Q22 ) ) /* Constant azimuth basis function */
     541             :     {
     542      928342 :         AlphaN = sub( AlphaN, sub( model->azimDim3, 1 ) );
     543             :     }
     544             : 
     545             :     /* Matrix multiplcation (row x column) */
     546      928342 :     Word64 temp = 0;
     547      928342 :     move64();
     548      928342 :     Word16 res_e = add( model->W_e, 1 );
     549    14055906 :     FOR( i = 0; i < qp; i++ )
     550             :     {
     551    13127564 :         index = BM_idx[i];
     552    13127564 :         move32();
     553    13127564 :         temp = W_add( temp, Mpy_32_32( modelEval->BM_ITD_fx[i], model->W_fx[index] ) );
     554             :     }
     555      928342 :     itdMod_e = W_norm( temp );
     556      928342 :     itdMod_e = sub( itdMod_e, 32 );
     557      928342 :     modelEval->itdMod_fx = W_shl_sat_l( temp, itdMod_e );
     558      928342 :     itdMod_e = sub( res_e, itdMod_e );
     559             : 
     560      928342 :     Word32 tmp32 = Mpy_32_16_1( modelEval->itdMod_fx, model->resamp_factor_fx ); // Q = 31 - ( itdMod_e + 1 )
     561      928342 :     Word16 tmp_q = sub( 30, itdMod_e );
     562             : 
     563      928342 :     IF( tmp_q < 0 )
     564             :     {
     565         292 :         tmp32 = L_shr( tmp32, tmp_q );
     566         292 :         tmp_q = 0;
     567         292 :         move16();
     568             :     }
     569      928050 :     ELSE IF( GE_32( tmp_q, 32 ) )
     570             :     {
     571       35893 :         tmp32 = L_shr( tmp32, sub( tmp_q, 31 ) );
     572       35893 :         tmp_q = 31;
     573       35893 :         move16();
     574             :     }
     575      928342 :     modelEval->itdMod_fx = L_negate( round_hrFilt_fx( tmp32, tmp_q ) ); // Q0
     576             : 
     577      928342 :     return;
     578             : }
     579             : 
     580             : 
     581             : /*-------------------------------------------------------------------*
     582             :  * getStandardBSplineSampVec()
     583             :  *
     584             :  * Obtain a periodic sampled B Spline basis vector.
     585             :  --------------------------------------------------------------------*/
     586             : 
     587     3224627 : static void getPeriodicBSplineSampVec_fx(
     588             :     Word32 *BfVec_fx,              /* o  : values for non-zero basis functions               Q30 */
     589             :     Word16 *AzIdx,                 /* o  : indices of non-zero basis functions                   */
     590             :     const Word16 NumBFs,           /* i  : the number of basis functions = third index of Bf.    */
     591             :     const Word32 t_fx,             /* i  : azimuth                                           Q22 */
     592             :     Word16 *num_az_idx,            /* o  : Number of azimuth indices                             */
     593             :     const Word32 knot_interval_fx, /* i  : The knot interval                                 Q22 */
     594             :     const Word32 azimKSeq_0_fx,    /* i  : Knot sequence                                     Q22 */
     595             :     const Word16 azimSegSamples,   /* i  : Samples per segment                                   */
     596             :     const Word32 *azimBsShape_fx,  /* i  : Basis shape                                       Q30 */
     597             :     const Word16 subSampFactor     /* i  : Subsampling factor                                    */
     598             : )
     599             : {
     600             :     Word16 i, nI, d0, d;
     601             :     Word32 tmp32;
     602             :     Word16 tmp_e1, tmp_e2;
     603             :     Word16 SegSamples;
     604             : 
     605     3224627 :     SegSamples = 0;
     606     3224627 :     move16();
     607     3224627 :     IF( azimSegSamples != 0 )
     608             :     {
     609     3224627 :         SegSamples = idiv1616( azimSegSamples, subSampFactor );
     610             :     }
     611             : 
     612             :     /* index of closest sample point */
     613     3224627 :     IF( knot_interval_fx == 0 )
     614             :     {
     615           0 :         d0 = 0;
     616           0 :         move16();
     617             :     }
     618             :     ELSE
     619             :     {
     620     3224627 :         tmp32 = L_deposit_h( BASOP_Util_Divide3216_Scale( knot_interval_fx, SegSamples, &tmp_e1 ) );
     621     3224627 :         tmp_e1 = add( tmp_e1, 9 - 15 );
     622     3224627 :         tmp32 = L_deposit_h( BASOP_Util_Divide3232_Scale( L_sub( t_fx, azimKSeq_0_fx ), tmp32, &tmp_e2 ) );
     623     3224627 :         tmp_e2 = add( tmp_e2, sub( 9, tmp_e1 ) );
     624     3224627 :         tmp32 = L_shr( tmp32, sub( 9, tmp_e2 ) ); // Q22 (assuming tmp32 will be in range of Q22)
     625     3224627 :         d0 = extract_l( round_hrFilt_fx( tmp32, Q22 ) );
     626             :     }
     627             : 
     628             :     /* find segment */
     629     3224627 :     nI = 0;
     630     3224627 :     move16();
     631     3224627 :     IF( d0 != 0 )
     632             :     {
     633     3178290 :         nI = idiv1616( d0, SegSamples );
     634             :     }
     635             : 
     636     3224627 :     *num_az_idx = HRTF_MODEL_BSPLINE_NUM_COEFFS;
     637     3224627 :     move16();
     638             : 
     639     3224627 :     IF( d0 % SegSamples == 0 )
     640             :     {
     641      436615 :         *num_az_idx = sub( *num_az_idx, 1 ); /* on the knot points, the last basis function is zero */
     642      436615 :         move16();
     643             :     }
     644             : 
     645    15686520 :     FOR( i = 0; i < *num_az_idx; i++ )
     646             :     {
     647    12461893 :         d = sub( d0, imult1616( ( sub( add( i, nI ), 1 ) ), SegSamples ) ); /* offset of knot_interval */
     648    12461893 :         d = sub( d0, imult1616( sub( add( i, nI ), 1 ), SegSamples ) );
     649    12461893 :         BfVec_fx[i] = azimBsShape_fx[i_mult( abs_s( d ), subSampFactor )];
     650    12461893 :         move32();
     651    12461893 :         AzIdx[i] = add( nI, i ) % NumBFs;
     652    12461893 :         move16();
     653             :     }
     654             : 
     655     3224627 :     return;
     656             : }
     657             : 
     658             : /*-------------------------------------------------------------------*
     659             :  * getStandardBSplineSampVec()
     660             :  *
     661             :  * Obtain a sampled B Spline basis vector.
     662             :  --------------------------------------------------------------------*/
     663             : 
     664     2785026 : static void getStandardBSplineSampVec_fx(
     665             :     Word32 *BfVec_fx,        /* o  : values for non-zero basis functions                Q30 */
     666             :     Word16 *NzIdx,           /* o  : indices of non-zero basis functions                    */
     667             :     Word16 *num_idx,         /* i/o: number of non-zero indices                             */
     668             :     const Word16 NumBFs,     /* i  : the number of basis functions = third index of Bf      */
     669             :     const Word32 t_fx,       /* i  : estimation point                                   Q22 */
     670             :     const Word32 *KSeq_fx,   /* i  : knot sequence including multiplicities             Q22 */
     671             :     const Word16 SegSamples, /* i  : samples per segment                                    */
     672             :     const Word16 *BsLen,     /* i  : lengths of basis shapes                                */
     673             :     const Word16 *BsStart,   /* i  : start of basis shapes                                  */
     674             :     const Word32 *BsShape_fx /* i  : basis shapes                                       Q30 */
     675             : )
     676             : {
     677             :     Word16 i, nI;
     678             :     Word32 knot_interval_fx;
     679             :     Word16 d0, d, shape_idx, start_idx;
     680             :     Word16 tmp_e1, tmp_e2, tmp_e3;
     681             :     Word32 tmp32;
     682             : 
     683             :     /* assuming triple knot at the first knot */
     684     2785026 :     knot_interval_fx = L_deposit_h( BASOP_Util_Divide3216_Scale( L_sub( KSeq_fx[NumBFs - 3], KSeq_fx[0] ), sub( NumBFs, 3 ), &tmp_e1 ) );
     685     2785026 :     tmp_e1 = add( tmp_e1, 9 - 15 );
     686             : 
     687             :     /* index of closest sample point */
     688     2785026 :     tmp32 = L_deposit_h( BASOP_Util_Divide3216_Scale( knot_interval_fx, SegSamples, &tmp_e2 ) );
     689     2785026 :     tmp_e2 = add( tmp_e2, sub( tmp_e1, 15 ) );
     690     2785026 :     tmp32 = L_deposit_h( BASOP_Util_Divide3232_Scale( L_sub( t_fx, KSeq_fx[0] ), tmp32, &tmp_e3 ) );
     691     2785026 :     tmp_e3 = add( tmp_e3, sub( 9, tmp_e2 ) );
     692     2785026 :     tmp32 = L_shr( tmp32, sub( 9, tmp_e3 ) ); // Q22 (assuming tmp32 will be in range of Q22)
     693     2785026 :     d0 = extract_l( round_hrFilt_fx( tmp32, 22 ) );
     694             : 
     695             :     /* find segment */
     696     2785026 :     nI = 0;
     697     2785026 :     move16();
     698     2785026 :     IF( d0 != 0 )
     699             :     {
     700     2769663 :         nI = idiv1616( d0, SegSamples );
     701             :     }
     702     2785026 :     *num_idx = HRTF_MODEL_BSPLINE_NUM_COEFFS;
     703     2785026 :     move16();
     704             : 
     705     2785026 :     IF( d0 % SegSamples == 0 )
     706             :     {
     707      914268 :         *num_idx = sub( *num_idx, 1 ); /* on the knot points, the last basis function is zero */
     708      914268 :         move16();
     709             :     }
     710             : 
     711    13010862 :     FOR( i = 0; i < *num_idx; i++ )
     712             :     {
     713    10225836 :         start_idx = s_max( 0, sub( add( i, nI ), 3 ) );
     714    10225836 :         shape_idx = s_min( add( i, nI ), s_min( 3, sub( sub( NumBFs, 1 ), ( add( i, nI ) ) ) ) );
     715    10225836 :         d = sub( d0, imult1616( start_idx, SegSamples ) );
     716             : 
     717    10225836 :         IF( GT_16( add( i, nI ), sub( NumBFs, 4 ) ) ) /* reverse full shape */
     718             :         {
     719      495283 :             d = sub( sub( BsLen[shape_idx], 1 ), d );
     720             :         }
     721     9730553 :         ELSE IF( GT_16( d, sub( BsLen[shape_idx], 1 ) ) ) /* reverse half shape */
     722             :         {
     723     4189158 :             d = sub( shl( sub( BsLen[shape_idx], 1 ), 1 ), d );
     724             :         }
     725    10225836 :         BfVec_fx[i] = BsShape_fx[add( BsStart[shape_idx], abs_s( d ) )]; /*TT, verify if abs is needed */
     726    10225836 :         move32();
     727    10225836 :         NzIdx[i] = add( nI, i );
     728    10225836 :         move16();
     729             :     }
     730             : 
     731     2785026 :     return;
     732             : }
     733             : 
     734             : 
     735             : /*-------------------------------------------------------------------*
     736             :  * HRTF_model_precalc()
     737             :  *
     738             :  * Set precalculated parameters for HRTF model
     739             :  --------------------------------------------------------------------*/
     740             : 
     741         543 : void HRTF_model_precalc(
     742             :     ModelParams_t *model /* i/o: HRTF model parameters        */
     743             : )
     744             : {
     745             :     Word16 sec_length;
     746             :     Word16 i;
     747         543 :     sec_length = mult( model->K, 10923 ); /*10923 == 2 ^ 15 / 3*/
     748        2172 :     FOR( i = 0; i < HRTF_MODEL_N_SECTIONS; i++ )
     749             :     {
     750        1629 :         model->iSecFirst[i] = imult1616( i, sec_length );
     751        1629 :         move16();
     752             :     }
     753        1629 :     FOR( i = 0; i < HRTF_MODEL_N_SECTIONS - 1; i++ )
     754             :     {
     755        1086 :         model->iSecLast[i] = sub( imult1616( add( i, 1 ), sec_length ), 1 );
     756        1086 :         move16();
     757             :     }
     758         543 :     model->iSecLast[HRTF_MODEL_N_SECTIONS - 1] = sub( model->K, 1 ); /* Final section is longer if (K % nSec) > 0 */
     759         543 :     move16();
     760         543 :     maximum_fx( model->azimDim3, model->elevDim3, &model->azimDim3Max );
     761         543 :     return;
     762             : }
     763             : 
     764             : 
     765             : /*-------------------------------------------------------------------*
     766             :  * BSplineModelEvalDealloc()
     767             :  *
     768             :  * Deallocate BSpline HR Filter model
     769             :  --------------------------------------------------------------------*/
     770         486 : void BSplineModelEvalDealloc_fx(
     771             :     ModelParams_t *model,  /* i  : Model parameters           */
     772             :     ModelEval_t *modelEval /* i  : Model evaluation structure */
     773             : )
     774             : {
     775             :     /* Allocated in LoadBSplineBinary() */
     776             :     Word16 i;
     777             : 
     778         486 :     IF( model->modelROM )
     779             :     {
     780         972 :         FOR( i = 0; i < model->num_unique_azim_splines; i++ )
     781             :         {
     782         486 :             free( model->azimBsShape_dyn_fx[i] );
     783             :         }
     784         486 :         free( model->azimBsShape_dyn_fx );
     785         486 :         free( (void *) model->azimBsShape_fx ); /* void* cast needed to please both gcc and Visual studio compilers. Deallocating const float** should be fine and gcc agrees, but Visual studio complains. */
     786        7776 :         FOR( i = 0; i < model->elevDim3; i++ )
     787             :         {
     788        7290 :             free( model->azimKSeq_fx[i] );
     789             :         }
     790         486 :         free( model->azimKSeq_fx );
     791         486 :         IF( modelEval != NULL )
     792             :         {
     793         486 :             free( modelEval->hrfModL_fx );
     794         486 :             free( modelEval->hrfModR_fx );
     795             :         }
     796             :     }
     797         486 :     return;
     798             : }
     799             : 
     800             : 
     801             : /*-------------------------------------------------------------------*
     802             :  * SkipSmallest_ValueIndex()
     803             :  *
     804             :  * Returns indices to the  largest values in a ValueIndex list,
     805             :  * unordered (i.e. skip the n_smallest values, return the remainder).
     806             :  --------------------------------------------------------------------*/
     807             : 
     808     5570052 : static void SkipSmallest_ValueIndex_fx(
     809             :     Word16 *use_inds,       /* i/o: List of indices to use    */
     810             :     const ValueIndex_t *VI, /* i  : List of value-index items */
     811             :     const Word16 N,         /* i  : Length of list            */
     812             :     const Word16 n_smallest /* i  : Number of items to skip   */
     813             : )
     814             : {
     815             :     Word16 i, j, k, flag;
     816             :     Word16 skip_inds[HRTF_MODEL_BSPLINE_NUM_COEFFS_SQ];
     817             :     Word32 candidate_max; /* Stores the max value in the shortlist (next to be kicked off) and its index */
     818             :     Word16 candidate_max_i;
     819             : 
     820             :     /* Initialise with first entries of VI */
     821     5570052 :     candidate_max = 0;
     822     5570052 :     move32();
     823     5570052 :     candidate_max_i = 0;
     824     5570052 :     move16();
     825    15627284 :     FOR( j = 0; j < n_smallest; j++ )
     826             :     {
     827    10057232 :         skip_inds[j] = j;
     828    10057232 :         move16();
     829    10057232 :         IF( LT_32( candidate_max, VI[j].val_fx ) )
     830             :         {
     831     3514181 :             candidate_max = VI[j].val_fx;
     832     3514181 :             move32();
     833     3514181 :             candidate_max_i = j;
     834     3514181 :             move16();
     835             :         }
     836             :     }
     837             : 
     838             :     /* Look in the remainder of the list for smaller values */
     839    70347286 :     FOR( i = n_smallest; i < N; i++ )
     840             :     {
     841   165925611 :         FOR( j = 0; j < n_smallest; j++ )
     842             :         {
     843   107700665 :             IF( LT_32( VI[i].val_fx, VI[skip_inds[j]].val_fx ) )
     844             :             {
     845             :                 /* Found a smaller value, so it goes into the list, replacing candidate_max. */
     846     6552288 :                 skip_inds[candidate_max_i] = i;
     847     6552288 :                 move16();
     848     6552288 :                 candidate_max = VI[i].val_fx;
     849     6552288 :                 move32();
     850             :                 /* Update candidate_max */
     851    30276953 :                 FOR( k = 0; k < n_smallest; k++ )
     852             :                 {
     853    23724665 :                     IF( GT_32( VI[skip_inds[k]].val_fx, candidate_max ) )
     854             :                     {
     855     4296086 :                         candidate_max = VI[skip_inds[k]].val_fx;
     856     4296086 :                         move32();
     857     4296086 :                         candidate_max_i = k;
     858     4296086 :                         move16();
     859             :                     }
     860             :                 }
     861     6552288 :                 BREAK;
     862             :             }
     863             :         }
     864             :     }
     865             : 
     866             :     /* Build the list of indices that will not be skipped */
     867     5570052 :     k = 0;
     868     5570052 :     move16();
     869    80404518 :     FOR( j = 0; j < N; j++ )
     870             :     {
     871    74834466 :         flag = 1;
     872    74834466 :         move16();
     873   207352262 :         FOR( i = 0; i < n_smallest; i++ )
     874             :         {
     875   142575028 :             IF( EQ_16( skip_inds[i], j ) )
     876             :             {
     877    10057232 :                 flag = 0;
     878    10057232 :                 move16();
     879    10057232 :                 BREAK;
     880             :             }
     881             :         }
     882    74834466 :         IF( flag )
     883             :         {
     884    64777234 :             use_inds[k] = j;
     885    64777234 :             move16();
     886    64777234 :             k = add( k, 1 );
     887             :         }
     888             :     }
     889             : 
     890     5570052 :     return;
     891             : }

Generated by: LCOV version 1.14