LCOV - code coverage report
Current view: top level - lib_enc - transient_detection.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 306 315 97.1 %
Date: 2025-05-23 08:37:30 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : /*====================================================================================
      34             :     EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0
      35             :   ====================================================================================*/
      36             : 
      37             : #include <stdint.h>
      38             : #include "options.h"
      39             : #ifdef DEBUGGING
      40             : #include "debug.h"
      41             : #endif
      42             : #include "stat_enc.h"
      43             : #include "cnst.h"
      44             : #include "prot.h"
      45             : #include "ivas_prot.h"
      46             : #include <assert.h>
      47             : #include "wmc_auto.h"
      48             : 
      49             : 
      50             : /*---------------------------------------------------------------*
      51             :  * Local constants
      52             :  *---------------------------------------------------------------*/
      53             : 
      54             : #define MIN_BLOCK_ENERGY 107.37f
      55             : 
      56             : #define THR_HIGH      8.5f
      57             : #define THR_NORM_HIGH 8.0f
      58             : #define THR_NORM_LOW  4.5f
      59             : #define THR_LOW       4.25f
      60             : #define THR_LOW_STEP  1.0f
      61             : 
      62             : 
      63             : /*---------------------------------------------------------------*
      64             :  * Local function prototypes
      65             :  *---------------------------------------------------------------*/
      66             : 
      67             : static void InitDelayBuffer( const int16_t nFrameLength, const int16_t nDelay, DelayBuffer *pDelayBuffer );
      68             : static void InitSubblockEnergies( const int16_t nFrameLength, const int16_t nDelay, DelayBuffer *pDelayBuffer, SubblockEnergies *pSubblockEnergies );
      69             : static void InitTransientDetector( SubblockEnergies *pSubblockEnergies, const int16_t nDelay, const int16_t nSubblocksToCheck, TCheckSubblocksForAttack pCheckSubblocksForAttack, const float attackRatioThreshold, TransientDetector *pTransientDetector );
      70             : static void UpdateDelayBuffer( const float *inputconst, const int16_t nSamplesAvailable, DelayBuffer *pDelayBuffer );
      71             : static void HighPassFilter( const float *input, const int16_t length, float *pFirState1, float *pFirState2, float *output );
      72             : static void UpdateSubblockEnergies( const float *input, const int16_t nSamplesAvailable, SubblockEnergies *pSubblockEnergies );
      73             : static void CalculateSubblockEnergies( const float *input, const int16_t nSamplesAvailable, SubblockEnergies *pSubblockEnergies );
      74             : static void RunTransientDetector( TransientDetector *pTransientDetector );
      75             : static void GetAttackForTCXDecision( const float *pSubblockNrg, const float *pAccSubblockNrg, const int16_t nSubblocks, const int16_t nPastSubblocks, const float attackRatioThreshold, int16_t *pbIsAttackPresent, int16_t *pAttackIndex );
      76             : 
      77             : 
      78             : /*-------------------------------------------------------------------*
      79             :  * InitTransientDetection()
      80             :  *
      81             :  *
      82             :  *-------------------------------------------------------------------*/
      83             : 
      84        8767 : void InitTransientDetection(
      85             :     const int16_t nFrameLength,
      86             :     const int16_t nTCXDelay,
      87             :     TRAN_DET_HANDLE hTranDet,
      88             :     const int16_t ext_mem_flag )
      89             : {
      90             :     /* Init the delay buffer. */
      91        8767 :     InitDelayBuffer( nFrameLength, nTCXDelay, &hTranDet->delayBuffer );
      92             : 
      93             :     /* Init a subblock energies buffer used for the TCX Short/Long decision. */
      94        8767 :     InitSubblockEnergies( nFrameLength, nTCXDelay, &hTranDet->delayBuffer, &hTranDet->subblockEnergies );
      95             : 
      96             :     /* Init the TCX Short/Long transient detector. */
      97        8767 :     InitTransientDetector( &hTranDet->subblockEnergies, nTCXDelay, NSUBBLOCKS, GetAttackForTCXDecision, 8.5f, &hTranDet->transientDetector );
      98             : 
      99             :     /* We need two past subblocks for the TCX TD and NSUBBLOCKS+1 for the temporal flatness measure for the TCX LTP. */
     100        8767 :     if ( ext_mem_flag )
     101             :     {
     102        8764 :         hTranDet->transientDetector.pSubblockEnergies->nDelay += ( NSUBBLOCKS_SHIFT + 1 ) + NSUBBLOCKS + 1;
     103             :     }
     104             :     else
     105             :     {
     106           3 :         hTranDet->transientDetector.pSubblockEnergies->nDelay += NSUBBLOCKS + 1;
     107             :     }
     108             : 
     109        8767 :     return;
     110             : }
     111             : 
     112             : 
     113             : /*-------------------------------------------------------------------*
     114             :  * GetTCXAvgTemporalFlatnessMeasure()
     115             :  *
     116             :  *
     117             :  *-------------------------------------------------------------------*/
     118             : 
     119     3021689 : float GetTCXAvgTemporalFlatnessMeasure(
     120             :     TRAN_DET_HANDLE hTranDet,
     121             :     const int16_t nCurrentSubblocks,
     122             :     const int16_t nPrevSubblocks )
     123             : {
     124             :     int16_t i;
     125     3021689 :     TransientDetector *pTransientDetector = &hTranDet->transientDetector;
     126     3021689 :     const SubblockEnergies *pSubblockEnergies = pTransientDetector->pSubblockEnergies;
     127     3021689 :     const int16_t nDelay = pTransientDetector->nDelay;
     128     3021689 :     const int16_t nRelativeDelay = pSubblockEnergies->nDelay - nDelay;
     129     3021689 :     const float *pSubblockNrgChange = NULL;
     130             :     float sumTempFlatness;
     131     3021689 :     const int16_t nTotBlocks = nCurrentSubblocks + nPrevSubblocks;
     132             : 
     133             :     /* Initialization */
     134     3021689 :     assert( nTotBlocks > 0 );
     135     3021689 :     sumTempFlatness = 0.0f;
     136             : 
     137     3021689 :     assert( ( nPrevSubblocks <= nRelativeDelay ) && ( nCurrentSubblocks <= NSUBBLOCKS + nDelay ) );
     138     3021689 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange[nRelativeDelay - nPrevSubblocks];
     139    31318351 :     for ( i = 0; i < nTotBlocks; i++ )
     140             :     {
     141    28296662 :         sumTempFlatness += pSubblockNrgChange[i];
     142             :     }
     143             : 
     144     3021689 :     return sumTempFlatness / (float) nTotBlocks;
     145             : }
     146             : 
     147             : 
     148             : /*-------------------------------------------------------------------*
     149             :  * GetTCXMaxenergyChange()
     150             :  *
     151             :  *
     152             :  *-------------------------------------------------------------------*/
     153             : 
     154      904335 : float GetTCXMaxenergyChange(
     155             :     TRAN_DET_HANDLE hTranDet,
     156             :     const int16_t isTCX10,
     157             :     const int16_t nCurrentSubblocks,
     158             :     const int16_t nPrevSubblocks )
     159             : {
     160             :     int16_t i;
     161      904335 :     const TransientDetector *pTransientDetector = &hTranDet->transientDetector;
     162      904335 :     const SubblockEnergies *pSubblockEnergies = pTransientDetector->pSubblockEnergies;
     163      904335 :     const int16_t nDelay = pTransientDetector->nDelay;
     164      904335 :     const int16_t nRelativeDelay = pSubblockEnergies->nDelay - nDelay;
     165      904335 :     const float *pSubblockNrgChange = NULL;
     166             :     float maxEnergyChange;
     167      904335 :     int16_t nTotBlocks = nCurrentSubblocks + nPrevSubblocks;
     168             :     /* Initialization */
     169      904335 :     assert( nTotBlocks > 0 );
     170      904335 :     maxEnergyChange = 0.0f;
     171             : 
     172      904335 :     assert( ( nPrevSubblocks <= nRelativeDelay ) && ( nCurrentSubblocks <= NSUBBLOCKS + nDelay ) );
     173      904335 :     pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange[nRelativeDelay - nPrevSubblocks];
     174      904335 :     if ( pTransientDetector->bIsAttackPresent || isTCX10 ) /* frame is TCX-10 */
     175             :     {
     176       18528 :         const float *pSubblockNrg = &pSubblockEnergies->subblockNrg[nRelativeDelay - nPrevSubblocks];
     177       18528 :         float nrgMin, nrgMax = pSubblockNrg[0];
     178       18528 :         int16_t idxMax = 0;
     179             :         /* find subblock with maximum energy */
     180      236148 :         for ( i = 1; i < nTotBlocks; i++ )
     181             :         {
     182      217620 :             if ( nrgMax < pSubblockNrg[i] )
     183             :             {
     184       60614 :                 nrgMax = pSubblockNrg[i];
     185       60614 :                 idxMax = i;
     186             :             }
     187             :         }
     188       18528 :         nrgMin = nrgMax;
     189             :         /* find minimum energy after maximum */
     190       94839 :         for ( i = idxMax + 1; i < nTotBlocks; i++ )
     191             :         {
     192       76311 :             if ( nrgMin > pSubblockNrg[i] )
     193             :             {
     194       42430 :                 nrgMin = pSubblockNrg[i];
     195             :             }
     196             :         }
     197             :         /* lower maxEnergyChange if energy doesn't decrease much after energy peak */
     198       18528 :         if ( nrgMin > 0.375f * nrgMax )
     199             :         {
     200        7248 :             nTotBlocks = idxMax - 3;
     201             :         }
     202             :     }
     203    12280308 :     for ( i = 0; i < nTotBlocks; i++ )
     204             :     {
     205    11375973 :         maxEnergyChange = max( maxEnergyChange, pSubblockNrgChange[i] );
     206             :     }
     207             : 
     208      904335 :     return maxEnergyChange;
     209             : }
     210             : 
     211             : 
     212             : /*---------------------------------------------------------------*
     213             :  * RunTransientDetection()
     214             :  *
     215             :  * Time Domain Transient Detector for TCX
     216             :  *---------------------------------------------------------------*/
     217             : 
     218     1195723 : void RunTransientDetection(
     219             :     const float *input,      /* i  : input signal                    */
     220             :     const int16_t length,    /* i  : frame length                    */
     221             :     TRAN_DET_HANDLE hTranDet /* i/o: transient detection handle      */
     222             : )
     223             : {
     224             :     float filteredInput[L_FRAME_MAX];
     225     1195723 :     SubblockEnergies *pSubblockEnergies = &hTranDet->subblockEnergies;
     226     1195723 :     TransientDetector *pTransientDetector = &hTranDet->transientDetector;
     227             :     float e0, e1;
     228             : 
     229     1195723 :     assert( ( input != NULL ) && ( hTranDet != NULL ) && ( pSubblockEnergies != NULL ) && ( pTransientDetector != NULL ) );
     230             : 
     231             :     /* Variable initializations */
     232     1195723 :     HighPassFilter( input, length, &pSubblockEnergies->firState1, &pSubblockEnergies->firState2, filteredInput );
     233             : 
     234             :     /* Update subblock energies. */
     235     1195723 :     UpdateSubblockEnergies( filteredInput, length, pSubblockEnergies );
     236             : 
     237             :     /* Run transient detectors. */
     238     1195723 :     RunTransientDetector( pTransientDetector );
     239             : 
     240             :     /* Update the delay buffer. */
     241     1195723 :     UpdateDelayBuffer( filteredInput, length, &hTranDet->delayBuffer );
     242             : 
     243             :     /* compute ramp up flag */
     244     1195723 :     pSubblockEnergies->ramp_up_flag = ( ( pSubblockEnergies->ramp_up_flag << 1 ) & 0x0003 );
     245     1195723 :     e0 = dotp( filteredInput + length / 2, filteredInput + length / 2, pSubblockEnergies->pDelayBuffer->nSubblockSize / 2 ) + 0.5f * MIN_BLOCK_ENERGY;
     246     1195723 :     e1 = pSubblockEnergies->subblockNrg[pSubblockEnergies->nDelay + 4] - e0;
     247     1195723 :     if ( e1 > e0 )
     248             :     {
     249      551687 :         pSubblockEnergies->ramp_up_flag |= 0x0001;
     250             :     }
     251             : 
     252     1195723 :     return;
     253             : }
     254             : 
     255             : 
     256      942360 : static uint16_t isLongTermTransient(
     257             :     const float frameTFM,
     258             :     float *lastTFM )
     259             : {
     260             :     float currTFM;
     261             : 
     262      942360 :     if ( frameTFM > *lastTFM )
     263             :     {
     264      476769 :         const float f = ( frameTFM - *lastTFM ) * ( frameTFM - *lastTFM );
     265             : 
     266      476769 :         currTFM = *lastTFM * ( 0.96875f - f ) + frameTFM * ( 0.03125f + f );
     267             :     }
     268             :     else
     269             :     {
     270      465591 :         currTFM = *lastTFM * 0.96875f + frameTFM * 0.03125f;
     271             :     }
     272             : 
     273      942360 :     *lastTFM = max( 0.015625f, currTFM );
     274             : 
     275      942360 :     return ( currTFM < 0.5625f ? 1 : 0 );
     276             : }
     277             : 
     278             : 
     279             : /*-------------------------------------------------------------------*
     280             :  * SetTCXModeInfo()
     281             :  *
     282             :  *
     283             :  *-------------------------------------------------------------------*/
     284             : 
     285      950452 : void SetTCXModeInfo(
     286             :     Encoder_State *st,        /* i/o: encoder state structure         */
     287             :     TRAN_DET_HANDLE hTranDet, /* i/o: transient detection handle      */
     288             :     int16_t *tcxModeOverlap   /* o  : window overlap of current frame */
     289             : )
     290             : {
     291      950452 :     TCX_ENC_HANDLE hTcxEnc = st->hTcxEnc;
     292             : 
     293      950452 :     if ( st->codec_mode == MODE2 || ( st->element_mode > EVS_MONO && st->core != HQ_CORE ) )
     294             :     {
     295      942360 :         assert( hTranDet != NULL );
     296             : 
     297             :         /* determine window sequence (1 long or 2 short windows) */
     298      942360 :         if ( st->tcx10Enabled && st->tcx20Enabled )
     299             :         {
     300             :             /* window switching based on transient detector output */
     301      805501 :             if ( ( ( hTranDet->transientDetector.bIsAttackPresent ) || ( st->currEnergyHF > st->prevEnergyHF * 39.0f && st->element_mode != IVAS_CPE_MDCT ) ) &&
     302       16128 :                  ( ( st->last_core != ACELP_CORE ) && ( st->last_core != AMR_WB_CORE ) ) )
     303             :             {
     304       16061 :                 hTcxEnc->tcxMode = TCX_10;
     305             :             }
     306             :             else
     307             :             {
     308      789440 :                 hTcxEnc->tcxMode = TCX_20;
     309             :             }
     310             :         }
     311             :         else
     312             :         {
     313             :             /* window selection (non-adaptive) based on flags only */
     314      136859 :             if ( st->tcx10Enabled )
     315             :             {
     316           0 :                 hTcxEnc->tcxMode = TCX_10;
     317             :             }
     318      136859 :             else if ( st->tcx20Enabled )
     319             :             {
     320      136859 :                 hTcxEnc->tcxMode = TCX_20;
     321             :             }
     322             :             else
     323             :             {
     324           0 :                 hTcxEnc->tcxMode = NO_TCX;
     325             :             }
     326             :         }
     327             :         /* set the left window overlap */
     328      942360 :         if ( st->last_core == ACELP_CORE || st->last_core == AMR_WB_CORE )
     329             :         {
     330        9953 :             st->hTcxCfg->tcx_last_overlap_mode = TRANSITION_OVERLAP;
     331             :         }
     332      932407 :         else if ( ( hTcxEnc->tcxMode == TCX_10 ) && ( st->hTcxCfg->tcx_curr_overlap_mode == ALDO_WINDOW ) )
     333             :         {
     334       12400 :             st->hTcxCfg->tcx_last_overlap_mode = FULL_OVERLAP;
     335             :         }
     336             :         else
     337             :         {
     338      920007 :             st->hTcxCfg->tcx_last_overlap_mode = st->hTcxCfg->tcx_curr_overlap_mode;
     339             :         }
     340             : 
     341             :         /* determine the right window overlap */
     342      942360 :         if ( hTcxEnc->tcxMode == TCX_10 )
     343             :         {
     344       16061 :             if ( hTranDet->transientDetector.attackIndex < 0 )
     345             :             {
     346           0 :                 *tcxModeOverlap = HALF_OVERLAP;
     347             :             }
     348             :             else
     349             :             {
     350       16061 :                 *tcxModeOverlap = hTranDet->transientDetector.attackIndex % 4;
     351       16061 :                 if ( *tcxModeOverlap == 1 )
     352             :                 {
     353        2570 :                     *tcxModeOverlap = FULL_OVERLAP;
     354             :                 }
     355             :             }
     356       16061 :             if ( isLongTermTransient( 1.0f / GetTCXAvgTemporalFlatnessMeasure( hTranDet, NSUBBLOCKS, 0 ), &hTcxEnc->tfm_mem ) && st->element_mode == IVAS_CPE_MDCT )
     357             :             {
     358         127 :                 if ( ( *tcxModeOverlap != MIN_OVERLAP ) && ( hTcxEnc->tcxltp_norm_corr_past < 0.5625f ) )
     359             :                 {
     360          49 :                     *tcxModeOverlap = HALF_OVERLAP;
     361             :                 }
     362             :             }
     363             :         }
     364      926299 :         else if ( hTcxEnc->tcxMode == TCX_20 )
     365             :         {
     366      926299 :             if ( hTranDet->transientDetector.attackIndex == 7 )
     367             :             {
     368        3244 :                 *tcxModeOverlap = HALF_OVERLAP;
     369             :             }
     370      923055 :             else if ( hTranDet->transientDetector.attackIndex == 6 )
     371             :             {
     372        2491 :                 *tcxModeOverlap = MIN_OVERLAP;
     373             :             }
     374             :             else
     375             :             {
     376      920564 :                 *tcxModeOverlap = ALDO_WINDOW;
     377             :             }
     378      926299 :             if ( isLongTermTransient( 1.0f / GetTCXAvgTemporalFlatnessMeasure( hTranDet, NSUBBLOCKS, 0 ), &hTcxEnc->tfm_mem ) && st->element_mode == IVAS_CPE_MDCT )
     379             :             {
     380        7197 :                 if ( ( *tcxModeOverlap != MIN_OVERLAP ) && ( hTcxEnc->tcxltp_norm_corr_past < 0.5625f ) )
     381             :                 {
     382        3813 :                     *tcxModeOverlap = HALF_OVERLAP;
     383             :                 }
     384             :             }
     385             :         }
     386             :         else
     387             :         {
     388             :             /* NO_TCX */
     389           0 :             *tcxModeOverlap = TRANSITION_OVERLAP;
     390           0 :             if ( st->element_mode == IVAS_CPE_MDCT )
     391             :             {
     392           0 :                 hTcxEnc->tfm_mem = 0.75f;
     393             :             }
     394             :         }
     395             : 
     396             :         /* for the ACELP -> TCX transition frames use full right window overlap */
     397      942360 :         if ( ( st->hTcxCfg->tcx_last_overlap_mode == TRANSITION_OVERLAP ) && ( *tcxModeOverlap == ALDO_WINDOW ) )
     398             :         {
     399        9848 :             *tcxModeOverlap = FULL_OVERLAP;
     400             :         }
     401             :     }
     402             : 
     403      950452 :     return;
     404             : }
     405             : 
     406             : 
     407             : /*---------------------------------------------------------------*
     408             :  * Local functions
     409             :  *---------------------------------------------------------------*/
     410             : 
     411             : /** TCX decision.
     412             :  * Check if there is an attack in a subblock. Version for TCX Long/Short decision.
     413             :  * See TCheckSubblocksForAttack for definition of parameters.
     414             :  * 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.
     415             :  */
     416     1195723 : static void GetAttackForTCXDecision(
     417             :     const float *pSubblockNrg,
     418             :     const float *pAccSubblockNrg,
     419             :     const int16_t nSubblocks,
     420             :     const int16_t nPastSubblocks,
     421             :     const float attackRatioThreshold,
     422             :     int16_t *pbIsAttackPresent,
     423             :     int16_t *pAttackIndex )
     424             : {
     425             :     int16_t i;
     426             :     int16_t bIsAttackPresent, attackIndex;
     427             : 
     428     1195723 :     assert( nSubblocks >= NSUBBLOCKS );
     429     1195723 :     assert( nPastSubblocks >= 2 );
     430             : 
     431     1195723 :     bIsAttackPresent = FALSE;
     432     1195723 :     attackIndex = -1;
     433             :     /* Search for the last attack in the subblocks */
     434     1195723 :     if ( ( pSubblockNrg[-1] > pAccSubblockNrg[-1] * attackRatioThreshold ) || ( pSubblockNrg[-2] > pAccSubblockNrg[-2] * attackRatioThreshold ) )
     435             :     {
     436        4724 :         bIsAttackPresent = TRUE;
     437        4724 :         attackIndex = 0;
     438             :     }
     439    10761507 :     for ( i = 0; i < NSUBBLOCKS; i++ )
     440             :     {
     441     9565784 :         if ( pSubblockNrg[i] > pAccSubblockNrg[i] * attackRatioThreshold )
     442             :         {
     443       27655 :             if ( i < 6 )
     444             :             {
     445       22859 :                 bIsAttackPresent = TRUE;
     446             :             }
     447       27655 :             if ( ( attackIndex != 2 ) && ( attackIndex != 6 ) )
     448             :             {
     449       27272 :                 attackIndex = i;
     450       27272 :                 if ( ( pSubblockNrg[i] < pAccSubblockNrg[i] * 1.125f * attackRatioThreshold ) && ( i == 2 || i == 6 ) )
     451             :                 {
     452         440 :                     attackIndex++; /* avoid minimum overlap to prevent clicks */
     453             :                 }
     454             :             }
     455             :         }
     456             :         else /* no attack, but set index anyway in case of strong energy increase */
     457             :         {
     458     9538129 :             if ( ( pSubblockNrg[i] > pSubblockNrg[i - 1] * 1.5f * attackRatioThreshold ) &&
     459       15354 :                  ( pSubblockNrg[i] > pSubblockNrg[i - 2] * 1.5f * attackRatioThreshold ) )
     460             :             {
     461        6680 :                 if ( ( attackIndex != 2 ) && ( attackIndex != 6 ) )
     462             :                 {
     463        6669 :                     attackIndex = i;
     464             : 
     465        6669 :                     if ( ( ( pSubblockNrg[i] < pSubblockNrg[i - 1] * 2.0f * attackRatioThreshold ) ||
     466        6669 :                            ( pSubblockNrg[i] < pSubblockNrg[i - 2] * 2.0f * attackRatioThreshold ) ) &&
     467        2011 :                          ( i == 2 || i == 6 ) )
     468             :                     {
     469         796 :                         attackIndex++; /* avoid minimum overlap to prevent clicks */
     470             :                     }
     471             :                 }
     472             :             }
     473             :         }
     474             :     }
     475             : 
     476             :     /* avoid post-echos on click sounds (very short transients) due to TNS aliasing */
     477     1195723 :     if ( attackIndex == 4 )
     478             :     {
     479        2659 :         attackIndex = 7;
     480             :     }
     481     1193064 :     else if ( attackIndex == 5 )
     482             :     {
     483        2938 :         attackIndex = 6;
     484             :     }
     485     1195723 :     *pAttackIndex = attackIndex;
     486     1195723 :     *pbIsAttackPresent = bIsAttackPresent;
     487             : 
     488     1195723 :     return;
     489             : }
     490             : 
     491             : 
     492        8767 : static void InitDelayBuffer(
     493             :     const int16_t nFrameLength,
     494             :     const int16_t nDelay,
     495             :     DelayBuffer *pDelayBuffer )
     496             : {
     497        8767 :     const int16_t nMaxBuffSize = L_FRAME_MAX / NSUBBLOCKS;
     498             : 
     499        8767 :     assert( ( nFrameLength > NSUBBLOCKS ) && ( nFrameLength % NSUBBLOCKS == 0 ) && ( nDelay >= 0 ) && ( pDelayBuffer != NULL ) );
     500        8767 :     pDelayBuffer->nSubblockSize = nFrameLength / NSUBBLOCKS;
     501        8767 :     assert( pDelayBuffer->nSubblockSize <= nMaxBuffSize );
     502        8767 :     set_f( pDelayBuffer->buffer, 0.0f, nMaxBuffSize );
     503        8767 :     pDelayBuffer->nDelay = nDelay % pDelayBuffer->nSubblockSize;
     504        8767 :     assert( pDelayBuffer->nDelay <= nMaxBuffSize );
     505             : 
     506        8767 :     return;
     507             : }
     508             : 
     509             : 
     510        8767 : static void InitSubblockEnergies(
     511             :     const int16_t nFrameLength,
     512             :     const int16_t nDelay,
     513             :     DelayBuffer *pDelayBuffer,
     514             :     SubblockEnergies *pSubblockEnergies )
     515             : {
     516        8767 :     const int16_t nMaxBuffSize = NSUBBLOCKS + MAX_TD_DELAY;
     517             : 
     518        8767 :     assert( ( pDelayBuffer != NULL ) && ( pSubblockEnergies != NULL ) && ( pDelayBuffer->nSubblockSize * NSUBBLOCKS == nFrameLength ) && ( pDelayBuffer->nSubblockSize > 0 ) );
     519             : 
     520        8767 :     set_f( pSubblockEnergies->subblockNrg, MIN_BLOCK_ENERGY, nMaxBuffSize );
     521        8767 :     set_f( pSubblockEnergies->accSubblockNrg, MIN_BLOCK_ENERGY, nMaxBuffSize + 1 );
     522        8767 :     set_f( pSubblockEnergies->subblockNrgChange, 1.0f, nMaxBuffSize );
     523        8767 :     pSubblockEnergies->nDelay = nDelay / pDelayBuffer->nSubblockSize;
     524        8767 :     assert( pSubblockEnergies->nDelay < nMaxBuffSize );
     525        8767 :     pSubblockEnergies->nPartialDelay = nDelay % pDelayBuffer->nSubblockSize;
     526        8767 :     pSubblockEnergies->facAccSubblockNrg = 0.8125f; /* Energy accumulation factor */
     527        8767 :     pSubblockEnergies->firState1 = 0.0f;
     528        8767 :     pSubblockEnergies->firState2 = 0.0f;
     529             : 
     530        8767 :     pSubblockEnergies->pDelayBuffer = pDelayBuffer;
     531        8767 :     pDelayBuffer->nDelay = max( pDelayBuffer->nDelay, pSubblockEnergies->nPartialDelay );
     532             : 
     533        8767 :     return;
     534             : }
     535             : 
     536             : 
     537             : /** Init transient detector.
     538             :  * Fills TransientDetector structure with sensible content and enable it.
     539             :  * @param pSubblockEnergies Subblock energies used in this transient detector.
     540             :  * @param nDelay Delay for this transient detector.
     541             :  * @param nSubblocksToCheck Number of subblocks to check in this transient detector.
     542             :  * @param pCheckSubblockForAttack Attack detection function for this transient detector.
     543             :  * @param pSetAttackPosition Function for finalizing this transient detector.
     544             :  * @param attackRatioThreshold Attack ratio threshold.
     545             :  * @param pTransientDetector Structure to be initialized.
     546             :  */
     547        8767 : static void InitTransientDetector(
     548             :     SubblockEnergies *pSubblockEnergies,
     549             :     const int16_t nDelay,
     550             :     const int16_t nSubblocksToCheck,
     551             :     TCheckSubblocksForAttack pCheckSubblocksForAttack,
     552             :     const float attackRatioThreshold,
     553             :     TransientDetector *pTransientDetector )
     554             : {
     555        8767 :     const int16_t nMaxBuffSize = NSUBBLOCKS + MAX_TD_DELAY;
     556             : 
     557        8767 :     assert( ( pSubblockEnergies != NULL ) && ( pSubblockEnergies->pDelayBuffer != NULL ) && ( pTransientDetector != NULL ) && ( pSubblockEnergies->pDelayBuffer->nSubblockSize != 0 ) );
     558        8767 :     pTransientDetector->pSubblockEnergies = pSubblockEnergies;
     559        8767 :     pTransientDetector->nDelay = ( nDelay - pSubblockEnergies->nPartialDelay ) / pSubblockEnergies->pDelayBuffer->nSubblockSize;
     560        8767 :     assert( nDelay == pTransientDetector->nDelay * pSubblockEnergies->pDelayBuffer->nSubblockSize + pSubblockEnergies->nPartialDelay );
     561        8767 :     assert( pTransientDetector->nDelay < nMaxBuffSize );
     562        8767 :     pSubblockEnergies->nDelay = max( pSubblockEnergies->nDelay, pTransientDetector->nDelay );
     563        8767 :     assert( nSubblocksToCheck <= NSUBBLOCKS + pTransientDetector->nDelay );
     564        8767 :     pTransientDetector->nSubblocksToCheck = nSubblocksToCheck;
     565        8767 :     pTransientDetector->CheckSubblocksForAttack = pCheckSubblocksForAttack;
     566        8767 :     pTransientDetector->attackRatioThreshold = attackRatioThreshold;
     567        8767 :     pTransientDetector->bIsAttackPresent = FALSE;
     568        8767 :     pTransientDetector->prev_bIsAttackPresent = FALSE;
     569        8767 :     pTransientDetector->attackIndex = -1;
     570        8767 :     pTransientDetector->pSubblockEnergies->ramp_up_flag = 0x0;
     571             : 
     572        8767 :     return;
     573             : }
     574             : 
     575             : 
     576             : /* This function should be inlined and WMOPS instrumentation takes that into account, meaning that all references are considered as local variables */
     577  1015807680 : static float InlineFilter(
     578             :     float inValue,
     579             :     float firState1,
     580             :     float firState2 )
     581             : {
     582  1015807680 :     return 0.375f * inValue - 0.5f * firState1 + 0.125f * firState2;
     583             : }
     584             : 
     585             : 
     586     1195723 : static void HighPassFilter(
     587             :     const float *input,
     588             :     const int16_t length,
     589             :     float *pFirState1,
     590             :     float *pFirState2,
     591             :     float *output )
     592             : {
     593             :     int16_t i;
     594             : 
     595     1195723 :     output[0] = InlineFilter( input[0], *pFirState1, *pFirState2 );
     596     1195723 :     output[1] = InlineFilter( input[1], input[0], *pFirState1 );
     597  1014611957 :     for ( i = 2; i < length; i++ )
     598             :     {
     599  1013416234 :         output[i] = InlineFilter( input[i], input[i - 1], input[i - 2] );
     600             :     }
     601             : 
     602             :     /* update filter states: shift time samples through delay line */
     603     1195723 :     *pFirState2 = input[length - 2];
     604     1195723 :     *pFirState1 = input[length - 1];
     605             : 
     606     1195723 :     return;
     607             : }
     608             : 
     609             : 
     610     1195723 : static void RunTransientDetector(
     611             :     TransientDetector *pTransientDetector )
     612             : {
     613     1195723 :     const float attackRatioThreshold = pTransientDetector->attackRatioThreshold;
     614     1195723 :     const SubblockEnergies *pSubblockEnergies = pTransientDetector->pSubblockEnergies;
     615     1195723 :     const int16_t nDelay = pTransientDetector->nDelay;
     616     1195723 :     const int16_t nRelativeDelay = pSubblockEnergies->nDelay - nDelay;
     617     1195723 :     const float *pSubblockNrg = &pSubblockEnergies->subblockNrg[nRelativeDelay];
     618     1195723 :     const float *pAccSubblockNrg = &pSubblockEnergies->accSubblockNrg[nRelativeDelay];
     619             : 
     620     1195723 :     assert( ( pTransientDetector->CheckSubblocksForAttack != NULL ) );
     621             : 
     622             :     /* Variable initialization */
     623             : #define WMC_TOOL_SKIP
     624     1195723 :     pTransientDetector->CheckSubblocksForAttack( pSubblockNrg, pAccSubblockNrg, NSUBBLOCKS + nDelay, nRelativeDelay, attackRatioThreshold, &pTransientDetector->bIsAttackPresent, &pTransientDetector->attackIndex );
     625             : #undef WMC_TOOL_SKIP
     626             : 
     627     1195723 :     return;
     628             : }
     629             : 
     630             : 
     631     1195723 : static void UpdateDelayBuffer(
     632             :     const float *input,
     633             :     const int16_t nSamplesAvailable,
     634             :     DelayBuffer *pDelayBuffer )
     635             : {
     636             :     int16_t i;
     637     1195723 :     int16_t nDelay = pDelayBuffer->nDelay;
     638             : 
     639     1195723 :     assert( ( nDelay >= 0 ) && ( nDelay <= (int16_t) sizeof( pDelayBuffer->buffer ) / (int16_t) sizeof( pDelayBuffer->buffer[0] ) ) );
     640     1195723 :     assert( nSamplesAvailable <= NSUBBLOCKS * pDelayBuffer->nSubblockSize );
     641             : 
     642             :     /* If this is not the last frame */
     643     1195723 :     if ( nSamplesAvailable == NSUBBLOCKS * pDelayBuffer->nSubblockSize )
     644             :     {
     645             :         /* Store the newest samples into the delay buffer */
     646     1319473 :         for ( i = 0; i < nDelay; i++ )
     647             :         {
     648      123750 :             pDelayBuffer->buffer[i] = input[i + nSamplesAvailable - nDelay];
     649             :         }
     650             :     }
     651             : 
     652     1195723 :     return;
     653             : }
     654             : 
     655             : 
     656     1195723 : static void UpdateSubblockEnergies(
     657             :     const float *input,
     658             :     const int16_t nSamplesAvailable,
     659             :     SubblockEnergies *pSubblockEnergies )
     660             : {
     661             :     int16_t i;
     662             : 
     663     1195723 :     assert( ( pSubblockEnergies->nDelay >= 0 ) && ( pSubblockEnergies->nDelay + NSUBBLOCKS <= (int16_t) sizeof( pSubblockEnergies->subblockNrg ) / (int16_t) sizeof( pSubblockEnergies->subblockNrg[0] ) ) );
     664     1195723 :     assert( pSubblockEnergies->nPartialDelay <= pSubblockEnergies->pDelayBuffer->nDelay );
     665             :     /* At least one block delay is required when subblock energy change is required */
     666     1195723 :     assert( pSubblockEnergies->nDelay >= 1 );
     667             : 
     668             :     /* Shift old subblock energies */
     669    16727722 :     for ( i = 0; i < pSubblockEnergies->nDelay; i++ )
     670             :     {
     671    15531999 :         pSubblockEnergies->subblockNrg[i] = pSubblockEnergies->subblockNrg[i + NSUBBLOCKS];
     672    15531999 :         pSubblockEnergies->accSubblockNrg[i] = pSubblockEnergies->accSubblockNrg[i + NSUBBLOCKS];
     673    15531999 :         pSubblockEnergies->subblockNrgChange[i] = pSubblockEnergies->subblockNrgChange[i + NSUBBLOCKS];
     674             :     }
     675             : 
     676             :     /* Compute filtered subblock energies for the new samples */
     677     1195723 :     CalculateSubblockEnergies( input, nSamplesAvailable, pSubblockEnergies );
     678             : 
     679     1195723 :     return;
     680             : }
     681             : 
     682             : 
     683             : /* This function should be inlined and WMOPS instrumentation takes that into account, meaning that all references are considered as local variables */
     684     9565784 : static void UpdatedAndStoreAccWindowNrg(
     685             :     float newWindowNrgF,
     686             :     float *pAccSubblockNrg,
     687             :     float facAccSubblockNrg,
     688             :     float *pOutAccWindowNrgF )
     689             : {
     690             :     /* Store the accumulated energy */
     691     9565784 :     *pOutAccWindowNrgF = *pAccSubblockNrg;
     692             : 
     693             :     /* Update the accumulated energy: maximum of the current and the accumulated energy */
     694     9565784 :     *pAccSubblockNrg *= facAccSubblockNrg;
     695     9565784 :     if ( newWindowNrgF > *pAccSubblockNrg )
     696             :     {
     697     5882642 :         *pAccSubblockNrg = newWindowNrgF;
     698             :     }
     699             : 
     700     9565784 :     return;
     701             : }
     702             : 
     703             : 
     704     1195723 : static void CalculateSubblockEnergies(
     705             :     const float *input,
     706             :     const int16_t nSamplesAvailable,
     707             :     SubblockEnergies *pSubblockEnergies )
     708             : {
     709     1195723 :     DelayBuffer *pDelayBuffer = pSubblockEnergies->pDelayBuffer;                            /*  */
     710     1195723 :     const int16_t nSubblockSize = pDelayBuffer->nSubblockSize;                              /*  */
     711     1195723 :     const int16_t nDelay = pSubblockEnergies->nDelay;                                       /*  */
     712     1195723 :     const int16_t nPartialDelay = pSubblockEnergies->nPartialDelay;                         /*  */
     713     1195723 :     const float *delayBuffer = &pDelayBuffer->buffer[pDelayBuffer->nDelay - nPartialDelay]; /*   */
     714     1195723 :     const float facAccSubblockNrg = pSubblockEnergies->facAccSubblockNrg;                   /*  */
     715     1195723 :     float *pSubblockNrg = &pSubblockEnergies->subblockNrg[nDelay];                          /*  */
     716     1195723 :     float *pAccSubblockNrg = &pSubblockEnergies->accSubblockNrg[nDelay];                    /*  */
     717     1195723 :     float *pSubblockNrgChange = &pSubblockEnergies->subblockNrgChange[nDelay];              /*  */
     718             :     float *pAccSubblockTmp;
     719             :     int16_t nWindows;
     720             :     int16_t i, w, k;
     721             :     /* Variable initializations */
     722     1195723 :     nWindows = ( nSamplesAvailable + nPartialDelay ) / nSubblockSize;
     723     1195723 :     pAccSubblockTmp = &pAccSubblockNrg[nWindows];
     724             : 
     725     1195723 :     set_f( pSubblockNrg, MIN_BLOCK_ENERGY, NSUBBLOCKS );
     726             : 
     727     1195723 :     if ( nWindows > 0 )
     728             :     {
     729             :         /* Process left over samples from the previous frame. */
     730     1319473 :         for ( k = 0; k < nPartialDelay; k++ )
     731             :         {
     732      123750 :             pSubblockNrg[0] += delayBuffer[k] * delayBuffer[k];
     733             :         }
     734     1195723 :         k = 0;
     735             : 
     736             :         /* Process new samples in the 0. subblock. */
     737   128047933 :         for ( i = nPartialDelay; i < nSubblockSize; i++, k++ )
     738             :         {
     739   126852210 :             pSubblockNrg[0] += input[k] * input[k];
     740             :         }
     741             : 
     742             :         /* Set accumulated subblock energy at this point. */
     743     1195723 :         UpdatedAndStoreAccWindowNrg( pSubblockNrg[0], pAccSubblockTmp, facAccSubblockNrg, &pAccSubblockNrg[0] );
     744             : 
     745     9565784 :         for ( w = 1; w < nWindows; w++ )
     746             :         {
     747             :             /* Process new samples in the w. subblock. */
     748   897201781 :             for ( i = 0; i < nSubblockSize; i++, k++ )
     749             :             {
     750   888831720 :                 pSubblockNrg[w] += input[k] * input[k];
     751             :             }
     752             :             /* Set accumulated subblock energy at this point. */
     753     8370061 :             UpdatedAndStoreAccWindowNrg( pSubblockNrg[w], pAccSubblockTmp, facAccSubblockNrg, &pAccSubblockNrg[w] );
     754             :         }
     755             : 
     756             :         /* Calculate energy change for each block. */
     757    10761507 :         for ( w = 0; w < nWindows; w++ )
     758             :         {
     759     9565784 :             if ( pSubblockNrg[w] > pSubblockNrg[w - 1] )
     760             :             {
     761     4372063 :                 pSubblockNrgChange[w] = pSubblockNrg[w] / pSubblockNrg[w - 1];
     762             :             }
     763             :             else
     764             :             {
     765     5193721 :                 pSubblockNrgChange[w] = pSubblockNrg[w - 1] / pSubblockNrg[w];
     766             :             }
     767             :         }
     768             :     }
     769             : 
     770     1195723 :     return;
     771             : }
     772             : 
     773             : 
     774             : /*-------------------------------------------------------------------*
     775             :  * set_transient_stereo()
     776             :  *
     777             :  *
     778             :  *-------------------------------------------------------------------*/
     779             : 
     780       63470 : void set_transient_stereo(
     781             :     CPE_ENC_HANDLE hCPE, /* i  : CPE structure               */
     782             :     float currFlatness[] /* i/o: current flatness            */
     783             : )
     784             : {
     785             :     int16_t n, attackIsPresent;
     786             :     float currFlatnessMax;
     787             :     Encoder_State **sts;
     788             : 
     789       63470 :     sts = hCPE->hCoreCoder;
     790             : 
     791             :     /* for DFT/TD based stereo ,map avg. flatness to individual stereo channels (M/S or X/Y) */
     792       63470 :     maximum( currFlatness, CPE_CHANNELS, &currFlatnessMax );
     793       63470 :     attackIsPresent = 0;
     794             : 
     795      190410 :     for ( n = 0; n < CPE_CHANNELS; n++ )
     796             :     {
     797      126940 :         attackIsPresent = max( attackIsPresent, sts[n]->hTranDet->transientDetector.bIsAttackPresent );
     798             :     }
     799             : 
     800       63470 :     set_f( currFlatness, currFlatnessMax, CPE_CHANNELS );
     801             : 
     802      190410 :     for ( n = 0; n < CPE_CHANNELS; n++ )
     803             :     {
     804      126940 :         sts[n]->hTranDet->transientDetector.bIsAttackPresent = attackIsPresent;
     805             :     }
     806             : 
     807       63470 :     if ( hCPE->hStereoDft != NULL )
     808             :     {
     809       59679 :         if ( hCPE->hStereoDft->attackPresent )
     810             :         {
     811        1837 :             hCPE->hStereoDft->wasTransient = 1;
     812             :         }
     813       57842 :         else if ( hCPE->hStereoDft->wasTransient )
     814             :         {
     815        1600 :             hCPE->hStereoDft->wasTransient = 0;
     816             :         }
     817             : 
     818       59679 :         hCPE->hStereoDft->attackPresent = attackIsPresent;
     819             : 
     820       59679 :         hCPE->hStereoDft->hItd->currFlatness = 0;
     821      179037 :         for ( n = 0; n < CPE_CHANNELS; n++ )
     822             :         {
     823      119358 :             hCPE->hStereoDft->hItd->currFlatness = max( hCPE->hStereoDft->hItd->currFlatness, currFlatness[n] );
     824             :         }
     825             :     }
     826             : 
     827       63470 :     if ( hCPE->hStereoMdct != NULL )
     828             :     {
     829           0 :         hCPE->hStereoMdct->hItd->currFlatness = 0;
     830           0 :         for ( n = 0; n < CPE_CHANNELS; n++ )
     831             :         {
     832           0 :             hCPE->hStereoMdct->hItd->currFlatness = max( hCPE->hStereoMdct->hItd->currFlatness, currFlatness[n] );
     833             :         }
     834             :     }
     835             : 
     836       63470 :     return;
     837             : }
     838             : 
     839             : /*-------------------------------------------------------------------*
     840             :  * transient_analysis()
     841             :  *
     842             :  *
     843             :  *-------------------------------------------------------------------*/
     844             : 
     845             : /*! r: preliminary flag to force ACELP */
     846       10886 : int16_t transient_analysis(
     847             :     TRAN_DET_HANDLE hTranDet,    /* i  : handle transient detection             */
     848             :     const float cor_map_LT[],    /* i  : LT correlation map                     */
     849             :     const float multi_harm_limit /* i  : multi harminic threshold               */
     850             : )
     851             : {
     852             :     const float *pSubblockNrg;
     853             :     float accSubblockNrgRev[NSUBBLOCKS]; /* store acc Nrg in reversed signal */
     854             :     float *pTmp;                         /* point to acc Nrg */
     855             :     int16_t offset;
     856             :     int16_t i;
     857             :     float thr_fwd;
     858             :     float thr_rev;
     859       10886 :     const int16_t nRelativeDelay = hTranDet->subblockEnergies.nDelay - hTranDet->transientDetector.nDelay;
     860             :     int16_t prel_force_td;
     861             :     float cor_map_LT_sum;
     862             : 
     863       10886 :     pTmp = &accSubblockNrgRev[NSUBBLOCKS - 1];
     864       10886 :     offset = nRelativeDelay - 4;
     865       10886 :     prel_force_td = FALSE;
     866             : 
     867             :     /* summation of the LT correlation map */
     868       10886 :     cor_map_LT_sum = sum_f( cor_map_LT, L_FFT / 2 ); /* Note maybe BE optimized by computing inside noise_est */
     869             : 
     870       10886 :     thr_fwd = THR_NORM_HIGH;
     871       10886 :     if ( cor_map_LT_sum > multi_harm_limit * 0.8f )
     872             :     {
     873        3310 :         thr_fwd = THR_HIGH;
     874             :     }
     875       10886 :     thr_rev = THR_LOW;
     876       10886 :     if ( cor_map_LT_sum > multi_harm_limit * 0.6f )
     877             :     {
     878        9810 :         thr_rev = THR_NORM_LOW;
     879             :     }
     880             : 
     881             :     /* forward attack analysis */
     882      108860 :     for ( i = -2; i < 7; i++ )
     883             :     {
     884       97974 :         if ( hTranDet->subblockEnergies.subblockNrg[nRelativeDelay + i] > hTranDet->subblockEnergies.accSubblockNrg[nRelativeDelay + i] * thr_fwd )
     885             :         {
     886         430 :             prel_force_td |= 0x0001;
     887             :         }
     888             :     }
     889       10886 :     if ( prel_force_td == 0 && hTranDet->transientDetector.prev_bIsAttackPresent == 1 )
     890             :     {
     891             :         /* release analysis */
     892         350 :         pSubblockNrg = hTranDet->transientDetector.pSubblockEnergies->subblockNrg;
     893         350 :         set_zero( accSubblockNrgRev, NSUBBLOCKS );
     894             : 
     895        3150 :         for ( i = NSUBBLOCKS - 1; i > -1; i-- )
     896             :         {
     897        2800 :             if ( i == NSUBBLOCKS - 1 )
     898             :             {
     899         350 :                 accSubblockNrgRev[i] = pSubblockNrg[i + offset];
     900             :             }
     901             :             else
     902             :             {
     903        2450 :                 accSubblockNrgRev[i] = *pTmp;
     904        2450 :                 *pTmp *= hTranDet->transientDetector.pSubblockEnergies->facAccSubblockNrg;
     905        2450 :                 if ( pSubblockNrg[i + offset] > *pTmp )
     906             :                 {
     907        1584 :                     *pTmp = pSubblockNrg[i + offset];
     908             :                 }
     909             :             }
     910             :         }
     911             : 
     912             :         /* -3 check */
     913         350 :         if ( pSubblockNrg[1 + offset] > accSubblockNrgRev[1] * thr_rev )
     914             :         {
     915           2 :             prel_force_td |= 0x0002;
     916             :         }
     917             : 
     918             :         /* -4 check */
     919         350 :         if ( prel_force_td == 0 && pSubblockNrg[offset] > accSubblockNrgRev[0] * thr_rev )
     920             :         {
     921           7 :             if ( pSubblockNrg[offset] > accSubblockNrgRev[0] * ( thr_rev + THR_LOW_STEP ) )
     922             :             {
     923           5 :                 prel_force_td |= 0x0004;
     924             :             }
     925           2 :             else if ( ( hTranDet->subblockEnergies.ramp_up_flag & 0x0002 ) != 0 )
     926             :             {
     927           2 :                 prel_force_td |= 0x0008;
     928             :             }
     929             :         }
     930             :     }
     931             : 
     932       10886 :     return prel_force_td != 0;
     933             : }

Generated by: LCOV version 1.14