LCOV - code coverage report
Current view: top level - lib_enc - transient_detection_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 749 840 89.2 %
Date: 2025-05-03 01:55:50 Functions: 30 31 96.8 %

          Line data    Source code
       1             : /*====================================================================================
       2             :     EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
       3             :   ====================================================================================*/
       4             : 
       5             : 
       6             : #include "options.h"
       7             : #include "stl.h"
       8             : #include "basop_util.h"
       9             : // #include "prot_fx.h"
      10             : #include "rom_com.h"
      11             : #include <assert.h>
      12             : #include <stdio.h>
      13             : #include <stdlib.h>
      14             : #include <stdarg.h>
      15             : #include "prot_fx.h"      /* Function prototypes                    */
      16             : #include "ivas_prot_fx.h" /* Function prototypes                    */
      17             : #include "prot_fx_enc.h"  /* Function prototypes                    */
      18             : 
      19             : 
      20             : /* Exponent of attack threshold. Picked according to current threshold values. */
      21             : #define ATTACKTHRESHOLD_E 4
      22             : /* Exponent of subblock energies and accumulated subblock energies.
      23             :    The current value of 2 does not prevent saturations to happen in all cases. */
      24             : #define SUBBLOCK_NRG_E 4
      25             : /* Exponent of the subblock energy change.
      26             :    This value is coupled to the transient detector API. */
      27             : #define SUBBLOCK_NRG_CHANGE_E NRG_CHANGE_E
      28             : 
      29             : #define MIN_BLOCK_ENERGY ( (Word32) 1 )
      30             : 
      31             : #define MIN_BLOCK_ENERGY_FX         107
      32             : #define THR_HIGH_FX                 17408      /* 8.5f in Q11   */
      33             : #define THR_NORM_HIGH_FX            16384      /* 8 in Q11      */
      34             : #define THR_NORM_LOW_FX             9216       /* 4.5f in Q11   */
      35             : #define THR_LOW_FX                  8704       /* 4.25f in Q11  */
      36             : #define THR_LOW_STEP_FX             ONE_IN_Q11 /* 1 in Q11      */
      37             : #define MIN_BLOCK_ENERGY_IVAS_FX_Q7 13743      /* 107.37f in Q7 */
      38             : 
      39             : /************************************************/
      40             : /*                                              */
      41             : /*        Internal functions prototypes         */
      42             : /*                                              */
      43             : /************************************************/
      44             : 
      45             : static void InitDelayBuffer( Word16 nFrameLength, Word16 nDelay, DelayBuffer *pDelayBuffer );
      46             : static void InitSubblockEnergies( Word16 nFrameLength, Word16 nDelay, DelayBuffer *pDelayBuffer, SubblockEnergies *pSubblockEnergies );
      47             : static void InitSubblockEnergies_ivas_fx( Word16 nFrameLength, Word16 nDelay, DelayBuffer *pDelayBuffer, SubblockEnergies *pSubblockEnergies );
      48             : static void InitTransientDetector_fx( SubblockEnergies *pSubblockEnergies, Word16 nDelay, Word16 nSubblocksToCheck, TCheckSubblocksForAttack_fx pCheckSubblocksForAttack, Word16 attackRatioThreshold, TransientDetector *pTransientDetector );
      49             : static void InitTransientDetector_ivas_fx( SubblockEnergies *pSubblockEnergies, Word16 nDelay, Word16 nSubblocksToCheck, TCheckSubblocksForAttack_fx pCheckSubblocksForAttack, Word16 attackRatioThreshold, TransientDetector *pTransientDetector );
      50             : static void UpdateDelayBuffer( Word16 const *input, Word16 nSamplesAvailable, DelayBuffer *pDelayBuffer );
      51             : static void HighPassFilter_fx( Word16 const *input, Word16 length, Word16 *pFirState1, Word16 *pFirState2, Word16 *output );
      52             : static void UpdateSubblockEnergies( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies );
      53             : static void CalculateSubblockEnergies( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies );
      54             : static void RunTransientDetector_fx( TransientDetector *pTransientDetector );
      55             : 
      56             : static void CalculateSubblockEnergies_ivas_fx( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies );
      57             : 
      58             : static void UpdateSubblockEnergies_ivas_fx( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies );
      59             : 
      60             : /************************************************/
      61             : /*                                              */
      62             : /*  Functions that define transient detectors   */
      63             : /*                                              */
      64             : /************************************************/
      65             : 
      66             : /** TCX decision.
      67             :  * Check IF there is an attack in a subblock. Version FOR TCX Long/Short decision.
      68             :  * See TCheckSubblocksForAttack_fx FOR definition of parameters.
      69             :  * It is assumed that the delay of MDCT overlap was not taken into account, so that the last subblock corresponds to the newest input subblock.
      70             :  */
      71        3100 : static void GetAttackForTCXDecision( Word32 const *pSubblockNrg, Word32 const *pAccSubblockNrg, Word16 nSubblocks, Word16 nPastSubblocks, Word16 attackRatioThreshold, Word16 *pbIsAttackPresent, Word16 *pAttackIndex )
      72             : {
      73             :     Word16 i;
      74             :     Word16 bIsAttackPresent, attackIndex;
      75             :     Word16 attackRatioThreshold_1_5;
      76             : 
      77             :     (void) nPastSubblocks;
      78             :     (void) nSubblocks;
      79        3100 :     assert( nSubblocks >= NSUBBLOCKS );
      80        3100 :     assert( nPastSubblocks >= 2 );
      81             : 
      82             :     /* attackRatioThreshold_1_5 = attackRatioThreshold * 1.5, exponent is ATTACKTHRESHOLD_E+1 */
      83        3100 :     attackRatioThreshold_1_5 = add( shr( attackRatioThreshold, 2 ), shr( attackRatioThreshold, 1 ) );
      84             : 
      85        3100 :     move16();
      86        3100 :     move16();
      87        3100 :     bIsAttackPresent = FALSE;
      88        3100 :     attackIndex = 0;
      89             :     /* Search for the last attack in the subblocks */
      90        3100 :     if ( s_or( (Word16) GT_32( L_shr( pSubblockNrg[-1], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[-1], attackRatioThreshold ) ),
      91        3100 :                L_sub( L_shr( pSubblockNrg[-2], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[-2], attackRatioThreshold ) ) > 0 ) )
      92             :     {
      93          22 :         move16();
      94          22 :         bIsAttackPresent = TRUE;
      95             :     }
      96             : 
      97       27900 :     FOR( i = 0; i < NSUBBLOCKS; i++ )
      98             :     {
      99       24800 :         IF( GT_32( L_shr( pSubblockNrg[i], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[i], attackRatioThreshold ) ) )
     100             :         {
     101          96 :             if ( i < 6 )
     102             :             {
     103          73 :                 move16();
     104          73 :                 bIsAttackPresent = TRUE;
     105             :             }
     106             : 
     107          96 :             if ( s_and( (Word16) NE_16( attackIndex, 2 ), (Word16) NE_16( attackIndex, 6 ) ) )
     108             :             {
     109          95 :                 move16();
     110          95 :                 attackIndex = i;
     111             :             }
     112             :         }
     113             :         ELSE /* no attack, but set index anyway in case of strong energy increase */
     114             :         {
     115       24704 :             IF( s_and( ( (Word16) GT_32( L_shr( pSubblockNrg[i], 1 + ATTACKTHRESHOLD_E ), Mpy_32_16_1( pSubblockNrg[sub( i, 1 )], attackRatioThreshold_1_5 ) ) ),
     116             :                        ( L_sub( L_shr( pSubblockNrg[i], 1 + ATTACKTHRESHOLD_E ), Mpy_32_16_1( pSubblockNrg[sub( i, 2 )], attackRatioThreshold_1_5 ) ) > 0 ) ) )
     117             :             {
     118             : 
     119          26 :                 if ( s_and( (Word16) NE_16( attackIndex, 2 ), (Word16) NE_16( attackIndex, 6 ) ) )
     120             :                 {
     121          26 :                     move16();
     122          26 :                     attackIndex = i;
     123             :                 }
     124             :             }
     125             :         }
     126             :     }
     127             :     /* avoid post-echos on click sounds (very short transients) due to TNS aliasing */
     128        3100 :     if ( EQ_16( attackIndex, 4 ) )
     129             :     {
     130          13 :         move16();
     131          13 :         attackIndex = 7;
     132             :     }
     133        3100 :     if ( EQ_16( attackIndex, 5 ) )
     134             :     {
     135          22 :         move16();
     136          22 :         attackIndex = 6;
     137             :     }
     138             : 
     139        3100 :     move16();
     140        3100 :     move16();
     141        3100 :     *pAttackIndex = attackIndex;
     142        3100 :     *pbIsAttackPresent = bIsAttackPresent;
     143        3100 : }
     144             : 
     145     1170853 : static void GetAttackForTCXDecision_ivas_fx( Word32 const *pSubblockNrg, Word32 const *pAccSubblockNrg, Word16 nSubblocks, Word16 nPastSubblocks, Word16 attackRatioThreshold, Word16 *pbIsAttackPresent, Word16 *pAttackIndex )
     146             : {
     147             :     Word16 i;
     148             :     Word16 bIsAttackPresent, attackIndex;
     149             :     Word16 attackRatioThreshold_1_5;
     150             :     Word64 W_tmp1, W_tmp2, W_tmp3;
     151             : 
     152             :     (void) nPastSubblocks;
     153             :     (void) nSubblocks;
     154     1170853 :     assert( nSubblocks >= NSUBBLOCKS );
     155     1170853 :     assert( nPastSubblocks >= 2 );
     156             : 
     157             :     /* attackRatioThreshold_1_5 = attackRatioThreshold * 1.5, exponent is ATTACKTHRESHOLD_E+1 */
     158     1170853 :     attackRatioThreshold_1_5 = add( shr( attackRatioThreshold, 2 ), shr( attackRatioThreshold, 1 ) );
     159             : 
     160     1170853 :     move16();
     161     1170853 :     move16();
     162     1170853 :     bIsAttackPresent = FALSE;
     163     1170853 :     attackIndex = -1;
     164             :     /* Search for the last attack in the subblocks */
     165     1170853 :     IF( s_or( (Word16) GT_32( L_shr( pSubblockNrg[-1], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[-1], attackRatioThreshold ) ),
     166             :               L_sub( L_shr( pSubblockNrg[-2], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[-2], attackRatioThreshold ) ) > 0 ) )
     167             :     {
     168        4566 :         move16();
     169        4566 :         bIsAttackPresent = TRUE;
     170        4566 :         attackIndex = 0;
     171        4566 :         move16();
     172             :     }
     173             : 
     174    10537677 :     FOR( i = 0; i < NSUBBLOCKS; i++ )
     175             :     {
     176     9366824 :         W_tmp2 = W_shr( W_mult_32_16( pAccSubblockNrg[i], attackRatioThreshold ), 1 );
     177     9366824 :         W_tmp1 = W_shl( pSubblockNrg[i], ( 15 - ATTACKTHRESHOLD_E ) );
     178             : 
     179     9366824 :         IF( GT_64( W_tmp1, W_tmp2 ) )
     180             :         {
     181       26373 :             if ( i < 6 )
     182             :             {
     183       21736 :                 move16();
     184       21736 :                 bIsAttackPresent = TRUE;
     185             :             }
     186             : 
     187       26373 :             IF( s_and( (Word16) NE_16( attackIndex, 2 ), (Word16) NE_16( attackIndex, 6 ) ) )
     188             :             {
     189       26003 :                 move16();
     190       26003 :                 attackIndex = i;
     191       26003 :                 W_tmp2 = W_shr( W_mult_32_16( pAccSubblockNrg[i], attackRatioThreshold ), 1 );
     192       26003 :                 W_tmp2 = W_add( W_tmp2, W_shr( W_tmp2, 3 ) ); // pAccSubblockNrg[i] * 1.125f
     193       26003 :                 W_tmp1 = W_shl( pSubblockNrg[i], ( 15 - ATTACKTHRESHOLD_E ) );
     194       26003 :                 if ( s_and( (Word16) LT_64( W_tmp1, W_tmp2 ), s_or( (Word16) EQ_16( i, 2 ), (Word16) EQ_16( i, 6 ) ) ) )
     195             :                 {
     196         444 :                     attackIndex = add( attackIndex, 1 ); /* avoid minimum overlap to prevent clicks */
     197             :                 }
     198             :             }
     199             :         }
     200             :         ELSE /* no attack, but set index anyway in case of strong energy increase */
     201             :         {
     202     9340451 :             W_tmp2 = W_shr( W_mult_32_16( pSubblockNrg[i - 1], attackRatioThreshold_1_5 ), 1 );
     203     9340451 :             W_tmp1 = W_shl( pSubblockNrg[i], ( 15 - ( ATTACKTHRESHOLD_E + 1 ) ) );
     204     9340451 :             W_tmp3 = W_shr( W_mult_32_16( pSubblockNrg[i - 2], attackRatioThreshold_1_5 ), 1 );
     205             : 
     206     9340451 :             IF( s_and( ( (Word16) GT_64( W_tmp1, W_tmp2 ) ),
     207             :                        ( W_sub( W_tmp1, W_tmp3 ) > 0 ) ) )
     208             :             {
     209             : 
     210        6436 :                 IF( s_and( (Word16) NE_16( attackIndex, 2 ), (Word16) NE_16( attackIndex, 6 ) ) )
     211             :                 {
     212        6425 :                     move16();
     213        6425 :                     attackIndex = i;
     214             : 
     215        6425 :                     W_tmp2 = W_mult_32_16( pSubblockNrg[i - 1], attackRatioThreshold );
     216        6425 :                     W_tmp3 = W_mult_32_16( pSubblockNrg[i - 2], attackRatioThreshold );
     217        6425 :                     W_tmp1 = W_shl( pSubblockNrg[i], ( 15 - ATTACKTHRESHOLD_E ) );
     218             : 
     219        6425 :                     if ( s_and( (Word16) s_or( (Word16) LT_64( W_tmp1, W_tmp2 ), (Word16)
     220        6425 :                                                                                      LT_64( W_tmp1, W_tmp3 ) ),
     221        6425 :                                 s_or( (Word16) EQ_16( i, 2 ), (Word16) EQ_16( i, 6 ) ) ) )
     222             :                     {
     223         835 :                         attackIndex = add( attackIndex, 1 ); /* avoid minimum overlap to prevent clicks */
     224             :                     }
     225             :                 }
     226             :             }
     227             :         }
     228             :     }
     229             :     /* avoid post-echos on click sounds (very short transients) due to TNS aliasing */
     230     1170853 :     if ( EQ_16( attackIndex, 4 ) )
     231             :     {
     232        2550 :         move16();
     233        2550 :         attackIndex = 7;
     234             :     }
     235     1170853 :     if ( EQ_16( attackIndex, 5 ) )
     236             :     {
     237        2827 :         move16();
     238        2827 :         attackIndex = 6;
     239             :     }
     240             : 
     241     1170853 :     move16();
     242     1170853 :     move16();
     243     1170853 :     *pAttackIndex = attackIndex;
     244     1170853 :     *pbIsAttackPresent = bIsAttackPresent;
     245     1170853 : }
     246             : 
     247           0 : void GetAttackForTCXDecision_fx( Word32 const *pSubblockNrg, Word32 const *pAccSubblockNrg, Word16 nSubblocks, Word16 nPastSubblocks, Word16 attackRatioThreshold, Word16 *pbIsAttackPresent, Word16 *pAttackIndex )
     248             : {
     249             :     Word16 i;
     250             :     Word16 bIsAttackPresent, attackIndex;
     251             :     Word16 attackRatioThreshold_1_5;
     252             : 
     253             :     (void) nPastSubblocks;
     254             :     (void) nSubblocks;
     255           0 :     assert( nSubblocks >= NSUBBLOCKS );
     256           0 :     assert( nPastSubblocks >= 2 );
     257             : 
     258             :     /* attackRatioThreshold_1_5 = attackRatioThreshold * 1.5, exponent is ATTACKTHRESHOLD_E+1 */
     259           0 :     attackRatioThreshold_1_5 = add( shr( attackRatioThreshold, 2 ), shr( attackRatioThreshold, 1 ) );
     260             : 
     261           0 :     move16();
     262           0 :     move16();
     263           0 :     bIsAttackPresent = FALSE;
     264           0 :     attackIndex = 0;
     265             :     /* Search for the last attack in the subblocks */
     266           0 :     if ( s_or( (Word16) GT_32( L_shr( pSubblockNrg[-1], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[-1], attackRatioThreshold ) ),
     267           0 :                L_sub( L_shr( pSubblockNrg[-2], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[-2], attackRatioThreshold ) ) > 0 ) )
     268             :     {
     269           0 :         move16();
     270           0 :         bIsAttackPresent = TRUE;
     271             :     }
     272             : 
     273           0 :     FOR( i = 0; i < NSUBBLOCKS; i++ )
     274             :     {
     275           0 :         IF( GT_32( L_shr( pSubblockNrg[i], ATTACKTHRESHOLD_E ), Mpy_32_16_1( pAccSubblockNrg[i], attackRatioThreshold ) ) )
     276             :         {
     277           0 :             if ( i < 6 )
     278             :             {
     279           0 :                 move16();
     280           0 :                 bIsAttackPresent = TRUE;
     281             :             }
     282             : 
     283           0 :             if ( s_and( (Word16) NE_16( attackIndex, 2 ), (Word16) NE_16( attackIndex, 6 ) ) )
     284             :             {
     285           0 :                 move16();
     286           0 :                 attackIndex = i;
     287             :             }
     288             :         }
     289             :         ELSE /* no attack, but set index anyway in case of strong energy increase */
     290             :         {
     291           0 :             IF( s_and( ( (Word16) GT_32( L_shr( pSubblockNrg[i], 1 + ATTACKTHRESHOLD_E ), Mpy_32_16_1( pSubblockNrg[sub( i, 1 )], attackRatioThreshold_1_5 ) ) ),
     292             :                        ( L_sub( L_shr( pSubblockNrg[i], 1 + ATTACKTHRESHOLD_E ), Mpy_32_16_1( pSubblockNrg[sub( i, 2 )], attackRatioThreshold_1_5 ) ) > 0 ) ) )
     293             :             {
     294             : 
     295           0 :                 if ( s_and( (Word16) NE_16( attackIndex, 2 ), (Word16) NE_16( attackIndex, 6 ) ) )
     296             :                 {
     297           0 :                     move16();
     298           0 :                     attackIndex = i;
     299             :                 }
     300             :             }
     301             :         }
     302             :     }
     303             :     /* avoid post-echos on click sounds (very short transients) due to TNS aliasing */
     304           0 :     if ( EQ_16( attackIndex, 4 ) )
     305             :     {
     306           0 :         move16();
     307           0 :         attackIndex = 7;
     308             :     }
     309           0 :     if ( EQ_16( attackIndex, 5 ) )
     310             :     {
     311           0 :         move16();
     312           0 :         attackIndex = 6;
     313             :     }
     314             : 
     315           0 :     move16();
     316           0 :     move16();
     317           0 :     *pAttackIndex = attackIndex;
     318           0 :     *pbIsAttackPresent = bIsAttackPresent;
     319           0 : }
     320             : 
     321             : /** Initialize TCX transient detector.
     322             :  * See InitTransientDetector_fx for definition of parameters.
     323             :  */
     324           3 : static void InitTCXTransientDetector( Word16 nDelay, SubblockEnergies *pSubblockEnergies, TransientDetector *pTransientDetector )
     325             : {
     326           3 :     InitTransientDetector_fx( pSubblockEnergies, nDelay, NSUBBLOCKS, GetAttackForTCXDecision, 17408 /*8.5f/(1<<ATTACKTHRESHOLD_E) Q15*/, pTransientDetector );
     327           3 : }
     328             : 
     329             : 
     330             : /************************************************/
     331             : /*                                              */
     332             : /*              Interface functions             */
     333             : /*                                              */
     334             : /************************************************/
     335             : 
     336           3 : void InitTransientDetection_fx( Word16 nFrameLength,
     337             :                                 Word16 nTCXDelay,
     338             :                                 TransientDetection *pTransientDetection )
     339             : {
     340             :     /* Init the delay buffer. */
     341           3 :     InitDelayBuffer( nFrameLength, nTCXDelay, &pTransientDetection->delayBuffer );
     342             :     /* Init a subblock energies buffer used for the TCX Short/Long decision. */
     343           3 :     InitSubblockEnergies( nFrameLength, nTCXDelay, &pTransientDetection->delayBuffer, &pTransientDetection->subblockEnergies );
     344             :     /* Init the TCX Short/Long transient detector. */
     345           3 :     InitTCXTransientDetector( nTCXDelay, &pTransientDetection->subblockEnergies, &pTransientDetection->transientDetector );
     346             :     /* We need two past subblocks for the TCX TD and NSUBBLOCKS+1 for the temporal flatness measure FOR the TCX LTP. */
     347           6 :     pTransientDetection->transientDetector.pSubblockEnergies->nDelay =
     348           3 :         add( pTransientDetection->transientDetector.pSubblockEnergies->nDelay, NSUBBLOCKS + 1 );
     349           3 : }
     350             : 
     351        8183 : void InitTransientDetection_ivas_fx( Word16 nFrameLength,
     352             :                                      Word16 nTCXDelay,
     353             :                                      TRAN_DET_HANDLE pTransientDetection,
     354             :                                      const Word16 ext_mem_flag )
     355             : {
     356             :     /* Init the delay buffer. */
     357        8183 :     InitDelayBuffer( nFrameLength, nTCXDelay, &pTransientDetection->delayBuffer );
     358             :     /* Init a subblock energies buffer used for the TCX Short/Long decision. */
     359        8183 :     InitSubblockEnergies_ivas_fx( nFrameLength, nTCXDelay, &pTransientDetection->delayBuffer, &pTransientDetection->subblockEnergies );
     360             :     /* Init the TCX Short/Long transient detector. */
     361        8183 :     InitTransientDetector_ivas_fx( &pTransientDetection->subblockEnergies, nTCXDelay, NSUBBLOCKS, GetAttackForTCXDecision_ivas_fx, 17408 /*8.5f/(1<<ATTACKTHRESHOLD_E) Q15*/, &pTransientDetection->transientDetector );
     362             :     /* We need two past subblocks for the TCX TD and NSUBBLOCKS+1 for the temporal flatness measure FOR the TCX LTP. */
     363        8183 :     IF( ext_mem_flag )
     364             :     {
     365       16366 :         pTransientDetection->transientDetector.pSubblockEnergies->nDelay =
     366        8183 :             add( pTransientDetection->transientDetector.pSubblockEnergies->nDelay, add( ( NSUBBLOCKS + 1 ), ( NSUBBLOCKS_SHIFT + 1 ) ) );
     367        8183 :         move16();
     368             :     }
     369             :     ELSE
     370             :     {
     371           0 :         pTransientDetection->transientDetector.pSubblockEnergies->nDelay =
     372           0 :             add( pTransientDetection->transientDetector.pSubblockEnergies->nDelay, NSUBBLOCKS + 1 );
     373           0 :         move16();
     374             :     }
     375        8183 : }
     376             : 
     377             : /**
     378             :  * \brief Calculate average of temporal energy change.
     379             :  * \return average temporal energy change with exponent = 8
     380             :  */
     381        4410 : Word16 GetTCXAvgTemporalFlatnessMeasure_fx( struct TransientDetection const *pTransientDetection, Word16 nCurrentSubblocks, Word16 nPrevSubblocks )
     382             : {
     383             :     Word16 i;
     384             :     TransientDetector const *pTransientDetector;
     385             :     SubblockEnergies const *pSubblockEnergies;
     386             :     Word16 nDelay;
     387             :     Word16 nRelativeDelay;
     388             :     Word16 const *pSubblockNrgChange;
     389             :     Word32 sumTempFlatness;
     390             :     Word16 nTotBlocks;
     391             : 
     392             : 
     393             :     /* Initialization */
     394        4410 :     pTransientDetector = &pTransientDetection->transientDetector;
     395        4410 :     pSubblockEnergies = pTransientDetector->pSubblockEnergies;
     396        4410 :     move16();
     397        4410 :     nDelay = pTransientDetector->nDelay;
     398        4410 :     nRelativeDelay = sub( pSubblockEnergies->nDelay, nDelay );
     399        4410 :     pSubblockNrgChange = NULL;
     400        4410 :     nTotBlocks = add( nCurrentSubblocks, nPrevSubblocks );
     401             : 
     402        4410 :     assert( nTotBlocks > 0 );
     403             : 
     404        4410 :     sumTempFlatness = L_deposit_l( 0 );
     405             : 
     406        4410 :     assert( ( nPrevSubblocks <= nRelativeDelay ) && ( nCurrentSubblocks <= NSUBBLOCKS + nDelay ) );
     407             : 
     408        4410 :     move16();
     409        4410 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange[sub( nRelativeDelay, nPrevSubblocks )];
     410             : 
     411       45565 :     FOR( i = 0; i < nTotBlocks; i++ )
     412             :     {
     413       41155 :         sumTempFlatness = L_add( sumTempFlatness, L_deposit_l( pSubblockNrgChange[i] ) );
     414             :     }
     415             : 
     416             :     /* exponent = AVG_FLAT_E */
     417        4410 :     i = div_l( L_shl( sumTempFlatness, 16 - 15 + SUBBLOCK_NRG_CHANGE_E - AVG_FLAT_E ), nTotBlocks );
     418             : 
     419        4410 :     return i;
     420             : }
     421             : 
     422     2951968 : Word32 GetTCXAvgTemporalFlatnessMeasure_ivas_fx( struct TransientDetection const *pTransientDetection, Word16 nCurrentSubblocks, Word16 nPrevSubblocks )
     423             : {
     424             :     Word32 i;
     425             :     TransientDetector const *pTransientDetector;
     426             :     SubblockEnergies const *pSubblockEnergies;
     427             :     Word16 nDelay;
     428             :     Word16 nRelativeDelay;
     429             :     Word32 const *pSubblockNrgChange;
     430             :     Word16 const *pSubblockNrgChange_exp;
     431             :     Word32 sumTempFlatness;
     432             :     Word16 nTotBlocks, sumTempFlatness_exp, exp;
     433             : 
     434             :     /* Initialization */
     435     2951968 :     pTransientDetector = &pTransientDetection->transientDetector;
     436     2951968 :     pSubblockEnergies = pTransientDetector->pSubblockEnergies;
     437     2951968 :     nDelay = pTransientDetector->nDelay;
     438     2951968 :     move16();
     439     2951968 :     nRelativeDelay = sub( pSubblockEnergies->nDelay, nDelay );
     440     2951968 :     pSubblockNrgChange = NULL;
     441     2951968 :     nTotBlocks = add( nCurrentSubblocks, nPrevSubblocks );
     442             : 
     443     2951968 :     assert( nTotBlocks > 0 );
     444             : 
     445     2951968 :     sumTempFlatness = L_deposit_l( 0 );
     446             : 
     447     2951968 :     assert( ( nPrevSubblocks <= nRelativeDelay ) && ( nCurrentSubblocks <= NSUBBLOCKS + nDelay ) );
     448             : 
     449     2951968 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange_32fx[( nRelativeDelay - nPrevSubblocks )];
     450     2951968 :     pSubblockNrgChange_exp = &pSubblockEnergies->subblockNrgChange_exp[( nRelativeDelay - nPrevSubblocks )];
     451     2951968 :     sumTempFlatness = 0;
     452     2951968 :     move32();
     453     2951968 :     sumTempFlatness_exp = 0;
     454     2951968 :     move16();
     455    30567032 :     FOR( i = 0; i < nTotBlocks; i++ )
     456             :     {
     457    27615064 :         sumTempFlatness = BASOP_Util_Add_Mant32Exp( sumTempFlatness, sumTempFlatness_exp, pSubblockNrgChange[i], pSubblockNrgChange_exp[i], &sumTempFlatness_exp );
     458             :     }
     459             : 
     460             :     /* exponent = AVG_FLAT_E */
     461     2951968 :     i = BASOP_Util_Divide3232_Scale_newton( sumTempFlatness, nTotBlocks, &exp );
     462     2951968 :     exp = add( exp, sub( sumTempFlatness_exp, 31 ) );
     463     2951968 :     i = L_shl_sat( i, sub( exp, 10 ) ); // Can be saturated, since it is used for comparision againt 3.25/20.0f, Q21
     464     2951968 :     return i;
     465             : }
     466             : 
     467        1310 : Word16 GetTCXMaxenergyChange_fx( struct TransientDetection const *pTransientDetection,
     468             :                                  const Word8 isTCX10,
     469             :                                  const Word16 nCurrentSubblocks,
     470             :                                  const Word16 nPrevSubblocks )
     471             : {
     472             :     Word16 i;
     473             :     TransientDetector const *pTransientDetector;
     474             :     SubblockEnergies const *pSubblockEnergies;
     475             :     Word16 nDelay;
     476             :     Word16 nRelativeDelay;
     477             :     Word16 const *pSubblockNrgChange;
     478             :     Word16 maxEnergyChange;
     479             :     Word16 nTotBlocks;
     480             : 
     481             : 
     482        1310 :     pTransientDetector = &pTransientDetection->transientDetector;
     483        1310 :     pSubblockEnergies = pTransientDetector->pSubblockEnergies;
     484        1310 :     move16();
     485        1310 :     nDelay = pTransientDetector->nDelay;
     486        1310 :     nRelativeDelay = sub( pSubblockEnergies->nDelay, nDelay );
     487        1310 :     pSubblockNrgChange = NULL;
     488        1310 :     nTotBlocks = nCurrentSubblocks + nPrevSubblocks;
     489        1310 :     move16();
     490             : 
     491        1310 :     assert( nTotBlocks > 0 );
     492        1310 :     maxEnergyChange = 0 /*0.0f Q7*/;
     493        1310 :     move16();
     494             : 
     495        1310 :     assert( ( nPrevSubblocks <= nRelativeDelay ) && ( nCurrentSubblocks <= NSUBBLOCKS + nDelay ) );
     496        1310 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange[nRelativeDelay - nPrevSubblocks];
     497             : 
     498        1310 :     IF( s_or( pTransientDetector->bIsAttackPresent, isTCX10 ) ) /* frame is TCX-10 */
     499             :     {
     500          39 :         Word32 const *pSubblockNrg = &pSubblockEnergies->subblockNrg[sub( nRelativeDelay, nPrevSubblocks )];
     501             :         Word32 nrgMin, nrgMax;
     502          39 :         Word16 idxMax = 0;
     503             : 
     504          39 :         move16();
     505             : 
     506          39 :         nrgMax = L_add( pSubblockNrg[0], 0 );
     507             : 
     508             :         /* find subblock with maximum energy */
     509         484 :         FOR( i = 1; i < nTotBlocks; i++ )
     510             :         {
     511         445 :             if ( LT_32( nrgMax, pSubblockNrg[i] ) )
     512             :             {
     513         113 :                 idxMax = i;
     514         113 :                 move16();
     515             :             }
     516         445 :             nrgMax = L_max( nrgMax, pSubblockNrg[i] );
     517             :         }
     518             : 
     519          39 :         nrgMin = L_add( nrgMax, 0 );
     520             : 
     521             :         /* find minimum energy after maximum */
     522         191 :         FOR( i = idxMax + 1; i < nTotBlocks; i++ )
     523             :         {
     524         152 :             nrgMin = L_min( nrgMin, pSubblockNrg[i] );
     525             :         }
     526             :         /* lower maxEnergyChange if energy doesn't decrease much after energy peak */
     527             :         /* if (nrgMin > 0.375f * nrgMax) */
     528          39 :         if ( LT_32( Mpy_32_16_1( nrgMax, 12288 /*0.375f Q15*/ ), nrgMin ) )
     529             :         {
     530          10 :             nTotBlocks = sub( idxMax, 3 );
     531             :         }
     532             :     }
     533             : 
     534       17609 :     FOR( i = 0; i < nTotBlocks; i++ )
     535             :     {
     536       16299 :         maxEnergyChange = s_max( maxEnergyChange, pSubblockNrgChange[i] );
     537             :     }
     538             : 
     539        1310 :     move16();
     540        1310 :     i = maxEnergyChange;
     541             : 
     542        1310 :     return i;
     543             : }
     544             : 
     545             : 
     546      878643 : Word16 GetTCXMaxenergyChange_ivas_fx( TRAN_DET_HANDLE hTranDet,
     547             :                                       const Word8 isTCX10,
     548             :                                       const Word16 nCurrentSubblocks,
     549             :                                       const Word16 nPrevSubblocks )
     550             : {
     551             :     Word16 i;
     552             :     TransientDetector const *pTransientDetector;
     553             :     SubblockEnergies const *pSubblockEnergies;
     554             :     Word16 nDelay;
     555             :     Word16 nRelativeDelay;
     556             :     Word32 const *pSubblockNrgChange;
     557             :     Word16 const *pSubblockNrgChange_exp;
     558             :     Word16 maxEnergyChange;
     559             :     Word16 nTotBlocks;
     560             : 
     561             : 
     562      878643 :     pTransientDetector = &hTranDet->transientDetector;
     563      878643 :     pSubblockEnergies = pTransientDetector->pSubblockEnergies;
     564      878643 :     move16();
     565      878643 :     nDelay = pTransientDetector->nDelay;
     566      878643 :     nRelativeDelay = sub( pSubblockEnergies->nDelay, nDelay );
     567      878643 :     pSubblockNrgChange = NULL;
     568      878643 :     nTotBlocks = add( nCurrentSubblocks, nPrevSubblocks );
     569             : 
     570      878643 :     assert( nTotBlocks > 0 );
     571      878643 :     maxEnergyChange = 0 /*0.0f Q3*/;
     572      878643 :     move16();
     573      878643 :     assert( ( nPrevSubblocks <= nRelativeDelay ) && ( nCurrentSubblocks <= NSUBBLOCKS + nDelay ) );
     574      878643 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange_32fx[nRelativeDelay - nPrevSubblocks];
     575      878643 :     pSubblockNrgChange_exp = &pSubblockEnergies->subblockNrgChange_exp[nRelativeDelay - nPrevSubblocks];
     576             : 
     577      878643 :     IF( s_or( pTransientDetector->bIsAttackPresent, isTCX10 ) ) /* frame is TCX-10 */
     578             :     {
     579       16598 :         Word32 const *pSubblockNrg = &pSubblockEnergies->subblockNrg[sub( nRelativeDelay, nPrevSubblocks )];
     580             :         Word32 nrgMin, nrgMax;
     581       16598 :         Word16 idxMax = 0;
     582       16598 :         move16();
     583             : 
     584       16598 :         nrgMax = L_add( pSubblockNrg[0], 0 );
     585             : 
     586             :         /* find subblock with maximum energy */
     587      211431 :         FOR( i = 1; i < nTotBlocks; i++ )
     588             :         {
     589      194833 :             if ( LT_32( nrgMax, pSubblockNrg[i] ) )
     590             :             {
     591       54084 :                 idxMax = i;
     592       54084 :                 move16();
     593             :             }
     594      194833 :             nrgMax = L_max( nrgMax, pSubblockNrg[i] );
     595             :         }
     596             : 
     597       16598 :         nrgMin = nrgMax;
     598       16598 :         move32();
     599             :         /* find minimum energy after maximum */
     600       85818 :         FOR( i = idxMax + 1; i < nTotBlocks; i++ )
     601             :         {
     602       69220 :             nrgMin = L_min( nrgMin, pSubblockNrg[i] );
     603             :         }
     604             :         /* lower maxEnergyChange if energy doesn't decrease much after energy peak */
     605             :         /* if (nrgMin > 0.375f * nrgMax) */
     606       16598 :         if ( LT_32( Mpy_32_16_1( nrgMax, 12288 /*0.375f Q15*/ ), nrgMin ) )
     607             :         {
     608        6270 :             nTotBlocks = sub( idxMax, 3 );
     609             :         }
     610             :     }
     611             : 
     612    11927120 :     FOR( i = 0; i < nTotBlocks; i++ )
     613             :     {
     614    11048477 :         maxEnergyChange = s_max( maxEnergyChange, extract_l( L_shl_sat( pSubblockNrgChange[i], sub( pSubblockNrgChange_exp[i], 28 ) ) ) ); // Q3
     615             :     }
     616             : 
     617      878643 :     move16();
     618      878643 :     i = maxEnergyChange; // Q3
     619             : 
     620      878643 :     return i;
     621             : }
     622             : 
     623        3100 : void RunTransientDetection_fx( Word16 const *input, Word16 nSamplesAvailable, TransientDetection *pTransientDetection )
     624             : {
     625             :     Word16 filteredInput[L_FRAME48k];
     626        3100 :     SubblockEnergies *pSubblockEnergies = &pTransientDetection->subblockEnergies;
     627        3100 :     TransientDetector *pTransientDetector = &pTransientDetection->transientDetector;
     628             : 
     629        3100 :     assert( ( input != NULL ) && ( pTransientDetection != NULL ) && ( pSubblockEnergies != NULL ) && ( pTransientDetector != NULL ) );
     630             : 
     631        3100 :     HighPassFilter_fx( input, nSamplesAvailable, &pSubblockEnergies->firState1, &pSubblockEnergies->firState2, filteredInput );
     632             : 
     633             :     /* Update subblock energies. */
     634        3100 :     UpdateSubblockEnergies( filteredInput, nSamplesAvailable, pSubblockEnergies );
     635             : 
     636             :     /* Run transient detectors. */
     637        3100 :     RunTransientDetector_fx( pTransientDetector );
     638             : 
     639             :     /* Update the delay buffer. */
     640        3100 :     UpdateDelayBuffer( filteredInput, nSamplesAvailable, &pTransientDetection->delayBuffer );
     641        3100 : }
     642             : 
     643             : 
     644     1170853 : void RunTransientDetection_ivas_fx(
     645             :     Word16 *input_fx,         /* i  : input signal                 Q: q_input   */
     646             :     const Word16 length,      /* i  : frame length                         */
     647             :     TRAN_DET_HANDLE hTranDet, /* i/o: transient detection handle           */
     648             :     Word16 q_input            /*i: stores q for input_fx*/
     649             : )
     650             : {
     651             : 
     652             :     Word16 filteredInput_fx[L_FRAME_MAX];
     653     1170853 :     SubblockEnergies *pSubblockEnergies = &hTranDet->subblockEnergies;
     654     1170853 :     TransientDetector *pTransientDetector = &hTranDet->transientDetector;
     655             : 
     656             :     Word32 e0_fx, e1_fx;
     657     1170853 :     Word16 exp = 0, exp1 = 0, q_old_inp = q_input;
     658     1170853 :     move16();
     659     1170853 :     move16();
     660     1170853 :     move16();
     661             : 
     662     1170853 :     assert( ( input_fx != NULL ) && ( hTranDet != NULL ) && ( pSubblockEnergies != NULL ) && ( pTransientDetector != NULL ) );
     663             : 
     664             :     /* Variable initializations */
     665     1170853 :     Word16 shift = norm_s( pSubblockEnergies->firState1 );
     666     1170853 :     shift = s_min( shift, norm_s( pSubblockEnergies->firState2 ) );
     667             : 
     668     1170853 :     IF( GT_16( sub( q_input, pSubblockEnergies->q_firState ), shift ) )
     669             :     {
     670       71239 :         Scale_sig( input_fx, length, add( sub( pSubblockEnergies->q_firState, q_input ), shift ) ); // q_firState + shift
     671       71239 :         q_input = add( pSubblockEnergies->q_firState, shift );                                      // q_firState + shift
     672       71239 :         pSubblockEnergies->firState1 = shl( pSubblockEnergies->firState1, shift );                  // q_firState + shift
     673       71239 :         move16();
     674       71239 :         pSubblockEnergies->firState2 = shl( pSubblockEnergies->firState2, shift ); // q_firState + shift
     675       71239 :         move16();
     676       71239 :         pSubblockEnergies->q_firState = add( pSubblockEnergies->q_firState, shift ); // q_firState + shift
     677       71239 :         move16();
     678             :     }
     679             :     ELSE
     680             :     {
     681     1099614 :         Word16 norm = norm_arr( input_fx, length );
     682     1099614 :         IF( norm == 0 )
     683             :         {
     684      771957 :             Scale_sig( input_fx, length, -1 );
     685      771957 :             q_input = sub( q_input, 1 );
     686             :         }
     687     1099614 :         pSubblockEnergies->firState1 = shl( pSubblockEnergies->firState1, sub( q_input, pSubblockEnergies->q_firState ) ); // q_input
     688     1099614 :         move16();
     689     1099614 :         pSubblockEnergies->firState2 = shl( pSubblockEnergies->firState2, sub( q_input, pSubblockEnergies->q_firState ) ); // q_input
     690     1099614 :         move16();
     691     1099614 :         pSubblockEnergies->q_firState = q_input;
     692     1099614 :         move16();
     693             :     }
     694             : 
     695     1170853 :     HighPassFilter_fx( input_fx, length, &pSubblockEnergies->firState1, &pSubblockEnergies->firState2, filteredInput_fx ); // q_input
     696             : 
     697     1170853 :     IF( NE_16( q_input, q_old_inp ) )
     698             :     {
     699      843196 :         Scale_sig( input_fx, length, sub( q_old_inp, q_input ) ); // q_old_inp
     700             :     }
     701             : 
     702             :     /* Update subblock energies. */
     703     1170853 :     Scale_sig( filteredInput_fx, length, sub( 0, q_input ) ); // q0
     704     1170853 :     UpdateSubblockEnergies_ivas_fx( filteredInput_fx, length, pSubblockEnergies );
     705             : 
     706             :     /* Run transient detectors. */
     707     1170853 :     RunTransientDetector_fx( pTransientDetector );
     708             : 
     709             :     /* Update the delay buffer. */
     710     1170853 :     UpdateDelayBuffer( filteredInput_fx, length, &hTranDet->delayBuffer );
     711             : 
     712             :     /* compute ramp up flag */
     713     1170853 :     pSubblockEnergies->ramp_up_flag = (UWord16) L_and( L_shl( pSubblockEnergies->ramp_up_flag, 1 ), 0x0003 );
     714     1170853 :     move16();
     715             : 
     716     1170853 :     e0_fx = dotp_fx( filteredInput_fx + /* length / 2 */ shr( length, 1 ), filteredInput_fx + /* length / 2 */ shr( length, 1 ), shr( pSubblockEnergies->pDelayBuffer->nSubblockSize, 1 ) /* pSubblockEnergies->pDelayBuffer->nSubblockSize / 2 */, &exp );
     717     1170853 :     exp = sub( exp, 2 * 0 - 1 ); // Q = 2*0 + (30-exp), E = 31 - (2*0 + 30 - exp) = 1 + exp - 2*0 = exp - (2*0-1)
     718     1170853 :     e0_fx = BASOP_Util_Add_Mant32Exp( MIN_BLOCK_ENERGY_IVAS_FX_Q7 / 2, 31 - Q7, e0_fx, exp, &exp );
     719     1170853 :     e1_fx = BASOP_Util_Add_Mant32Exp( pSubblockEnergies->subblockNrg[pSubblockEnergies->nDelay + 4], 32, L_negate( e0_fx ), exp, &exp1 );
     720     1170853 :     IF( BASOP_Util_Cmp_Mant32Exp( e1_fx, exp1, e0_fx, exp ) > 0 )
     721             :     {
     722      504314 :         pSubblockEnergies->ramp_up_flag = (UWord16) L_or( pSubblockEnergies->ramp_up_flag, 0x0001 );
     723      504314 :         move16();
     724             :     }
     725             : 
     726     1170853 :     return;
     727             : }
     728             : 
     729             : /*-------------------------------------------------------------------*
     730             :  * isLongTermTransient_fx()
     731             :  *
     732             :  *
     733             :  *-------------------------------------------------------------------*/
     734      921877 : static Word16 isLongTermTransient_fx(
     735             :     const Word32 frameTFM,
     736             :     Word32 *lastTFM )
     737             : {
     738             :     Word32 currTFM, f;
     739             : 
     740      921877 :     IF( GT_32( frameTFM, *lastTFM ) )
     741             :     {
     742      473540 :         f = Mpy_32_32( L_sub( frameTFM, *lastTFM ), L_sub( frameTFM, *lastTFM ) );                                                                                 // Q31
     743      473540 :         currTFM = L_add( Mpy_32_32( *lastTFM, L_sub( 2080374784 /* 0.96875f in Q31 */, f ) ), Mpy_32_32( frameTFM, L_add( 67108864 /* 0.03125f in Q31 */, f ) ) ); // Q31
     744             :     }
     745             :     ELSE
     746             :     {
     747      448337 :         currTFM = L_add( Mpy_32_32( *lastTFM, 2080374784 /* 0.96875f in Q31 */ ), Mpy_32_32( frameTFM, 67108864 /* 0.03125f in Q31 */ ) ); // Q31
     748             :     }
     749             : 
     750      921877 :     *lastTFM = L_max( 33554432 /* 0.015625f in Q31 */, currTFM );
     751      921877 :     move32();
     752             : 
     753      921877 :     IF( LT_32( currTFM, 1207959552 /* 0.5625f in Q31 */ ) )
     754             :     {
     755       16875 :         return 1;
     756             :     }
     757      905002 :     return 0;
     758             : }
     759             : 
     760             : 
     761      929692 : void SetTCXModeInfo_ivas_fx(
     762             :     Encoder_State *st,        /* i/o: encoder state structure         */
     763             :     TRAN_DET_HANDLE hTranDet, /* i/o: transient detection handle      */
     764             :     Word16 *tcxModeOverlap    /* o  : window overlap of current frame */
     765             : )
     766             : {
     767      929692 :     TCX_ENC_HANDLE hTcxEnc = st->hTcxEnc;
     768             :     Word16 tmp, exp_diff;
     769             : 
     770      929692 :     test();
     771      929692 :     test();
     772      929692 :     IF( EQ_16( st->codec_mode, MODE2 ) || ( GT_16( st->element_mode, EVS_MONO ) && NE_16( st->core, HQ_CORE ) ) )
     773             :     {
     774      921877 :         assert( hTranDet != NULL );
     775             : 
     776             :         /* determine window sequence (1 long or 2 short windows) */
     777      921877 :         test();
     778      921877 :         IF( st->tcx10Enabled && st->tcx20Enabled )
     779             :         {
     780             :             /* window switching based on transient detector output */
     781      785703 :             test();
     782      785703 :             test();
     783      785703 :             test();
     784      785703 :             test();
     785             :             /* window switching based on transient detector output */
     786      785703 :             IF( ( ( hTranDet->transientDetector.bIsAttackPresent ) || ( EQ_32( BASOP_Util_Cmp_Mant32Exp( Mpy_32_32( st->currEnergyHF_fx, 55063683 /*1.0f/39.0f Q31*/ ), st->currEnergyHF_e_fx, st->prevEnergyHF_fx, 17 ), 1 ) && NE_16( st->element_mode, IVAS_CPE_MDCT ) ) ) &&
     787             :                 ( ( NE_16( st->last_core, ACELP_CORE ) ) && ( NE_16( st->last_core, AMR_WB_CORE ) ) ) )
     788             :             {
     789       14982 :                 hTcxEnc->tcxMode = TCX_10;
     790       14982 :                 move16();
     791             :             }
     792             :             ELSE
     793             :             {
     794      770721 :                 hTcxEnc->tcxMode = TCX_20;
     795      770721 :                 move16();
     796             :             }
     797             :         }
     798             :         ELSE
     799             :         {
     800             :             /* window selection (non-adaptive) based on flags only */
     801      136174 :             IF( st->tcx10Enabled )
     802             :             {
     803           0 :                 hTcxEnc->tcxMode = TCX_10;
     804           0 :                 move16();
     805             :             }
     806      136174 :             ELSE IF( st->tcx20Enabled )
     807             :             {
     808      136174 :                 hTcxEnc->tcxMode = TCX_20;
     809      136174 :                 move16();
     810             :             }
     811             :             ELSE
     812             :             {
     813           0 :                 hTcxEnc->tcxMode = NO_TCX;
     814           0 :                 move16();
     815             :             }
     816             :         }
     817             : 
     818             : #ifdef SUPPORT_FORCE_TCX10_TCX20
     819             : #ifdef DEBUGGING
     820             :         if ( st->force == FORCE_TCX10 )
     821             :         {
     822             :             hTcxEnc->tcxMode = TCX_10;
     823             :         }
     824             :         else if ( st->force == FORCE_TCX20 )
     825             :         {
     826             :             hTcxEnc->tcxMode = TCX_20;
     827             :         }
     828             : #endif
     829             : #endif
     830             : 
     831             :         /* set the left window overlap */
     832      921877 :         test();
     833      921877 :         test();
     834      921877 :         IF( EQ_16( st->last_core, ACELP_CORE ) || EQ_16( st->last_core, AMR_WB_CORE ) )
     835             :         {
     836        9217 :             st->hTcxCfg->tcx_last_overlap_mode = TRANSITION_OVERLAP;
     837        9217 :             move16();
     838             :         }
     839      912660 :         ELSE IF( ( EQ_16( hTcxEnc->tcxMode, TCX_10 ) ) && ( EQ_16( st->hTcxCfg->tcx_curr_overlap_mode, ALDO_WINDOW ) ) )
     840             :         {
     841       11487 :             st->hTcxCfg->tcx_last_overlap_mode = FULL_OVERLAP;
     842       11487 :             move16();
     843             :         }
     844             :         ELSE
     845             :         {
     846      901173 :             st->hTcxCfg->tcx_last_overlap_mode = st->hTcxCfg->tcx_curr_overlap_mode;
     847      901173 :             move16();
     848             :         }
     849             : 
     850             :         /* determine the right window overlap */
     851      921877 :         IF( EQ_16( hTcxEnc->tcxMode, TCX_10 ) )
     852             :         {
     853       14982 :             IF( hTranDet->transientDetector.attackIndex < 0 )
     854             :             {
     855           0 :                 *tcxModeOverlap = HALF_OVERLAP;
     856           0 :                 move16();
     857             :             }
     858             :             ELSE
     859             :             {
     860       14982 :                 *tcxModeOverlap = s_and( hTranDet->transientDetector.attackIndex, 3 );
     861       14982 :                 move16();
     862       14982 :                 if ( EQ_16( *tcxModeOverlap, 1 ) )
     863             :                 {
     864        2504 :                     *tcxModeOverlap = FULL_OVERLAP;
     865        2504 :                     move16();
     866             :                 }
     867             :             }
     868       14982 :             tmp = BASOP_Util_Divide3232_Scale( ONE_IN_Q21, GetTCXAvgTemporalFlatnessMeasure_ivas_fx( (const TransientDetection *) hTranDet, NSUBBLOCKS, 0 ), &exp_diff );
     869       14982 :             tmp = shl_sat( tmp, exp_diff ); // Q15
     870       14982 :             test();
     871       14982 :             IF( isLongTermTransient_fx( L_deposit_h( tmp ), &hTcxEnc->tfm_mem_fx ) && EQ_16( st->element_mode, IVAS_CPE_MDCT ) )
     872             :             {
     873         126 :                 test();
     874         126 :                 IF( NE_16( *tcxModeOverlap, MIN_OVERLAP ) && LT_16( hTcxEnc->tcxltp_norm_corr_past, 18432 /* 0.5625f in Q15 */ ) )
     875             :                 {
     876          51 :                     *tcxModeOverlap = HALF_OVERLAP;
     877          51 :                     move16();
     878             :                 }
     879             :             }
     880             :         }
     881      906895 :         ELSE IF( EQ_16( hTcxEnc->tcxMode, TCX_20 ) )
     882             :         {
     883      906895 :             IF( EQ_16( hTranDet->transientDetector.attackIndex, 7 ) )
     884             :             {
     885        3164 :                 *tcxModeOverlap = HALF_OVERLAP;
     886        3164 :                 move16();
     887             :             }
     888      903731 :             ELSE IF( EQ_16( hTranDet->transientDetector.attackIndex, 6 ) )
     889             :             {
     890        2427 :                 *tcxModeOverlap = MIN_OVERLAP;
     891        2427 :                 move16();
     892             :             }
     893             :             ELSE
     894             :             {
     895      901304 :                 *tcxModeOverlap = ALDO_WINDOW;
     896      901304 :                 move16();
     897             :             }
     898      906895 :             tmp = BASOP_Util_Divide3232_Scale( ONE_IN_Q21, GetTCXAvgTemporalFlatnessMeasure_ivas_fx( (const TransientDetection *) hTranDet, NSUBBLOCKS, 0 ), &exp_diff );
     899      906895 :             tmp = shl_sat( tmp, exp_diff ); // Q15
     900      906895 :             test();
     901      906895 :             IF( isLongTermTransient_fx( L_deposit_h( tmp ), &hTcxEnc->tfm_mem_fx ) && EQ_16( st->element_mode, IVAS_CPE_MDCT ) )
     902             :             {
     903        6818 :                 test();
     904        6818 :                 if ( NE_16( *tcxModeOverlap, MIN_OVERLAP ) && LT_16( hTcxEnc->tcxltp_norm_corr_past, 18432 /* 0.5625f in Q15 */ ) )
     905             :                 {
     906        3702 :                     *tcxModeOverlap = HALF_OVERLAP;
     907        3702 :                     move16();
     908             :                 }
     909             :             }
     910             :         }
     911             :         ELSE
     912             :         {
     913             :             /* NO_TCX */
     914           0 :             *tcxModeOverlap = TRANSITION_OVERLAP;
     915           0 :             move16();
     916           0 :             if ( EQ_16( st->element_mode, IVAS_CPE_MDCT ) )
     917             :             {
     918           0 :                 hTcxEnc->tfm_mem_fx = 1610612736; /* 0.75f in Q31 */
     919           0 :                 move16();
     920             :             }
     921             :         }
     922             : 
     923             :         /* for the ACELP -> TCX transition frames use full right window overlap */
     924      921877 :         test();
     925      921877 :         IF( ( EQ_16( st->hTcxCfg->tcx_last_overlap_mode, TRANSITION_OVERLAP ) ) && ( EQ_16( *tcxModeOverlap, ALDO_WINDOW ) ) )
     926             :         {
     927        9124 :             *tcxModeOverlap = FULL_OVERLAP;
     928        9124 :             move16();
     929             :         }
     930             :     }
     931             : 
     932      929692 :     return;
     933             : }
     934             : 
     935             : 
     936        1310 : void SetTCXModeInfo_fx( Encoder_State *st,
     937             :                         TransientDetection const *pTransientDetection,
     938             :                         Word16 *tcxModeOverlap )
     939             : {
     940        1310 :     TCX_ENC_HANDLE hTcxEnc = st->hTcxEnc;
     941             : 
     942        1310 :     assert( pTransientDetection != NULL );
     943             : 
     944        1310 :     IF( EQ_16( st->codec_mode, MODE2 ) )
     945             :     {
     946             : 
     947             :         /* determine window sequence (1 long or 2 short windows) */
     948             : 
     949        1266 :         test();
     950        1266 :         IF( st->tcx10Enabled != 0 && st->tcx20Enabled != 0 )
     951             :         {
     952             :             /* window switching based on transient detector output */
     953           0 :             test();
     954           0 :             test();
     955           0 :             test();
     956           0 :             IF( ( ( pTransientDetection->transientDetector.bIsAttackPresent != 0 ) || ( GT_32( Mpy_32_16_1( st->currEnergyHF_fx, 840 /*1.0f/39.0f Q15*/ ), st->prevEnergyHF_fx ) ) ) && ( ( NE_16( st->last_core, ACELP_CORE ) ) && ( NE_16( st->last_core, AMR_WB_CORE ) ) ) )
     957             :             {
     958           0 :                 move16();
     959           0 :                 hTcxEnc->tcxMode = TCX_10;
     960             :             }
     961             :             ELSE
     962             :             {
     963           0 :                 move16();
     964           0 :                 hTcxEnc->tcxMode = TCX_20;
     965             :             }
     966             :         }
     967             :         ELSE
     968             :         {
     969             :             /* window selection (non-adaptive) based on flags only */
     970        1266 :             IF( st->tcx10Enabled )
     971             :             {
     972           0 :                 move16();
     973           0 :                 hTcxEnc->tcxMode = TCX_10;
     974             :             }
     975        1266 :             ELSE IF( st->tcx20Enabled )
     976             :             {
     977        1266 :                 move16();
     978        1266 :                 hTcxEnc->tcxMode = TCX_20;
     979             :             }
     980             :             ELSE
     981             :             {
     982           0 :                 move16();
     983           0 :                 hTcxEnc->tcxMode = NO_TCX;
     984             :             }
     985             :         }
     986        1266 :         test();
     987        1266 :         test();
     988        1266 :         IF( st->last_core == ACELP_CORE || st->last_core == AMR_WB_CORE )
     989             :         {
     990         613 :             move16();
     991         613 :             st->hTcxCfg->tcx_last_overlap_mode = TRANSITION_OVERLAP;
     992             :         }
     993         653 :         ELSE IF( ( EQ_16( hTcxEnc->tcxMode, TCX_10 ) ) && ( EQ_16( st->hTcxCfg->tcx_curr_overlap_mode, ALDO_WINDOW ) ) )
     994             :         {
     995           0 :             move16();
     996           0 :             st->hTcxCfg->tcx_last_overlap_mode = FULL_OVERLAP;
     997             :         }
     998             :         ELSE
     999             :         {
    1000         653 :             move16();
    1001         653 :             st->hTcxCfg->tcx_last_overlap_mode = st->hTcxCfg->tcx_curr_overlap_mode;
    1002             :         }
    1003             : 
    1004             :         /* determine window overlaps (0 full, 2 none, or 3 half) */
    1005             : 
    1006        1266 :         IF( EQ_16( hTcxEnc->tcxMode, TCX_10 ) )
    1007             :         {
    1008           0 :             IF( pTransientDetection->transientDetector.attackIndex < 0 )
    1009             :             {
    1010           0 :                 move16();
    1011           0 :                 *tcxModeOverlap = HALF_OVERLAP;
    1012             :             }
    1013             :             ELSE
    1014             :             {
    1015           0 :                 move16();
    1016           0 :                 *tcxModeOverlap = s_and( pTransientDetection->transientDetector.attackIndex, 3 );
    1017           0 :                 if ( EQ_16( *tcxModeOverlap, 1 ) )
    1018             :                 {
    1019           0 :                     move16();
    1020           0 :                     *tcxModeOverlap = FULL_OVERLAP;
    1021             :                 }
    1022             :             }
    1023             :         }
    1024        1266 :         ELSE IF( EQ_16( hTcxEnc->tcxMode, TCX_20 ) )
    1025             :         {
    1026        1266 :             IF( EQ_16( pTransientDetection->transientDetector.attackIndex, 7 ) )
    1027             :             {
    1028          14 :                 move16();
    1029          14 :                 *tcxModeOverlap = HALF_OVERLAP;
    1030             :             }
    1031        1252 :             ELSE IF( EQ_16( pTransientDetection->transientDetector.attackIndex, 6 ) )
    1032             :             {
    1033          18 :                 move16();
    1034          18 :                 *tcxModeOverlap = MIN_OVERLAP;
    1035             :             }
    1036             :             ELSE
    1037             :             {
    1038        1234 :                 move16();
    1039        1234 :                 *tcxModeOverlap = ALDO_WINDOW;
    1040             :             }
    1041             :         }
    1042             :         ELSE /* NO_TCX */
    1043             :         {
    1044           0 :             move16();
    1045           0 :             *tcxModeOverlap = TRANSITION_OVERLAP;
    1046             :         }
    1047        1266 :         test();
    1048        1266 :         if ( ( EQ_16( st->hTcxCfg->tcx_last_overlap_mode, TRANSITION_OVERLAP ) ) && ( EQ_16( *tcxModeOverlap, ALDO_WINDOW ) ) )
    1049             :         {
    1050         597 :             move16();
    1051         597 :             *tcxModeOverlap = FULL_OVERLAP;
    1052             :         }
    1053             : 
    1054             :         /* Sanity check */
    1055        1266 :         assert( *tcxModeOverlap != 1 );
    1056             :     }
    1057        1310 : }
    1058             : 
    1059             : /************************************************/
    1060             : /*                                              */
    1061             : /*              Internal functions              */
    1062             : /*                                              */
    1063             : /************************************************/
    1064             : 
    1065        8186 : static void InitDelayBuffer( Word16 nFrameLength, Word16 nDelay, DelayBuffer *pDelayBuffer )
    1066             : {
    1067        8186 :     Word16 const nMaxBuffSize = sizeof( pDelayBuffer->buffer ) / sizeof( pDelayBuffer->buffer[0] );
    1068             : 
    1069             : 
    1070        8186 :     move16();
    1071        8186 :     move16();
    1072        8186 :     assert( ( nFrameLength > NSUBBLOCKS ) && ( nFrameLength % NSUBBLOCKS == 0 ) && ( nDelay >= 0 ) && ( pDelayBuffer != NULL ) );
    1073        8186 :     pDelayBuffer->nSubblockSize = nFrameLength / NSUBBLOCKS;
    1074        8186 :     assert( pDelayBuffer->nSubblockSize <= nMaxBuffSize );
    1075        8186 :     set16_fx( pDelayBuffer->buffer, 0, nMaxBuffSize );
    1076        8186 :     pDelayBuffer->nDelay = nDelay % pDelayBuffer->nSubblockSize;
    1077        8186 :     assert( pDelayBuffer->nDelay <= nMaxBuffSize );
    1078        8186 : }
    1079             : 
    1080           3 : static void InitSubblockEnergies( Word16 nFrameLength, Word16 nDelay, DelayBuffer *pDelayBuffer, SubblockEnergies *pSubblockEnergies )
    1081             : {
    1082           3 :     Word16 const nMaxBuffSize = sizeof( pSubblockEnergies->subblockNrg ) / sizeof( pSubblockEnergies->subblockNrg[0] );
    1083           3 :     move16();
    1084             :     (void) nFrameLength;
    1085             : 
    1086             : 
    1087           3 :     assert( ( pDelayBuffer != NULL ) && ( pSubblockEnergies != NULL ) && ( pDelayBuffer->nSubblockSize * NSUBBLOCKS == nFrameLength ) && ( pDelayBuffer->nSubblockSize > 0 ) );
    1088             : 
    1089           3 :     set32_fx( pSubblockEnergies->subblockNrg, MIN_BLOCK_ENERGY, nMaxBuffSize );
    1090           3 :     set32_fx( pSubblockEnergies->accSubblockNrg, MIN_BLOCK_ENERGY, nMaxBuffSize + 1 );
    1091           3 :     set16_fx( pSubblockEnergies->subblockNrgChange, 0x7fff, nMaxBuffSize );
    1092           3 :     pSubblockEnergies->nDelay = idiv1616_1( nDelay, pDelayBuffer->nSubblockSize );
    1093           3 :     assert( pSubblockEnergies->nDelay < nMaxBuffSize );
    1094           3 :     pSubblockEnergies->nPartialDelay = nDelay % pDelayBuffer->nSubblockSize;
    1095           3 :     pSubblockEnergies->facAccSubblockNrg = 26624 /*0.8125f Q15*/; /* Energy accumulation factor */
    1096           3 :     pSubblockEnergies->firState1 = 0;
    1097           3 :     pSubblockEnergies->firState2 = 0;
    1098           3 :     move16();
    1099           3 :     move16();
    1100           3 :     move16();
    1101           3 :     move16();
    1102           3 :     move16();
    1103             : 
    1104           3 :     pSubblockEnergies->pDelayBuffer = pDelayBuffer;
    1105           3 :     pDelayBuffer->nDelay = s_max( pDelayBuffer->nDelay, pSubblockEnergies->nPartialDelay );
    1106           3 : }
    1107             : 
    1108        8183 : static void InitSubblockEnergies_ivas_fx( Word16 nFrameLength, Word16 nDelay, DelayBuffer *pDelayBuffer, SubblockEnergies *pSubblockEnergies )
    1109             : {
    1110        8183 :     Word16 const nMaxBuffSize = NSUBBLOCKS + MAX_TD_DELAY;
    1111        8183 :     move16();
    1112             : 
    1113        8183 :     assert( ( pDelayBuffer != NULL ) && ( pSubblockEnergies != NULL ) && ( pDelayBuffer->nSubblockSize * NSUBBLOCKS == nFrameLength ) && ( pDelayBuffer->nSubblockSize > 0 ) );
    1114             : 
    1115        8183 :     set32_fx( pSubblockEnergies->subblockNrg, 54 /* 107.37 in Q(-1) */, nMaxBuffSize );
    1116        8183 :     set32_fx( pSubblockEnergies->accSubblockNrg, 54 /* 107.37 in Q(-1) */, nMaxBuffSize + 1 );
    1117        8183 :     set32_fx( pSubblockEnergies->subblockNrgChange_32fx, ONE_IN_Q15, nMaxBuffSize );
    1118        8183 :     set16_fx( pSubblockEnergies->subblockNrgChange_exp, 16, nMaxBuffSize );
    1119        8183 :     IF( nDelay != 0 )
    1120             :     {
    1121           0 :         pSubblockEnergies->nDelay = idiv1616( nDelay, pDelayBuffer->nSubblockSize );
    1122           0 :         move16();
    1123             :     }
    1124             :     ELSE
    1125             :     {
    1126        8183 :         pSubblockEnergies->nDelay = 0;
    1127        8183 :         move16();
    1128             :     }
    1129        8183 :     assert( pSubblockEnergies->nDelay < nMaxBuffSize );
    1130        8183 :     pSubblockEnergies->nPartialDelay = nDelay % pDelayBuffer->nSubblockSize;
    1131        8183 :     move16();
    1132        8183 :     pSubblockEnergies->facAccSubblockNrg = 26624 /*0.8125f Q15*/; /* Energy accumulation factor */
    1133        8183 :     move16();
    1134        8183 :     pSubblockEnergies->firState1 = 0;
    1135        8183 :     move16();
    1136        8183 :     pSubblockEnergies->firState2 = 0;
    1137        8183 :     move16();
    1138        8183 :     pSubblockEnergies->q_firState = 15;
    1139        8183 :     move16();
    1140             : 
    1141        8183 :     pSubblockEnergies->pDelayBuffer = pDelayBuffer;
    1142        8183 :     pDelayBuffer->nDelay = s_max( pDelayBuffer->nDelay, pSubblockEnergies->nPartialDelay );
    1143        8183 :     move16();
    1144        8183 : }
    1145             : 
    1146             : /** Init transient detector.
    1147             :  * Fills TransientDetector structure with sensible content and enable it.
    1148             :  * @param pSubblockEnergies Subblock energies used in this transient detector.
    1149             :  * @param nDelay Delay FOR this transient detector.
    1150             :  * @param nSubblocksToCheck Number of subblocks to check in this transient detector.
    1151             :  * @param pCheckSubblockForAttack Attack detection function FOR this transient detector.
    1152             :  * @param pSetAttackPosition Function FOR finalizing this transient detector.
    1153             :  * @param attackRatioThreshold Attack ratio threshold with exponent ATTACKTHRESHOLD_E.
    1154             :  * @param pTransientDetector Structure to be initialized.
    1155             :  */
    1156           3 : static void InitTransientDetector_fx( SubblockEnergies *pSubblockEnergies, Word16 nDelay, Word16 nSubblocksToCheck, TCheckSubblocksForAttack_fx pCheckSubblocksForAttack, Word16 attackRatioThreshold, TransientDetector *pTransientDetector )
    1157             : {
    1158             :     Word16 nMaxBuffSize;
    1159             : 
    1160           3 :     move16();
    1161           3 :     nMaxBuffSize = sizeof( pSubblockEnergies->subblockNrg ) / sizeof( pSubblockEnergies->subblockNrg[0] );
    1162             : 
    1163           3 :     assert( ( pSubblockEnergies != NULL ) && ( pSubblockEnergies->pDelayBuffer != NULL ) && ( pTransientDetector != NULL ) && ( pSubblockEnergies->pDelayBuffer->nSubblockSize != 0 ) );
    1164           3 :     pTransientDetector->pSubblockEnergies = pSubblockEnergies;
    1165           3 :     pTransientDetector->nDelay = ( nDelay - pSubblockEnergies->nPartialDelay ) / pSubblockEnergies->pDelayBuffer->nSubblockSize;
    1166           3 :     move16();
    1167           3 :     assert( nDelay == pTransientDetector->nDelay * pSubblockEnergies->pDelayBuffer->nSubblockSize + pSubblockEnergies->nPartialDelay );
    1168           3 :     assert( pTransientDetector->nDelay < nMaxBuffSize );
    1169           3 :     pSubblockEnergies->nDelay = s_max( pSubblockEnergies->nDelay, pTransientDetector->nDelay );
    1170           3 :     assert( nSubblocksToCheck <= NSUBBLOCKS + pTransientDetector->nDelay );
    1171           3 :     pTransientDetector->nSubblocksToCheck = nSubblocksToCheck;
    1172           3 :     move16();
    1173           3 :     pTransientDetector->CheckSubblocksForAttack_fx = pCheckSubblocksForAttack;
    1174           3 :     pTransientDetector->attackRatioThreshold = attackRatioThreshold;
    1175           3 :     move16();
    1176           3 :     pTransientDetector->prev_bIsAttackPresent = FALSE;
    1177           3 :     move16();
    1178           3 :     pTransientDetector->bIsAttackPresent = FALSE;
    1179           3 :     move16();
    1180           3 :     pTransientDetector->attackIndex = -1;
    1181           3 :     move16();
    1182           3 : }
    1183             : 
    1184        8183 : static void InitTransientDetector_ivas_fx( SubblockEnergies *pSubblockEnergies, Word16 nDelay, Word16 nSubblocksToCheck, TCheckSubblocksForAttack_fx pCheckSubblocksForAttack, Word16 attackRatioThreshold, TransientDetector *pTransientDetector )
    1185             : {
    1186        8183 :     const Word16 nMaxBuffSize = NSUBBLOCKS + MAX_TD_DELAY;
    1187        8183 :     move16();
    1188             : 
    1189        8183 :     assert( ( pSubblockEnergies != NULL ) && ( pSubblockEnergies->pDelayBuffer != NULL ) && ( pTransientDetector != NULL ) && ( pSubblockEnergies->pDelayBuffer->nSubblockSize != 0 ) );
    1190        8183 :     pTransientDetector->pSubblockEnergies = pSubblockEnergies;
    1191        8183 :     IF( sub( nDelay, pSubblockEnergies->nPartialDelay ) != 0 )
    1192             :     {
    1193           0 :         pTransientDetector->nDelay = idiv1616( sub( nDelay, pSubblockEnergies->nPartialDelay ), pSubblockEnergies->pDelayBuffer->nSubblockSize );
    1194           0 :         move16();
    1195             :     }
    1196             :     ELSE
    1197             :     {
    1198        8183 :         pTransientDetector->nDelay = 0;
    1199        8183 :         move16();
    1200             :     }
    1201        8183 :     assert( nDelay == pTransientDetector->nDelay * pSubblockEnergies->pDelayBuffer->nSubblockSize + pSubblockEnergies->nPartialDelay );
    1202        8183 :     assert( pTransientDetector->nDelay < nMaxBuffSize );
    1203        8183 :     pSubblockEnergies->nDelay = s_max( pSubblockEnergies->nDelay, pTransientDetector->nDelay );
    1204        8183 :     move16();
    1205        8183 :     assert( nSubblocksToCheck <= NSUBBLOCKS + pTransientDetector->nDelay );
    1206        8183 :     pTransientDetector->nSubblocksToCheck = nSubblocksToCheck;
    1207        8183 :     move16();
    1208        8183 :     pTransientDetector->CheckSubblocksForAttack_fx = pCheckSubblocksForAttack;
    1209        8183 :     pTransientDetector->attackRatioThreshold = attackRatioThreshold;
    1210        8183 :     move16();
    1211        8183 :     pTransientDetector->bIsAttackPresent = FALSE;
    1212        8183 :     move16();
    1213        8183 :     pTransientDetector->prev_bIsAttackPresent = FALSE;
    1214        8183 :     move16();
    1215        8183 :     pTransientDetector->attackIndex = -1;
    1216        8183 :     move16();
    1217        8183 :     pTransientDetector->pSubblockEnergies->ramp_up_flag = 0x0;
    1218        8183 :     move16();
    1219        8183 : }
    1220             : 
    1221             : /* This function should be inlined and WMOPS instrumentation takes that into account, meaning that all references are considered as local variables */
    1222   996604480 : static Word32 InlineFilter( Word16 inValue, Word16 firState1, Word16 firState2 )
    1223             : {
    1224             :     /*  0.375f * inValue - 0.5f * firState1 + 0.125f * firState2 */
    1225             : 
    1226   996604480 :     return L_msu( L_mac( L_mult( firState2, 4096 /*0.125f Q15*/ ), inValue, 12288 /*0.375f Q15*/ ), firState1, 16384 /*0.5f Q15*/ );
    1227             : }
    1228             : 
    1229     1173953 : static void HighPassFilter_fx( Word16 const *input, Word16 length, Word16 *pFirState1, Word16 *pFirState2, Word16 *output )
    1230             : {
    1231             :     Word16 i;
    1232             : 
    1233     1173953 :     output[0] = round_fx( InlineFilter( input[0], *pFirState1, *pFirState2 ) );
    1234     1173953 :     move16();
    1235     1173953 :     output[1] = round_fx( InlineFilter( input[1], input[0], *pFirState1 ) );
    1236     1173953 :     move16();
    1237             : 
    1238   995430527 :     FOR( i = 2; i < length; i++ )
    1239             :     {
    1240   994256574 :         output[i] = round_fx( InlineFilter( input[i], input[i - 1], input[i - 2] ) );
    1241   994256574 :         move16();
    1242             :     }
    1243             : 
    1244             :     /* update filter states: shift time samples through delay line */
    1245     1173953 :     move16();
    1246     1173953 :     move16();
    1247     1173953 :     *pFirState2 = input[length - 2];
    1248     1173953 :     *pFirState1 = input[length - 1];
    1249     1173953 : }
    1250             : 
    1251     1173953 : static void RunTransientDetector_fx( TransientDetector *pTransientDetector )
    1252             : {
    1253     1173953 :     Word16 const attackRatioThreshold = pTransientDetector->attackRatioThreshold;
    1254     1173953 :     move16();
    1255     1173953 :     SubblockEnergies const *pSubblockEnergies = pTransientDetector->pSubblockEnergies;
    1256     1173953 :     Word16 const nDelay = pTransientDetector->nDelay;
    1257     1173953 :     move16();
    1258     1173953 :     Word16 const nRelativeDelay = sub( pSubblockEnergies->nDelay, nDelay );
    1259     1173953 :     move16();
    1260     1173953 :     Word32 const *pSubblockNrg = &pSubblockEnergies->subblockNrg[nRelativeDelay];
    1261     1173953 :     Word32 const *pAccSubblockNrg = &pSubblockEnergies->accSubblockNrg[nRelativeDelay];
    1262             : 
    1263     1173953 :     assert( ( pTransientDetector->CheckSubblocksForAttack_fx != NULL ) );
    1264             : 
    1265             : #define WMC_TOOL_SKIP
    1266     1173953 :     pTransientDetector->CheckSubblocksForAttack_fx( pSubblockNrg, pAccSubblockNrg,
    1267     1173953 :                                                     NSUBBLOCKS + nDelay, nRelativeDelay,
    1268             :                                                     attackRatioThreshold,
    1269             :                                                     &pTransientDetector->bIsAttackPresent, &pTransientDetector->attackIndex );
    1270             : #undef WMC_TOOL_SKIP
    1271     1173953 : }
    1272             : 
    1273     1173953 : static void UpdateDelayBuffer( Word16 const *input, Word16 nSamplesAvailable, DelayBuffer *pDelayBuffer )
    1274             : {
    1275             :     Word16 i;
    1276             :     Word16 nDelay;
    1277             : 
    1278             : 
    1279     1173953 :     move16();
    1280     1173953 :     nDelay = pDelayBuffer->nDelay;
    1281             : 
    1282     1173953 :     assert( ( nDelay >= 0 ) && ( nDelay <= (Word32) sizeof( pDelayBuffer->buffer ) / (Word32) sizeof( pDelayBuffer->buffer[0] ) ) );
    1283     1173953 :     assert( nSamplesAvailable <= NSUBBLOCKS * pDelayBuffer->nSubblockSize );
    1284             :     /* If this is not the last frame */
    1285     1173953 :     IF( EQ_16( nSamplesAvailable, imult1616( NSUBBLOCKS, pDelayBuffer->nSubblockSize ) ) )
    1286             :     {
    1287             :         /* Store the newest samples into the delay buffer */
    1288     1297703 :         FOR( i = 0; i < nDelay; i++ )
    1289             :         {
    1290      123750 :             move16();
    1291      123750 :             pDelayBuffer->buffer[i] = input[i + nSamplesAvailable - nDelay];
    1292             :         }
    1293             :     }
    1294     1173953 : }
    1295             : 
    1296        3100 : static void UpdateSubblockEnergies( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies )
    1297             : {
    1298             :     Word16 i;
    1299             : 
    1300             : 
    1301        3100 :     assert( ( pSubblockEnergies->nDelay >= 0 ) && ( pSubblockEnergies->nDelay + NSUBBLOCKS <= (Word32) sizeof( pSubblockEnergies->subblockNrg ) / (Word32) sizeof( pSubblockEnergies->subblockNrg[0] ) ) );
    1302        3100 :     assert( pSubblockEnergies->nPartialDelay <= pSubblockEnergies->pDelayBuffer->nDelay );
    1303             :     /* At least one block delay is required when subblock energy change is required */
    1304        3100 :     assert( pSubblockEnergies->nDelay >= 1 );
    1305             : 
    1306             :     /* Shift old subblock energies */
    1307       31000 :     FOR( i = 0; i < pSubblockEnergies->nDelay; i++ )
    1308             :     {
    1309       27900 :         move32();
    1310       27900 :         move32();
    1311       27900 :         move16();
    1312       27900 :         pSubblockEnergies->subblockNrg[i] = pSubblockEnergies->subblockNrg[i + NSUBBLOCKS];
    1313       27900 :         pSubblockEnergies->accSubblockNrg[i] = pSubblockEnergies->accSubblockNrg[i + NSUBBLOCKS];
    1314       27900 :         pSubblockEnergies->subblockNrgChange[i] = pSubblockEnergies->subblockNrgChange[i + NSUBBLOCKS];
    1315             :     }
    1316             : 
    1317             :     /* Compute filtered subblock energies for the new samples */
    1318        3100 :     CalculateSubblockEnergies( input, nSamplesAvailable, pSubblockEnergies );
    1319        3100 : }
    1320             : 
    1321     1170853 : static void UpdateSubblockEnergies_ivas_fx( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies )
    1322             : {
    1323             :     Word16 i;
    1324             : 
    1325             : 
    1326     1170853 :     assert( ( pSubblockEnergies->nDelay >= 0 ) && ( pSubblockEnergies->nDelay + NSUBBLOCKS <= (Word32) sizeof( pSubblockEnergies->subblockNrg ) / (Word32) sizeof( pSubblockEnergies->subblockNrg[0] ) ) );
    1327     1170853 :     assert( pSubblockEnergies->nPartialDelay <= pSubblockEnergies->pDelayBuffer->nDelay );
    1328             :     /* At least one block delay is required when subblock energy change is required */
    1329     1170853 :     assert( pSubblockEnergies->nDelay >= 1 );
    1330             : 
    1331             :     /* Shift old subblock energies */
    1332    16391942 :     FOR( i = 0; i < pSubblockEnergies->nDelay; i++ )
    1333             :     {
    1334    15221089 :         move32();
    1335    15221089 :         move32();
    1336    15221089 :         move32();
    1337    15221089 :         move16();
    1338    15221089 :         pSubblockEnergies->subblockNrg[i] = pSubblockEnergies->subblockNrg[i + NSUBBLOCKS];
    1339    15221089 :         pSubblockEnergies->accSubblockNrg[i] = pSubblockEnergies->accSubblockNrg[i + NSUBBLOCKS];
    1340    15221089 :         pSubblockEnergies->subblockNrgChange_32fx[i] = pSubblockEnergies->subblockNrgChange_32fx[i + NSUBBLOCKS];
    1341    15221089 :         pSubblockEnergies->subblockNrgChange_exp[i] = pSubblockEnergies->subblockNrgChange_exp[i + NSUBBLOCKS];
    1342             :     }
    1343             : 
    1344             :     /* Compute filtered subblock energies for the new samples */
    1345     1170853 :     CalculateSubblockEnergies_ivas_fx( input, nSamplesAvailable, pSubblockEnergies );
    1346     1170853 : }
    1347             : 
    1348             : /* This function should be inlined and WMOPS instrumentation takes that into account, meaning that all references are considered as local variables */
    1349     9391624 : static void UpdatedAndStoreAccWindowNrg( Word32 newWindowNrgF, Word32 *pAccSubblockNrg, Word16 facAccSubblockNrg, Word32 *pOutAccWindowNrgF )
    1350             : {
    1351             :     /* Store the accumulated energy */
    1352     9391624 :     move32();
    1353     9391624 :     *pOutAccWindowNrgF = *pAccSubblockNrg;
    1354             :     /* Update the accumulated energy: maximum of the current and the accumulated energy */
    1355     9391624 :     *pAccSubblockNrg = Mpy_32_16_1( *pAccSubblockNrg, facAccSubblockNrg );
    1356             : 
    1357     9391624 :     if ( GT_32( newWindowNrgF, *pAccSubblockNrg ) )
    1358             :     {
    1359     5804783 :         move32();
    1360     5804783 :         *pAccSubblockNrg = newWindowNrgF;
    1361             :     }
    1362     9391624 : }
    1363             : 
    1364        3100 : static void CalculateSubblockEnergies( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies )
    1365             : {
    1366             :     DelayBuffer *pDelayBuffer;
    1367             :     Word16 nSubblockSize;
    1368             :     Word16 nDelay;
    1369             :     Word16 nPartialDelay;
    1370             :     Word16 *delayBuffer;
    1371             :     Word16 facAccSubblockNrg;
    1372             :     Word32 *pSubblockNrg;
    1373             :     Word32 *pAccSubblockNrg;
    1374             :     Word16 *pSubblockNrgChange;
    1375             :     Word32 *pAccSubblockTmp;
    1376             :     Word16 nWindows;
    1377             :     Word16 w, k, k2, tmp;
    1378             :     Word16 firState1, firState2;
    1379             :     Word32 w0, w1;
    1380             :     Word32 accu;
    1381             : 
    1382        3100 :     move16();
    1383        3100 :     pDelayBuffer = pSubblockEnergies->pDelayBuffer;
    1384        3100 :     facAccSubblockNrg = pSubblockEnergies->facAccSubblockNrg;
    1385             : 
    1386        3100 :     move16();
    1387        3100 :     move16();
    1388        3100 :     move16();
    1389        3100 :     nSubblockSize = pDelayBuffer->nSubblockSize;
    1390        3100 :     nDelay = pSubblockEnergies->nDelay;
    1391        3100 :     nPartialDelay = pSubblockEnergies->nPartialDelay;
    1392             : 
    1393        3100 :     delayBuffer = &pDelayBuffer->buffer[sub( pDelayBuffer->nDelay, nPartialDelay )];
    1394        3100 :     pSubblockNrg = &pSubblockEnergies->subblockNrg[nDelay];
    1395        3100 :     pAccSubblockNrg = &pSubblockEnergies->accSubblockNrg[nDelay];
    1396        3100 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange[nDelay];
    1397             : 
    1398        3100 :     move16();
    1399        3100 :     move16();
    1400             :     /* nWindows = (nSamplesAvailable + nPartialDelay) / nSubblockSize */
    1401        3100 :     nWindows = shr( div_s( add( nSamplesAvailable, nPartialDelay ), shl( nSubblockSize, 7 ) ), 8 );
    1402        3100 :     firState1 = pSubblockEnergies->firState1;
    1403        3100 :     firState2 = pSubblockEnergies->firState2;
    1404        3100 :     pAccSubblockTmp = &pAccSubblockNrg[nWindows];
    1405             : 
    1406        3100 :     IF( nWindows > 0 )
    1407             :     {
    1408             :         /* Process left over samples from the previous frame. */
    1409        3100 :         accu = L_add( MIN_BLOCK_ENERGY, 0 );
    1410             :         assert( ( SUBBLOCK_NRG_E & 1 ) == 0 );
    1411      126850 :         FOR( k = 0; k < nPartialDelay; k++ )
    1412             :         {
    1413      123750 :             tmp = shr( delayBuffer[k], SUBBLOCK_NRG_E / 2 );
    1414      123750 :             accu = L_mac0( accu, tmp, tmp );
    1415             :         }
    1416             : 
    1417             :         /* Process new samples in the 0. subblock. */
    1418        3100 :         w = sub( nSubblockSize, nPartialDelay );
    1419             :         assert( ( SUBBLOCK_NRG_E & 1 ) == 0 );
    1420      209350 :         FOR( k = 0; k < w; k++ )
    1421             :         {
    1422      206250 :             tmp = shr( input[k], SUBBLOCK_NRG_E / 2 );
    1423      206250 :             accu = L_mac0_sat( accu, tmp, tmp );
    1424             :         }
    1425             : 
    1426        3100 :         move32();
    1427        3100 :         pSubblockNrg[0] = accu;
    1428             :         /* Set accumulated subblock energy at this point. */
    1429        3100 :         UpdatedAndStoreAccWindowNrg( pSubblockNrg[0], pAccSubblockTmp, facAccSubblockNrg, &pAccSubblockNrg[0] );
    1430             : 
    1431       24800 :         FOR( w = 1; w < nWindows; w++ )
    1432             :         {
    1433       21700 :             accu = L_add( MIN_BLOCK_ENERGY, 0 );
    1434             :             /* Process new samples in the w. subblock. */
    1435       21700 :             k2 = add( k, nSubblockSize );
    1436             :             assert( ( SUBBLOCK_NRG_E & 1 ) == 0 );
    1437     2331700 :             FOR( ; k < k2; k++ )
    1438             :             {
    1439     2310000 :                 tmp = shr( input[k], SUBBLOCK_NRG_E / 2 );
    1440     2310000 :                 accu = L_mac0_sat( accu, tmp, tmp );
    1441             :             }
    1442       21700 :             move32();
    1443       21700 :             pSubblockNrg[w] = accu;
    1444             :             /* Set accumulated subblock energy at this point. */
    1445       21700 :             UpdatedAndStoreAccWindowNrg( pSubblockNrg[w], pAccSubblockTmp, facAccSubblockNrg, &pAccSubblockNrg[w] );
    1446             :         }
    1447             : 
    1448             :         /* Calculate energy change for each block. */
    1449       27900 :         FOR( w = 0; w < nWindows; w++ )
    1450             :         {
    1451       24800 :             w0 = L_add( pSubblockNrg[w], 0 );
    1452       24800 :             w1 = L_add( pSubblockNrg[sub( w, 1 )], 0 );
    1453             : 
    1454       24800 :             IF( GT_32( w0, w1 ) )
    1455             :             {
    1456       11470 :                 k2 = BASOP_Util_Divide3232_uu_1616_Scale( w0, w1, &k );
    1457             :             }
    1458             :             ELSE
    1459             :             {
    1460       13330 :                 k2 = BASOP_Util_Divide3232_uu_1616_Scale( w1, w0, &k );
    1461             :             }
    1462       24800 :             move16();
    1463       24800 :             pSubblockNrgChange[w] = MAX_16;
    1464       24800 :             IF( LT_16( k, SUBBLOCK_NRG_CHANGE_E ) )
    1465             :             {
    1466       24779 :                 move16();
    1467       24779 :                 pSubblockNrgChange[w] = shr( k2, sub( SUBBLOCK_NRG_CHANGE_E, k ) );
    1468             :             }
    1469             :         }
    1470             :     }
    1471             : 
    1472        3100 :     move16();
    1473        3100 :     move16();
    1474        3100 :     pSubblockEnergies->firState1 = firState1;
    1475        3100 :     pSubblockEnergies->firState2 = firState2;
    1476        3100 : }
    1477             : 
    1478     1170853 : static void CalculateSubblockEnergies_ivas_fx( Word16 const *input, Word16 nSamplesAvailable, SubblockEnergies *pSubblockEnergies )
    1479             : {
    1480             :     DelayBuffer *pDelayBuffer;
    1481             :     Word16 nSubblockSize;
    1482             :     Word16 nDelay;
    1483             :     Word16 nPartialDelay;
    1484             :     Word16 *delayBuffer;
    1485             :     Word16 facAccSubblockNrg;
    1486             :     Word32 *pSubblockNrg;
    1487             :     Word32 *pAccSubblockNrg;
    1488             :     Word32 *pSubblockNrgChange;
    1489             :     Word16 *pSubblockNrgChange_exp;
    1490             :     Word32 *pAccSubblockTmp;
    1491             :     Word16 nWindows;
    1492             :     Word16 w, k, k2;
    1493             :     Word32 w0, w1;
    1494             :     Word64 accu;
    1495             : 
    1496     1170853 :     move16();
    1497     1170853 :     pDelayBuffer = pSubblockEnergies->pDelayBuffer;
    1498     1170853 :     facAccSubblockNrg = pSubblockEnergies->facAccSubblockNrg;
    1499             : 
    1500     1170853 :     move16();
    1501     1170853 :     move16();
    1502     1170853 :     move16();
    1503     1170853 :     nSubblockSize = pDelayBuffer->nSubblockSize;
    1504     1170853 :     nDelay = pSubblockEnergies->nDelay;
    1505     1170853 :     nPartialDelay = pSubblockEnergies->nPartialDelay;
    1506             : 
    1507     1170853 :     delayBuffer = &pDelayBuffer->buffer[sub( pDelayBuffer->nDelay, nPartialDelay )];
    1508     1170853 :     pSubblockNrg = &pSubblockEnergies->subblockNrg[nDelay];
    1509     1170853 :     pAccSubblockNrg = &pSubblockEnergies->accSubblockNrg[nDelay];
    1510     1170853 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange_32fx[nDelay];
    1511     1170853 :     pSubblockNrgChange_exp = &pSubblockEnergies->subblockNrgChange_exp[nDelay];
    1512             : 
    1513             :     /* nWindows = (nSamplesAvailable + nPartialDelay) / nSubblockSize */
    1514     1170853 :     nWindows = shr( div_s( add( nSamplesAvailable, nPartialDelay ), shl( nSubblockSize, 7 ) ), 8 );
    1515     1170853 :     pAccSubblockTmp = &pAccSubblockNrg[nWindows];
    1516             : 
    1517     1170853 :     IF( nWindows > 0 )
    1518             :     {
    1519             :         /* Process left over samples from the previous frame. */
    1520     1170853 :         accu = 215; // 107.37f in Q1
    1521     1170853 :         move64();
    1522     1170853 :         FOR( k = 0; k < nPartialDelay; k++ )
    1523             :         {
    1524           0 :             accu = W_mac_16_16( accu, delayBuffer[k], delayBuffer[k] ); // Q1
    1525             :         }
    1526             : 
    1527             :         /* Process new samples in the 0. subblock. */
    1528   125416413 :         FOR( k = 0; k < ( nSubblockSize - nPartialDelay ); k++ )
    1529             :         {
    1530   124245560 :             accu = W_mac_16_16( accu, input[k], input[k] ); // Q1
    1531             :         }
    1532             : 
    1533     1170853 :         pSubblockNrg[0] = W_shl_sat_l( accu, -2 ); // Q(-1)
    1534     1170853 :         move32();
    1535             :         /* Set accumulated subblock energy at this point. */
    1536     1170853 :         UpdatedAndStoreAccWindowNrg( pSubblockNrg[0], pAccSubblockTmp, facAccSubblockNrg, &pAccSubblockNrg[0] );
    1537             : 
    1538     9366824 :         FOR( w = 1; w < nWindows; w++ )
    1539             :         {
    1540     8195971 :             accu = 215; // 107.37f in Q1
    1541     8195971 :             move64();
    1542             :             /* Process new samples in the w. subblock. */
    1543     8195971 :             k2 = add( k, nSubblockSize );
    1544   877914891 :             FOR( ; k < k2; k++ )
    1545             :             {
    1546   869718920 :                 accu = W_mac_16_16( accu, input[k], input[k] ); // Q1
    1547             :             }
    1548     8195971 :             pSubblockNrg[w] = W_shl_sat_l( accu, -2 ); // Q(-1)
    1549     8195971 :             move32();
    1550             :             /* Set accumulated subblock energy at this point. */
    1551     8195971 :             UpdatedAndStoreAccWindowNrg( pSubblockNrg[w], pAccSubblockTmp, facAccSubblockNrg, &pAccSubblockNrg[w] );
    1552             :         }
    1553             : 
    1554             :         /* Calculate energy change for each block. */
    1555    10537677 :         FOR( w = 0; w < nWindows; w++ )
    1556             :         {
    1557     9366824 :             w0 = L_add( pSubblockNrg[w], 0 );
    1558     9366824 :             w1 = L_add( pSubblockNrg[sub( w, 1 )], 0 );
    1559             : 
    1560     9366824 :             IF( GT_32( w0, w1 ) )
    1561             :             {
    1562     4183602 :                 pSubblockNrgChange[w] = BASOP_Util_Divide3232_Scale_newton( w0, w1, &k );
    1563     4183602 :                 pSubblockNrgChange_exp[w] = k;
    1564             :             }
    1565             :             ELSE
    1566             :             {
    1567     5183222 :                 pSubblockNrgChange[w] = BASOP_Util_Divide3232_Scale_newton( w1, w0, &k );
    1568     5183222 :                 pSubblockNrgChange_exp[w] = k;
    1569             :             }
    1570     9366824 :             move32();
    1571     9366824 :             move16();
    1572             :         }
    1573             :     }
    1574     1170853 : }
    1575             : 
    1576             : /*-------------------------------------------------------------------*
    1577             :  * transient_analysis()
    1578             :  *
    1579             :  *
    1580             :  *-------------------------------------------------------------------*/
    1581             : 
    1582             : /*! r: preliminary flag to force ACELP */
    1583       10390 : Word16 transient_analysis_ivas_fx(
    1584             :     TRAN_DET_HANDLE hTranDet,  /* i  : handle transient detection       */
    1585             :     const Word16 cor_map_LT[], /* i  : LT correlation map  Q_cor_map */
    1586             :     Word16 Q_cor_map,
    1587             :     const Word16 multi_harm_limit, /* i  : multi harmonic threshold Q_multi_harm_limit */
    1588             :     Word16 Q_multi_harm_limit )
    1589             : {
    1590             :     const Word32 *pSubblockNrg;
    1591             :     Word32 accSubblockNrgRev_fx[NSUBBLOCKS];
    1592             :     Word32 *pTmp_fx;
    1593             :     Word16 offset;
    1594             :     Word16 i;
    1595             :     Word16 thr_fwd_fx;
    1596             :     Word16 thr_rev_fx;
    1597       10390 :     const Word16 nRelativeDelay = sub( hTranDet->subblockEnergies.nDelay, hTranDet->transientDetector.nDelay );
    1598             :     Word16 prel_force_td;
    1599       10390 :     Word32 cor_map_LT_sum = 0;
    1600       10390 :     move32();
    1601             : 
    1602             :     /* Set pointer to the reverse accumulator buffer */
    1603       10390 :     pTmp_fx = &accSubblockNrgRev_fx[NSUBBLOCKS - 1];
    1604       10390 :     offset = sub( nRelativeDelay, 4 );
    1605       10390 :     prel_force_td = FALSE;
    1606       10390 :     move16();
    1607             : 
    1608       10390 :     cor_map_LT_sum = sum16_32_fx( cor_map_LT, L_FFT / 2 );
    1609             : 
    1610       10390 :     thr_fwd_fx = THR_NORM_HIGH_FX; // THR_NORM_HIGH_FX is in Q11 Format
    1611       10390 :     move16();
    1612       10390 :     Word16 shift = 0;
    1613       10390 :     move16();
    1614             :     /* Q_cor_map: cor_map_LT is in Q_cor_map format */
    1615             :     /* Q_multi_harm_limit: multi_harm_limit is in Q_multi_harm_limit format */
    1616       10390 :     IF( GT_16( Q_cor_map, Q_multi_harm_limit ) )
    1617             :     {
    1618       10390 :         shift = sub( Q_cor_map, Q_multi_harm_limit );
    1619             : 
    1620       10390 :         if ( GT_32( L_shr( cor_map_LT_sum, shift ), L_deposit_l( mult( multi_harm_limit, 26214 ) ) ) ) // 26214 is 0.8 in Q15 format
    1621             :         {
    1622        2921 :             thr_fwd_fx = THR_HIGH_FX; // THR_HIGH_FX is in Q11 Format
    1623        2921 :             move16();
    1624             :         }
    1625             :     }
    1626             :     ELSE
    1627             :     {
    1628           0 :         shift = sub( Q_multi_harm_limit, Q_cor_map );
    1629             : 
    1630           0 :         if ( GT_32( cor_map_LT_sum, L_deposit_l( shr( mult( multi_harm_limit, 26214 ), shift ) ) ) ) // 26214 is 0.8 in Q15 format
    1631             :         {
    1632           0 :             thr_fwd_fx = THR_HIGH_FX; // THR_HIGH_FX is in Q11 Format
    1633           0 :             move16();
    1634             :         }
    1635             :     }
    1636             : 
    1637       10390 :     thr_rev_fx = THR_LOW_FX; // THR_LOW_FX is in Q11 Format
    1638       10390 :     move16();
    1639       10390 :     IF( GT_16( Q_cor_map, Q_multi_harm_limit ) )
    1640             :     {
    1641       10390 :         shift = sub( Q_cor_map, Q_multi_harm_limit );
    1642             : 
    1643       10390 :         if ( GT_32( L_shr( cor_map_LT_sum, shift ), L_deposit_l( mult( multi_harm_limit, 19661 ) ) ) ) // 19661 is 0.6 in Q15 format
    1644             :         {
    1645        9307 :             thr_rev_fx = THR_NORM_LOW_FX; // THR_NORM_LOW_FX is in Q11 Format
    1646        9307 :             move16();
    1647             :         }
    1648             :     }
    1649             :     ELSE
    1650             :     {
    1651           0 :         shift = sub( Q_multi_harm_limit, Q_cor_map );
    1652             : 
    1653           0 :         if ( GT_32( cor_map_LT_sum, L_deposit_l( shr( mult( multi_harm_limit, 19661 ), shift ) ) ) ) // 19661 is 0.6 in Q15 format
    1654             :         {
    1655           0 :             thr_rev_fx = THR_NORM_LOW_FX; // THR_NORM_LOW_FX is in Q11 Format
    1656           0 :             move16();
    1657             :         }
    1658             :     }
    1659             : 
    1660             :     /*  Forward attack analysis */
    1661      103900 :     FOR( i = -2; i < 7; i++ )
    1662             :     {
    1663       93510 :         IF( BASOP_Util_Cmp_Mant32Exp( hTranDet->subblockEnergies.subblockNrg[nRelativeDelay + i], 32, Mpy_32_16_1( hTranDet->subblockEnergies.accSubblockNrg[nRelativeDelay + i], thr_fwd_fx ), ( 32 + 4 ) ) > 0 )
    1664             :         {
    1665         432 :             prel_force_td = s_or( prel_force_td, 0x0001 );
    1666             :         }
    1667             :     }
    1668             : 
    1669       10390 :     test();
    1670       10390 :     IF( prel_force_td == 0 && EQ_16( hTranDet->transientDetector.prev_bIsAttackPresent, 1 ) )
    1671             :     {
    1672             :         /* Release analysis */
    1673         371 :         pSubblockNrg = hTranDet->transientDetector.pSubblockEnergies->subblockNrg;
    1674             : 
    1675         371 :         set32_fx( accSubblockNrgRev_fx, 0, NSUBBLOCKS );
    1676             : 
    1677        3339 :         FOR( i = NSUBBLOCKS - 1; i > -1; i-- )
    1678             :         {
    1679             : 
    1680        2968 :             IF( EQ_16( i, NSUBBLOCKS - 1 ) )
    1681             :             {
    1682         371 :                 accSubblockNrgRev_fx[i] = pSubblockNrg[i + offset];
    1683         371 :                 move32();
    1684             :             }
    1685             :             ELSE
    1686             :             {
    1687        2597 :                 accSubblockNrgRev_fx[i] = *pTmp_fx;
    1688        2597 :                 *pTmp_fx = Mpy_32_16_1( *pTmp_fx, hTranDet->transientDetector.pSubblockEnergies->facAccSubblockNrg );
    1689        2597 :                 move32();
    1690        2597 :                 if ( GT_32( pSubblockNrg[i + offset], *pTmp_fx ) )
    1691             :                 {
    1692        1668 :                     *pTmp_fx = pSubblockNrg[i + offset];
    1693        1668 :                     move32();
    1694             :                 }
    1695             :             }
    1696             :         }
    1697             : 
    1698             :         /* -3 check */
    1699         371 :         test();
    1700         371 :         IF( BASOP_Util_Cmp_Mant32Exp( pSubblockNrg[1 + offset], 32, Mpy_32_16_1( accSubblockNrgRev_fx[1], thr_rev_fx ), ( 32 + 4 ) ) > 0 )
    1701             :         {
    1702           1 :             prel_force_td = s_or( prel_force_td, 0x0002 );
    1703           1 :             move16();
    1704             :         }
    1705             : 
    1706             :         /* -4 check */
    1707         371 :         test();
    1708         371 :         IF( prel_force_td == 0 && BASOP_Util_Cmp_Mant32Exp( pSubblockNrg[offset], 32, Mpy_32_16_1( accSubblockNrgRev_fx[0], thr_rev_fx ), ( 32 + 4 ) ) > 0 )
    1709             :         {
    1710             : 
    1711          19 :             IF( BASOP_Util_Cmp_Mant32Exp( pSubblockNrg[offset], 32, Mpy_32_16_1( accSubblockNrgRev_fx[0], add( thr_rev_fx, THR_LOW_STEP_FX ) ), ( 32 + 4 ) ) > 0 )
    1712             :             {
    1713          17 :                 prel_force_td = s_or( prel_force_td, 0x0004 );
    1714             :             }
    1715           2 :             ELSE IF( ( s_and( hTranDet->subblockEnergies.ramp_up_flag, 0x0002 ) ) != 0 )
    1716             :             {
    1717           2 :                 prel_force_td = s_or( prel_force_td, 0x0008 );
    1718             :             }
    1719             :         }
    1720             :     }
    1721             : 
    1722             : 
    1723       10390 :     return prel_force_td != 0;
    1724             : }
    1725             : 
    1726             : /*-------------------------------------------------------------------*
    1727             :  * set_transient_stereo()
    1728             :  *
    1729             :  *
    1730             :  *-------------------------------------------------------------------*/
    1731       63470 : void set_transient_stereo_fx(
    1732             :     CPE_ENC_HANDLE hCPE,  /* i  : CPE structure               */
    1733             :     Word32 currFlatness[] /* i/o: current flatness            */
    1734             : )
    1735             : {
    1736             :     Word16 n, attackIsPresent;
    1737             :     Word32 currFlatnessMax;
    1738             :     Encoder_State **sts;
    1739             : 
    1740       63470 :     sts = hCPE->hCoreCoder;
    1741             : 
    1742             :     /* for DFT/TD based stereo ,map avg. flatness to individual stereo channels (M/S or X/Y) */
    1743       63470 :     maximum_32_fx( currFlatness, CPE_CHANNELS, &currFlatnessMax );
    1744       63470 :     attackIsPresent = 0;
    1745       63470 :     move16();
    1746             : 
    1747      190410 :     FOR( n = 0; n < CPE_CHANNELS; n++ )
    1748             :     {
    1749      126940 :         attackIsPresent = s_max( attackIsPresent, sts[n]->hTranDet->transientDetector.bIsAttackPresent );
    1750             :     }
    1751             : 
    1752       63470 :     set32_fx( currFlatness, currFlatnessMax, CPE_CHANNELS );
    1753             : 
    1754      190410 :     FOR( n = 0; n < CPE_CHANNELS; n++ )
    1755             :     {
    1756      126940 :         sts[n]->hTranDet->transientDetector.bIsAttackPresent = attackIsPresent;
    1757      126940 :         move16();
    1758             :     }
    1759             : 
    1760       63470 :     IF( hCPE->hStereoDft != NULL )
    1761             :     {
    1762       59643 :         IF( hCPE->hStereoDft->attackPresent )
    1763             :         {
    1764        1842 :             hCPE->hStereoDft->wasTransient = 1;
    1765        1842 :             move16();
    1766             :         }
    1767       57801 :         ELSE IF( hCPE->hStereoDft->wasTransient )
    1768             :         {
    1769        1606 :             hCPE->hStereoDft->wasTransient = 0;
    1770        1606 :             move16();
    1771             :         }
    1772             : 
    1773       59643 :         hCPE->hStereoDft->attackPresent = attackIsPresent;
    1774       59643 :         move16();
    1775             : 
    1776       59643 :         hCPE->hStereoDft->hItd->currFlatness_fx = 0;
    1777       59643 :         move16();
    1778      178929 :         FOR( n = 0; n < CPE_CHANNELS; n++ )
    1779             :         {
    1780      119286 :             hCPE->hStereoDft->hItd->currFlatness_fx = L_max( hCPE->hStereoDft->hItd->currFlatness_fx, currFlatness[n] );
    1781      119286 :             move32();
    1782             :         }
    1783             :     }
    1784             : 
    1785       63470 :     IF( hCPE->hStereoMdct != NULL )
    1786             :     {
    1787           0 :         hCPE->hStereoMdct->hItd->currFlatness_fx = 0;
    1788           0 :         move16();
    1789           0 :         FOR( n = 0; n < CPE_CHANNELS; n++ )
    1790             :         {
    1791           0 :             hCPE->hStereoMdct->hItd->currFlatness_fx = L_max( hCPE->hStereoMdct->hItd->currFlatness_fx, currFlatness[n] );
    1792           0 :             move32();
    1793             :         }
    1794             :     }
    1795             : 
    1796       63470 :     return;
    1797             : }

Generated by: LCOV version 1.14