LCOV - code coverage report
Current view: top level - lib_enc - transient_detection_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main @ 43b7b28dcb1471ff5d355252c4b8f37ee7ecc268 Lines: 750 806 93.1 %
Date: 2025-11-02 02:02:47 Functions: 30 30 100.0 %

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

Generated by: LCOV version 1.14