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

Generated by: LCOV version 1.14