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

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : #include <stdint.h>
      34             : #include "options.h"
      35             : #include <math.h>
      36             : #include "cnst.h"
      37             : #include "rom_com.h"
      38             : #include "prot.h"
      39             : #include "ivas_prot.h"
      40             : #include "ivas_rom_com.h"
      41             : #include "ivas_cnst.h"
      42             : #include "rom_enc.h"
      43             : #ifdef DEBUGGING
      44             : #include "debug.h"
      45             : #endif
      46             : #include "wmc_auto.h"
      47             : 
      48             : 
      49             : /*-------------------------------------------------------------------*
      50             :  * Local constants
      51             :  *-------------------------------------------------------------------*/
      52             : 
      53             : #define RMS_MIN     1500  /* Minimum energy for ratio index*/
      54             : #define RMS_MIN2    1000  /* Minimum energy for LR encoding*/
      55             : #define CORR_THRES  0.95f /* Maximal open loop correlation */
      56             : #define DT_ENER_THR 200   /* Energy variation threshold */
      57             : 
      58             : #define ALP_REF 0.8f /* smoothing factor */
      59             : #define BET_REF ( 1.0f - ALP_REF )
      60             : 
      61             : #define ALP1 0.5f            /* smoothing factor in case of correlation are going in different directions */
      62             : #define BET1 ( 1.0f - ALP1 ) /* increase the update rate */
      63             : 
      64             : #define ALP2      0.2f            /* smoothing factor in case of correlation are going in different directions in SM mode*/
      65             : #define BET2      ( 1.0f - ALP2 ) /* increase the update rate in SM mode*/
      66             : #define RATIO_MAX 1.5f            /* Maximum correlation ratio */
      67             : 
      68             : #define LIMIT_ADAP_FAC 0.15f
      69             : #define MIN_ADAP_FAC   0.1f
      70             : #define M_ADAP         0.0009f
      71             : #define B_ADAP         0.16f
      72             : 
      73             : #define PC_LIMIT    64
      74             : #define RATIO_PG_HR 0.94f
      75             : #define RATIO_PG    0.92f
      76             : #define PG2ND       3.0f
      77             : #define EUCLDST     0.04f
      78             : #define RATIO_PG2   0.86f
      79             : #define PG2ND2      3.0f
      80             : #define EUCLDST2    0.08f
      81             : 
      82             : #define RMS_THR       100
      83             : #define RATIO_PG_LRTD 0.96f
      84             : 
      85             : #define IVAS_BRATE_OMASA_STEREO_SW_THR 15000
      86             : 
      87             : 
      88             : /*-------------------------------------------------------------------*
      89             :  * Local function prototypes
      90             :  *-------------------------------------------------------------------*/
      91             : 
      92             : static int16_t stereo_tdm_ener_analysis_SM( CPE_ENC_HANDLE hCPE, Encoder_State **sts, const int16_t input_frame, int16_t *tdm_SM_flag );
      93             : 
      94             : static void Get_corr_n( const float L[], const float R[], float *ic_Lm, float *ic_Rm, const int16_t len, float *es_em, const int16_t tdm_SM_calc_flag );
      95             : 
      96             : static int16_t stereo_smooth_LR_transition( int16_t *tdm_prev_stable_idx, int16_t *tdm_ratio_transition_mov_flag, int16_t tdm_last_ratio_idx, int16_t *tdm_prev_desired_idx, int16_t *tdm_ratio_transition_cnt, const int16_t tdm_SM_flag, int16_t desired_idx );
      97             : 
      98             : static int16_t limit_idx_Dwnmix( const int16_t idx_in, const int16_t unclr_decision, const int16_t inst_idx, const int16_t previous_idx, const int16_t tdm_last_LRTD_PriCh_cnt, const int16_t tdm_last_LRTD_frame_cnt );
      99             : 
     100             : static int16_t limit_idx_NoDwnmix( const int16_t idx_in, const int16_t side_can_change, const float d_lt_corr_raw );
     101             : 
     102             : static void Get_LR_rms( const float *Left_in, const float *Right_in, const int16_t input_frame, float *rms_L, float *rms_R );
     103             : 
     104             : static int16_t Get_dt_lt_ener( CPE_ENC_HANDLE hCPE, const int16_t IsSideMono, const int16_t input_frame, const int16_t tdm_last_SM_flag, const float rms_L, const float rms_R, float *tdm_lt_rms_L, float *tdm_lt_rms_R, float *tdm_last_ener_lt_L, float *tdm_last_ener_lt_R, float *tdm_LT_es_em, int16_t *tdm_hyst_cnt, int16_t *tdm_NOOP_SM_flag_loc, float *ener_R_dt, float *ener_L_dt, float *corr_LM, float *corr_RM );
     105             : 
     106             : static void NOOP_decision( CPE_ENC_HANDLE hCPE, const int16_t tdm_NOOP_flag_loc, const int16_t tmp_SM_flag, const float rms_L, const float rms_R, int16_t *tdm_SM_flag_loc );
     107             : 
     108             : static float Comp_diff_lt_corr( CPE_ENC_HANDLE hCPE, const int16_t IsSideMono, const float rms_L, const float rms_R, const float ener_L_dt, const float ener_R_dt, float corr_LM, float corr_RM, const float tdm_lt_rms_L, const float tdm_lt_rms_R, float *tdm_lt_corr_LM, float *tdm_lt_corr_RM, float *tdm_last_diff_lt_corr, float *inst_ratio_L_out, float *diff_lt_corr );
     109             : 
     110             : /*-------------------------------------------------------------------*
     111             :  * Function stereo_tdm_ener_analysis()
     112             :  *
     113             :  *-------------------------------------------------------------------*/
     114             : 
     115        3791 : int16_t stereo_tdm_ener_analysis(
     116             :     const int16_t ivas_format,   /* i  : IVAS format                         */
     117             :     CPE_ENC_HANDLE hCPE,         /* i  : CPE structure                       */
     118             :     const int16_t input_frame,   /* i  : Number of samples                   */
     119             :     int16_t *tdm_SM_or_LRTD_Pri, /* o  : channel combination scheme flag in TD stereo OR LRTD primary channel */
     120             :     int16_t *tdm_ratio_idx_SM    /* o  : TDM ratio index for SM mode         */
     121             : )
     122             : {
     123             :     float rms_R, rms_L;
     124        3791 :     float corr_RM, corr_LM, diff_lt_corr = 0, ratio_L, dist;
     125             :     int16_t i, side_can_change;
     126             :     int16_t idx, tdm_SM_flag_loc;
     127             :     int16_t tmp_SM_flag;
     128             :     float ener_R_dt, ener_L_dt;
     129             :     int16_t desired_idx;
     130             :     float rms_thd;
     131             :     int16_t tdm_NOOP_flag_loc, tdm_NOOP_flag;
     132             :     STEREO_TD_ENC_DATA_HANDLE hStereoTD;
     133             :     Encoder_State **sts;
     134             :     const float *Left_in, *Right_in;
     135             :     float d_lt_corr_raw;
     136        3791 :     float inst_ratio_L = 0;
     137             :     int16_t tdm_LRTD_pri_side;
     138             : 
     139        3791 :     hStereoTD = hCPE->hStereoTD;
     140        3791 :     sts = hCPE->hCoreCoder;
     141        3791 :     Left_in = sts[0]->input;  /* Left channel  */
     142        3791 :     Right_in = sts[1]->input; /* Right channel */
     143             : 
     144        3791 :     desired_idx = 0;
     145             : 
     146             :     /*----------------------------------------------------------------*
     147             :      * Compute L and R energy and Long term RMS of each channel
     148             :      *----------------------------------------------------------------*/
     149             : 
     150        3791 :     Get_LR_rms( Left_in, Right_in, input_frame, &rms_L, &rms_R );
     151             : 
     152             :     /*----------------------------------------------------------------*
     153             :      * Compute the 1st order energy difference difference
     154             :      * Compute the gain of L&R channel compared to mono
     155             :      * - estimate the long term evolution of the L to Mono gain
     156             :      * - estimate the long term evolution of the R to Mono gain
     157             :      * - estimate the long term difference between the long term
     158             :      * - evolution of the L and R to Mono gain
     159             :      *----------------------------------------------------------------*/
     160             : 
     161        3791 :     tdm_SM_flag_loc = hStereoTD->tdm_last_SM_flag;
     162             : 
     163        3791 :     tmp_SM_flag = Get_dt_lt_ener( hCPE, 0, input_frame, hStereoTD->tdm_last_SM_flag, rms_L, rms_R, &hStereoTD->tdm_lt_rms_L, &hStereoTD->tdm_lt_rms_R, &hStereoTD->tdm_last_ener_lt_L, &hStereoTD->tdm_last_ener_lt_R,
     164             :                                   &hStereoTD->tdm_LT_es_em, &hStereoTD->tdm_hyst_cnt, &tdm_NOOP_flag_loc, &ener_R_dt, &ener_L_dt, &corr_LM, &corr_RM );
     165             : 
     166        3791 :     hStereoTD->tdm_SM_reset_flag = 0;
     167             : 
     168             :     /*----------------------------------------------------------------*
     169             :      * Check if the signal has Near Out Of Phase characteristics
     170             :      * and trigger side/mono configuration if needed
     171             :      *----------------------------------------------------------------*/
     172             : 
     173        3791 :     NOOP_decision( hCPE, tdm_NOOP_flag_loc, tmp_SM_flag, rms_L, rms_R, &tdm_SM_flag_loc );
     174             : 
     175             :     /*----------------------------------------------------------------*
     176             :      * Adjust stereo downmixing adaptation rate factor
     177             :      * in function of the signal energy. If signal energy is low,
     178             :      * adaptation rate factor is lower. This prevent stereo image
     179             :      * move on speech offset
     180             :      *----------------------------------------------------------------*/
     181             : 
     182        3791 :     d_lt_corr_raw = Comp_diff_lt_corr( hCPE, 0, rms_L, rms_R, ener_L_dt, ener_R_dt, corr_LM, corr_RM, hStereoTD->tdm_lt_rms_L, hStereoTD->tdm_lt_rms_R, &hStereoTD->tdm_lt_corr_LM,
     183             :                                        &hStereoTD->tdm_lt_corr_RM, &hStereoTD->tdm_last_diff_lt_corr, &inst_ratio_L, &diff_lt_corr );
     184             : 
     185             :     /*----------------------------------------------------------------*
     186             :      * UNCLR classifier (detection of uncorrelated L and R channels)
     187             :      * Xtalk classifier (detection of cross-talk L and R channels)
     188             :      *----------------------------------------------------------------*/
     189             : 
     190        3791 :     unclr_classifier_td( hCPE );
     191        3791 :     xtalk_classifier_td( hCPE );
     192             : 
     193             :     /* switch to LRTD on cross-talk segments where two speakers are weakly correlated */
     194        3791 :     hStereoTD->prev_fr_LRTD_TD_dec = hCPE->hStereoClassif->lrtd_mode;
     195             : 
     196             :     /*----------------------------------------------------------------*
     197             :      * When the energies of channels are low enough, compute the ratio
     198             :      * of L and R needed to create new mono/side signals
     199             :      *----------------------------------------------------------------*/
     200             : 
     201        3791 :     if ( ivas_format == MASA_ISM_FORMAT )
     202             :     {
     203             : 
     204           0 :         if ( ( hCPE->hStereoClassif->lrtd_mode == 1 || hCPE->hStereoTD->prev_fr_LRTD_TD_dec == 1 ) && ( hCPE->element_brate - 50 * FRAMES_PER_SEC + hCPE->brate_surplus + hCPE->brate_surplus < IVAS_BRATE_OMASA_STEREO_SW_THR ) )
     205             :         {
     206           0 :             hStereoTD->prev_fr_LRTD_TD_dec = 0;
     207             :         }
     208             :     }
     209             : 
     210        3791 :     rms_thd = RMS_MIN;
     211        3791 :     if ( hCPE->hStereoClassif->lrtd_mode == 1 )
     212             :     {
     213        3791 :         rms_thd *= .25f;
     214        3791 :         if ( hStereoTD->tdm_lt_rms_L <= 75 || hStereoTD->tdm_lt_rms_R <= 75 /*|| sts[0]->last_coder_type == TRANSITION */ )
     215             :         {
     216         435 :             rms_thd *= .03125f;
     217             :         }
     218        3356 :         else if ( sts[0]->hVAD->hangover_cnt >= 8 && sts[1]->hVAD->hangover_cnt >= 8 )
     219             :         {
     220           0 :             rms_thd /= .2f;
     221             :         }
     222             : 
     223             :         /* Overwrite the LR decision flag in case the signals is already considered as S/M or when the signal is very similar between left and right channel */
     224        3791 :         if ( tdm_SM_flag_loc == 1 )
     225             :         {
     226          13 :             hStereoTD->prev_fr_LRTD_TD_dec = 0;
     227             :         }
     228        3778 :         else if ( hStereoTD->tdm_LRTD_flag == 1 && hStereoTD->tdm_FD2LRTD_SW_cnt > 10 &&
     229        3121 :                   ( hCPE->hStereoClassif->vad_flag_glob == 0 || ( hCPE->hStereoClassif->unclr_decision == 0 && ( hCPE->hStereoClassif->xtalk_score < -0.8f || hCPE->hStereoClassif->xtalk_wscore < -0.13f ) ) ||
     230        3088 :                     ( hCPE->hStereoClassif->unclr_decision == 1 && sts[0]->last_clas == UNVOICED_CLAS && sts[1]->last_clas == UNVOICED_CLAS && fabsf( hCPE->hStereoClassif->unclr_wscore ) < 0.005f ) ) )
     231             :         {
     232             :             /* This forces the LRTD to switch to TD when inactive content happens on both channel */
     233          33 :             hStereoTD->prev_fr_LRTD_TD_dec = 0;
     234             :         }
     235        3745 :         else if ( hStereoTD->tdm_LRTD_flag == 0 &&
     236         113 :                   ( hCPE->hStereoClassif->vad_flag_glob == 0 || ( hCPE->hStereoClassif->unclr_decision == 0 && ( hCPE->hStereoClassif->xtalk_score <= 0.0f || hCPE->hStereoClassif->xtalk_wscore <= 0.1f ) ) ||
     237           0 :                     ( hCPE->hStereoClassif->unclr_decision == 1 && ( sts[0]->last_clas == UNVOICED_CLAS && sts[1]->last_clas == UNVOICED_CLAS ) && fabsf( hCPE->hStereoClassif->unclr_wscore ) < 0.025f )
     238             :                     /* (sts[0]->last_clas == UNVOICED_CLAS && sts[1]->last_clas == UNVOICED_CLAS && hCPE->hStereoClassif->xtalk_wscore <= 0.0f)*/ ) )
     239             :         {
     240             :             /* This forces the LRTD to switch to TD when inactive content happens on both channel */
     241         113 :             hStereoTD->prev_fr_LRTD_TD_dec = 0;
     242             :         }
     243             :     }
     244             : 
     245        3791 :     side_can_change = 0;
     246             : 
     247             :     /* update LRTD->DFT stereo hangover counters */
     248        3791 :     if ( hStereoTD->prev_fr_LRTD_TD_dec == 1 )
     249             :     {
     250        3632 :         hStereoTD->tdm_last_LRTD_frame_cnt = 0;
     251             :     }
     252             :     else
     253             :     {
     254         159 :         hStereoTD->tdm_last_LRTD_frame_cnt++;
     255         159 :         hStereoTD->tdm_last_LRTD_frame_cnt = min( hStereoTD->tdm_last_LRTD_frame_cnt, 100 );
     256             :     }
     257             : 
     258        3791 :     if ( hCPE->last_element_mode != IVAS_CPE_TD )
     259             :     {
     260          59 :         side_can_change = 1;
     261             :     }
     262             : 
     263        3791 :     if ( hStereoTD->prev_fr_LRTD_TD_dec == 1 && side_can_change == 0 )
     264             :     {
     265        3573 :         if ( ( hStereoTD->tdm_lt_rms_L <= rms_thd && hStereoTD->tdm_lt_rms_R <= 2 * rms_thd ) ||
     266        3383 :              ( hStereoTD->tdm_lt_rms_R <= rms_thd && hStereoTD->tdm_lt_rms_L <= 2 * rms_thd ) ||
     267        3330 :              ( sts[0]->hVAD->hangover_cnt != 0 && sts[1]->hNoiseEst->Etot_last < 12 ) ||
     268        3281 :              ( sts[1]->hVAD->hangover_cnt != 0 && sts[0]->hNoiseEst->Etot_last < 12 ) ||
     269        3281 :              ( sts[0]->hSpMusClas->past_dec[0] != sts[1]->hSpMusClas->past_dec[0] ) )
     270             :         {
     271        2096 :             if ( ( ( rms_L < RMS_THR && rms_R < RMS_THR && fabsf( rms_R - rms_L ) < RMS_THR / 2.0f && fabsf( d_lt_corr_raw ) > 0.3f ) ||
     272        2050 :                    ( fabsf( sts[0]->old_corr - sts[1]->old_corr ) < 0.15f && sts[0]->old_corr > 0.7f && sts[0]->old_corr < 0.85f && fabsf( rms_L - rms_R ) < rms_thd && fabsf( d_lt_corr_raw ) > 0.3f ) ) /* Both channels are low energy, clean background switching is allowed */
     273             :             )
     274             :             {
     275         154 :                 side_can_change = 1;
     276             :             }
     277             :         }
     278             :     }
     279         218 :     else if ( side_can_change == 0 ) /*if( hStereoTD->prev_fr_LRTD_TD_dec == 0 )*/
     280             :     {
     281         159 :         if ( ( ( sts[0]->old_corr < CORR_THRES && sts[1]->old_corr < CORR_THRES ) || ( hStereoTD->tdm_lt_rms_L <= RMS_MIN2 && hStereoTD->tdm_lt_rms_R <= RMS_MIN2 ) ) &&
     282         159 :              ( ( ( hStereoTD->tdm_lt_rms_L <= rms_thd && hStereoTD->tdm_lt_rms_R <= 2 * rms_thd ) || ( hStereoTD->tdm_lt_rms_R <= rms_thd && hStereoTD->tdm_lt_rms_L <= 2 * rms_thd ) ) ||
     283          81 :                ( hCPE->hStereoClassif->lrtd_mode == 1 && ( sts[0]->tdm_LRTD_flag == 0 || ( sts[0]->tdm_LRTD_flag == 1 && ( ( rms_L < 2 * rms_thd && rms_R < 2 * rms_thd ) || ( sts[0]->hSpMusClas->past_dec[0] != sts[1]->hSpMusClas->past_dec[0] ) ) ) ) ) /* Even if the UNCLR is set to 1, the content should be encoded with TD, lower swichting requierment */
     284             :                ) )
     285             :         {
     286         159 :             side_can_change = 1;
     287             :         }
     288             :     }
     289             : 
     290        3791 :     if ( hCPE->hStereoClassif->xtalk_wscore >= 0.05f && hStereoTD->prev_fr_LRTD_TD_dec == 0 && hCPE->hStereoClassif->lrtd_mode == 1 )
     291             :     {
     292           0 :         side_can_change = 0;
     293             :     }
     294        3791 :     if ( hCPE->last_element_mode == IVAS_CPE_MDCT || hStereoTD->flag_skip_DMX == 1 )
     295             :     {
     296         100 :         desired_idx = LRTD_STEREO_LEFT_IS_PRIM;
     297         100 :         hStereoTD->tdm_prev_desired_idx = LRTD_STEREO_LEFT_IS_PRIM;
     298         100 :         ratio_L = 1.0f;
     299         100 :         hStereoTD->tdm_prev_stable_idx = LRTD_STEREO_LEFT_IS_PRIM;
     300         100 :         hStereoTD->tdm_ratio_transition_mov_flag = 0;
     301         100 :         hStereoTD->tdm_last_ratio_idx = LRTD_STEREO_LEFT_IS_PRIM;
     302         100 :         hStereoTD->tdm_ratio_transition_cnt = 0;
     303         100 :         idx = TDM_NQ; /* Reserved quantizer index for special case */
     304             :     }
     305        3691 :     else if ( side_can_change || sts[1]->ini_frame <= 1 )
     306             :     {
     307         392 :         ratio_L = max( diff_lt_corr, -RATIO_MAX );
     308         392 :         ratio_L = min( ratio_L, RATIO_MAX );
     309         392 :         ratio_L = 0.667f * ratio_L + 1.0f;
     310             : 
     311         392 :         if ( hCPE->hStereoClassif->lrtd_mode == 1 && ( hCPE->last_element_mode != IVAS_CPE_TD || hStereoTD->tdm_FD2LRTD_SW_cnt < 4 ) )
     312             :         {
     313          89 :             ratio_L = hCPE->hStereoTD->tdm_last_ratio; /* note: the last_ratio is set in before in stereo_set_tdm() */
     314             :         }
     315             :         else
     316             :         {
     317         303 :             ratio_L = ( 1.0f - cosf( EVS_PI * ratio_L / 2.0f ) ) / 2.0f;
     318             :         }
     319             : 
     320         392 :         if ( hStereoTD->tdm_LRTD_flag == 1 || ( hCPE->hStereoClassif->lrtd_mode == 1 && ( hCPE->hStereoClassif->prev_lrtd_mode == 0 || abs( hCPE->hStereoTCA->indx_ica_gD - 20 ) > 2 ) ) )
     321             :         {
     322         266 :             if ( ratio_L >= 0.53f ) /* small hysteresis is used to prevent undesired switching during inactive segment */
     323             :             {
     324         132 :                 desired_idx = LRTD_STEREO_LEFT_IS_PRIM - 1;
     325             :             }
     326         134 :             else if ( ratio_L < 0.47f )
     327             :             {
     328         105 :                 desired_idx = LRTD_STEREO_RIGHT_IS_PRIM + 1;
     329             :             }
     330          29 :             else if ( rms_L - rms_R > 10 )
     331             :             {
     332           0 :                 desired_idx = LRTD_STEREO_LEFT_IS_PRIM - 1;
     333             :             }
     334             :             else
     335             :             {
     336          29 :                 desired_idx = LRTD_STEREO_RIGHT_IS_PRIM + 1;
     337             :             }
     338             : 
     339         266 :             if ( desired_idx != hStereoTD->tdm_prev_desired_idx && hStereoTD->tdm_last_LRTD_frame_cnt == 1 && sts[0]->last_coder_type <= UNVOICED ) /* TD transtionning to FD, we don't want an inversion of channels on the first transition frame */
     340             :             {
     341           0 :                 desired_idx = hStereoTD->tdm_prev_desired_idx;
     342             :             }
     343             :             else
     344             :             {
     345         266 :                 hStereoTD->tdm_prev_desired_idx = desired_idx;
     346             :             }
     347         266 :             idx = desired_idx;
     348             :         }
     349             :         else
     350             :         {
     351         126 :             if ( hCPE->element_brate >= IVAS_48k && sts[0]->hVAD->hangover_cnt != 0 && max( hStereoTD->tdm_lt_rms_L, hStereoTD->tdm_lt_rms_R ) < 512.0f )
     352             :             {
     353           0 :                 ratio_L = check_bounds( ratio_L, 0.3f, 0.7f );
     354             :             }
     355             : 
     356         126 :             if ( ( hCPE->hStereoTCA->instTargetGain > 1.2f || hCPE->hStereoTCA->targetGain > 1.0f ) && ratio_L < 0.4f )
     357             :             {
     358           0 :                 ratio_L = 0.4f;
     359             :             }
     360         126 :             else if ( ( hCPE->hStereoTCA->instTargetGain < 0.8f || hCPE->hStereoTCA->targetGain < 1.0f ) && ratio_L > 0.6f )
     361             :             {
     362           0 :                 ratio_L = 0.6f;
     363             :             }
     364             : 
     365         126 :             dist = fabsf( ratio_L - tdm_ratio_tabl[0] );
     366             : 
     367         126 :             desired_idx = 0;
     368        3906 :             for ( i = 1; i < TDM_NQ; i++ )
     369             :             {
     370        3780 :                 if ( fabsf( ratio_L - tdm_ratio_tabl[i] ) <= dist )
     371             :                 {
     372        1614 :                     dist = fabsf( ratio_L - tdm_ratio_tabl[i] );
     373        1614 :                     desired_idx = i;
     374             :                 }
     375             :             }
     376             : 
     377         126 :             idx = stereo_smooth_LR_transition( &hStereoTD->tdm_prev_stable_idx, &hStereoTD->tdm_ratio_transition_mov_flag, hStereoTD->tdm_last_ratio_idx, &hStereoTD->tdm_prev_desired_idx, &hStereoTD->tdm_ratio_transition_cnt, tdm_SM_flag_loc, desired_idx );
     378             : 
     379             :             /* Change the switching level in case of dual mono (in case the scenario still accept left right switching */
     380             :             /* This logic is needed in case the content is exactly the same in the 2 channel and it is expected to get back to LRTD, to prevent the secondary channel to be completely empty */
     381         126 :             if ( hCPE->hStereoClassif->lrtd_mode == 1 )
     382             :             {
     383         126 :                 if ( idx <= LRTD_STEREO_MID_IS_PRIM )
     384             :                 {
     385          90 :                     idx = min( idx, LRTD_STEREO_MID_IS_PRIM - 1 );
     386             :                 }
     387             :                 else
     388             :                 {
     389          36 :                     idx = max( idx, LRTD_STEREO_MID_IS_PRIM + 1 );
     390             :                 }
     391             : 
     392         126 :                 hStereoTD->tdm_prev_desired_idx = idx;
     393             :             }
     394             :             /* 0 and 30 are reserved to signal L-R only coding  */
     395             :         }
     396             :     }
     397             :     else
     398             :     {
     399        3299 :         idx = hStereoTD->tdm_last_ratio_idx;
     400             :     }
     401             : 
     402        3791 :     hStereoTD->tdm_inst_ratio_idx = LRTD_STEREO_RIGHT_IS_PRIM;
     403        3791 :     tdm_LRTD_pri_side = -1;
     404        3791 :     if ( hStereoTD->tdm_FD2LRTD_SW_cnt < 5 )
     405             :     {
     406         236 :         desired_idx = 15;
     407             :     }
     408             :     else
     409             :     {
     410        3555 :         desired_idx = 0;
     411        3555 :         dist = fabsf( inst_ratio_L - tdm_ratio_tabl[0] );
     412             : 
     413      110205 :         for ( i = 1; i < TDM_NQ; i++ )
     414             :         {
     415      106650 :             if ( fabsf( inst_ratio_L - tdm_ratio_tabl[i] ) <= dist )
     416             :             {
     417       51997 :                 dist = fabsf( inst_ratio_L - tdm_ratio_tabl[i] );
     418       51997 :                 desired_idx = i;
     419             :             }
     420             :         }
     421             :     }
     422             : 
     423        3791 :     if ( ( sts[1]->lp_speech - sts[1]->lp_noise ) < 50.0f ) /* likely presence of noisy content */
     424             :     {
     425             :         /* pointing in the right direction, inverse it else do nothing */
     426          33 :         if ( ( idx > LRTD_STEREO_MID_IS_PRIM && desired_idx > LRTD_STEREO_MID_IS_PRIM ) || ( idx < LRTD_STEREO_MID_IS_PRIM && desired_idx < LRTD_STEREO_MID_IS_PRIM ) )
     427             :         {
     428             :             int16_t idx_offet;
     429           0 :             idx_offet = 5;
     430           0 :             if ( desired_idx > LRTD_STEREO_MID_IS_PRIM ) /* slightly Favor the 2nd channel */
     431             :             {
     432           0 :                 idx_offet *= -1;
     433             :             }
     434           0 :             desired_idx += idx_offet;
     435           0 :             desired_idx = check_bounds_s( desired_idx, 0, 30 );
     436             :         }
     437             :     }
     438             : 
     439        3791 :     if ( sts[1]->clas != UNVOICED_CLAS || sts[0]->clas != UNVOICED_CLAS )
     440             :     {
     441        2896 :         desired_idx = check_bounds_s( desired_idx, 5, 25 );
     442             :     }
     443             : 
     444        3791 :     hStereoTD->tdm_inst_ratio_idx = desired_idx;
     445        3791 :     if ( /*hCPE->last_element_mode == IVAS_CPE_MDCT ||*/ hStereoTD->flag_skip_DMX == 1 )
     446             :     {
     447             :         /*force tdm_inst_ratio_idx to the reserved index */
     448         100 :         hStereoTD->tdm_inst_ratio_idx = idx;
     449         100 :         tdm_LRTD_pri_side = 1; /* left channel */
     450             :     }
     451        3691 :     else if ( hStereoTD->tdm_LRTD_flag == 1 )
     452             :     {
     453        3565 :         idx = limit_idx_NoDwnmix( idx, side_can_change, d_lt_corr_raw );
     454        3565 :         hStereoTD->tdm_prev_stable_idx = LRTD_STEREO_LEFT_IS_PRIM;
     455        3565 :         tdm_LRTD_pri_side = 0; /* right channel */
     456        3565 :         if ( idx != LRTD_STEREO_RIGHT_IS_PRIM )
     457             :         {
     458        3297 :             tdm_LRTD_pri_side = 1; /* left channel */
     459        3297 :             hStereoTD->tdm_prev_stable_idx = LRTD_STEREO_RIGHT_IS_PRIM;
     460             :         }
     461             :     }
     462             :     else
     463             :     {
     464         126 :         idx = limit_idx_Dwnmix( idx, ( hCPE->hStereoClassif->unclr_decision || ( sts[0]->flag_noisy_speech_snr == 1 && hCPE->hStereoClassif->xtalk_wscore > 0.1f ) ), desired_idx, hStereoTD->tdm_last_ratio_idx, hStereoTD->tdm_last_LRTD_PriCh_cnt, hStereoTD->tdm_last_LRTD_frame_cnt );
     465             :     }
     466             : 
     467        3791 :     if ( abs( hStereoTD->tdm_last_ratio_idx - idx ) > LRTD_STEREO_MID_IS_PRIM )
     468             :     {
     469          37 :         hStereoTD->tdm_last_LRTD_PriCh_cnt = 0;
     470             :     }
     471             :     else
     472             :     {
     473        3754 :         hStereoTD->tdm_last_LRTD_PriCh_cnt++;
     474             :     }
     475        3791 :     ratio_L = tdm_ratio_tabl[idx];
     476             : 
     477        3791 :     if ( hStereoTD->tdm_SM_modi_flag == 1 && hStereoTD->tdm_LRTD_flag == 0 )
     478             :     {
     479           0 :         idx = (int16_t) ( ( hStereoTD->tdm_last_ratio_idx + ( LRTD_STEREO_MID_IS_PRIM + 1 ) ) * 0.5 );
     480           0 :         ratio_L = tdm_ratio_tabl[idx];
     481             :     }
     482             : 
     483        3791 :     if ( ( hStereoTD->tdm_ratio_transition_mov_flag == 1 && hStereoTD->tdm_ratio_transition_cnt >= 31 ) || ( ( hStereoTD->tdm_last_SM_flag == tdm_SM_flag_loc ) && ( idx == hStereoTD->tdm_prev_stable_idx ) ) )
     484             :     {
     485          55 :         hStereoTD->tdm_ratio_transition_cnt = 0;
     486          55 :         hStereoTD->tdm_ratio_transition_mov_flag = 0;
     487             :     }
     488             : 
     489        3791 :     if ( hStereoTD->tdm_ratio_transition_mov_flag == 0 || tdm_SM_flag_loc == 0 )
     490             :     {
     491        3789 :         hStereoTD->tdm_prev_stable_idx = idx;
     492             :     }
     493             : 
     494             :     /* NOOP ratio calculation */
     495        3791 :     if ( tdm_SM_flag_loc )
     496             :     {
     497          13 :         if ( hStereoTD->tdm_SM_reset_flag )
     498             :         {
     499           1 :             hStereoTD->tdm_lt_corr_RM_SM = 0.01f;
     500           1 :             hStereoTD->tdm_lt_corr_LM_SM = 0.01f;
     501           1 :             hStereoTD->tdm_last_ratio_SM = hStereoTD->tdm_last_ratio;
     502           1 :             hStereoTD->tdm_last_ratio_idx_SM = hStereoTD->tdm_last_ratio_idx;
     503           1 :             hStereoTD->tdm_lt_rms_L_SM = 40.0f;
     504           1 :             hStereoTD->tdm_lt_rms_R_SM = 40.0f;
     505           1 :             hStereoTD->tdm_last_diff_lt_corr_SM = 0;
     506           1 :             hStereoTD->tdm_last_ener_lt_R_SM = 0;
     507           1 :             hStereoTD->tdm_last_ener_lt_L_SM = 0;
     508             : 
     509           1 :             hStereoTD->tdm_noop_mov_flag = 0;
     510           1 :             hStereoTD->tdm_noop_cnt = 0;
     511           1 :             hStereoTD->tdm_last_SM_flag_noop = 0;
     512           1 :             hStereoTD->tdm_prev_stable_idx_SM = 0;
     513           1 :             hStereoTD->tdm_prev_desired_idx_SM = 0;
     514           1 :             hStereoTD->tdm_LT_es_em_SM = 0.1f;
     515           1 :             hStereoTD->tdm_hyst_cnt_SM = 0;
     516             :         }
     517             : 
     518          13 :         *tdm_ratio_idx_SM = stereo_tdm_ener_analysis_SM( hCPE, sts, input_frame, &tdm_NOOP_flag );
     519             :     }
     520             :     else
     521             :     {
     522        3778 :         *tdm_ratio_idx_SM = LRTD_STEREO_MID_IS_PRIM;
     523        3778 :         tdm_NOOP_flag = 1;
     524             :     }
     525             : 
     526        3791 :     sts[0]->tdm_LRTD_flag = hStereoTD->tdm_LRTD_flag;
     527        3791 :     sts[1]->tdm_LRTD_flag = hStereoTD->tdm_LRTD_flag;
     528             : 
     529             :     /* set channel combination scheme flag */
     530        3791 :     *tdm_SM_or_LRTD_Pri = tdm_SM_flag_loc;
     531        3791 :     if ( hCPE->hStereoTD->tdm_LRTD_flag == 1 )
     532             :     {
     533        3665 :         *tdm_SM_or_LRTD_Pri = tdm_LRTD_pri_side;
     534             :     }
     535             : 
     536        3791 :     hCPE->hStereoClassif->ratio_L = ratio_L;
     537             : 
     538             : #ifdef DEBUG_MODE_TD
     539             :     dbgwrite( &ratio_L, 4, 1, 320, "res/ratio_L" );
     540             :     dbgwrite( &hStereoTD->prev_fr_LRTD_TD_dec, 2, 1, 320, "res/prev_fr_LRTD_TD_dec" );
     541             :     dbgwrite( &hStereoTD->tdm_inst_ratio_idx, 2, 1, 320, "res/inst_ratio_L" );
     542             : #endif
     543             : 
     544        3791 :     return ( idx );
     545             : }
     546             : 
     547             : /*-------------------------------------------------------------------*
     548             :  * Function Get_LR_rms()
     549             :  *
     550             :  * Get current frame left and right rms values
     551             :  *-------------------------------------------------------------------*/
     552             : 
     553        3804 : static void Get_LR_rms(
     554             :     const float *Left_in,
     555             :     const float *Right_in,
     556             :     const int16_t input_frame,
     557             :     float *rms_L,
     558             :     float *rms_R )
     559             : {
     560             :     float ener_l, ener_r;
     561             :     int16_t i;
     562             : 
     563        3804 :     ener_l = 0.01f;
     564        3804 :     ener_r = 0.01f;
     565             : 
     566     2528924 :     for ( i = 0; i < input_frame; i++ )
     567             :     {
     568     2525120 :         ener_l += Left_in[i] * Left_in[i];
     569     2525120 :         ener_r += Right_in[i] * Right_in[i];
     570             :     }
     571        3804 :     *rms_L = sqrtf( ener_l / input_frame );
     572        3804 :     *rms_R = sqrtf( ener_r / input_frame );
     573             : 
     574        3804 :     return;
     575             : }
     576             : 
     577             : 
     578             : /*-------------------------------------------------------------------*
     579             :  * Function Get_dt_lt_ener()
     580             :  *
     581             :  * Compute the gain of L&R channel compared to mono
     582             :  * - estimate the long term evolution of the L to Mono gain
     583             :  * - estimate the long term evolution of the R to Mono gain
     584             :  * - estimate the long term difference between the long term
     585             :  * - evolution of the L and R to Mono gain
     586             :  *-------------------------------------------------------------------*/
     587             : 
     588        3804 : static int16_t Get_dt_lt_ener(
     589             :     CPE_ENC_HANDLE hCPE,
     590             :     const int16_t IsSideMono,
     591             :     const int16_t input_frame,
     592             :     const int16_t tdm_last_SM_flag,
     593             :     const float rms_L,
     594             :     const float rms_R,
     595             :     float *tdm_lt_rms_L,
     596             :     float *tdm_lt_rms_R,
     597             :     float *tdm_last_ener_lt_L,
     598             :     float *tdm_last_ener_lt_R,
     599             :     float *tdm_LT_es_em,
     600             :     int16_t *tdm_hyst_cnt,
     601             :     int16_t *tdm_NOOP_SM_flag_loc,
     602             :     float *ener_R_dt,
     603             :     float *ener_L_dt,
     604             :     float *corr_LM,
     605             :     float *corr_RM )
     606             : {
     607             :     Encoder_State **sts;
     608             :     const float *Left_in, *Right_in;
     609             :     float es_em;
     610             :     int16_t tmp_SM_flag, tdm_SM_flag_loc;
     611             : 
     612        3804 :     sts = hCPE->hCoreCoder;
     613        3804 :     Left_in = sts[0]->input;  /* Left channel  */
     614        3804 :     Right_in = sts[1]->input; /* Right channel */
     615             : 
     616        3804 :     tdm_SM_flag_loc = tdm_last_SM_flag;
     617             : 
     618        3804 :     if ( hCPE->last_element_mode != IVAS_CPE_TD && IsSideMono == 0 ) /* last coding mode not TD and normal mono/side case, quick update of lt energy */
     619             :     {
     620          59 :         *tdm_lt_rms_L = .9f * rms_L;
     621          59 :         *tdm_lt_rms_R = .9f * rms_R;
     622          59 :         sts[1]->hNoiseEst->Etot_last = 0.9f * ( sts[0]->hNoiseEst->Etot_last );
     623          59 :         sts[1]->hVAD->hangover_cnt = 0;
     624             :     }
     625             :     else
     626             :     {
     627        3745 :         *tdm_lt_rms_L = 0.6f * *tdm_lt_rms_L + 0.4f * rms_L;
     628        3745 :         *tdm_lt_rms_R = 0.6f * *tdm_lt_rms_R + 0.4f * rms_R;
     629             :     }
     630             : 
     631             :     /*----------------------------------------------------------------*
     632             :      * Compute the 1st order energy difference difference
     633             :      *----------------------------------------------------------------*/
     634             : 
     635        3804 :     *ener_R_dt = *tdm_lt_rms_R - *tdm_last_ener_lt_R;
     636        3804 :     *tdm_last_ener_lt_R = *tdm_lt_rms_R;
     637             : 
     638        3804 :     *ener_L_dt = *tdm_lt_rms_L - *tdm_last_ener_lt_L;
     639        3804 :     *tdm_last_ener_lt_L = *tdm_lt_rms_L;
     640             : 
     641             :     /*----------------------------------------------------------------*
     642             :      * Compute the gain of L&R channel compared to mono
     643             :      * - estimate the long term evolution of the L to Mono gain
     644             :      * - estimate the long term evolution of the R to Mono gain
     645             :      * - estimate the long term difference between the long term
     646             :      * - evolution of the L and R to Mono gain
     647             :      *----------------------------------------------------------------*/
     648             : 
     649        3804 :     Get_corr_n( Left_in, Right_in, corr_LM, corr_RM, input_frame, &es_em, IsSideMono );
     650             : 
     651        3804 :     hCPE->hStereoClassif->xtalk_fv[E_diff_corrLM_corrRM] = *corr_LM - *corr_RM;
     652             : 
     653        3804 :     if ( sts[0]->hVAD->hangover_cnt != 0 )
     654             :     {
     655         398 :         *tdm_LT_es_em = 0.9f * *tdm_LT_es_em;
     656             :     }
     657             :     else
     658             :     {
     659        3406 :         *tdm_LT_es_em = 0.9f * *tdm_LT_es_em + 0.1f * es_em;
     660             :     }
     661             : 
     662        3804 :     hCPE->hStereoClassif->xtalk_fv[E_tdm_LT_es_em] = *tdm_LT_es_em;
     663             : 
     664        3804 :     tmp_SM_flag = 0;
     665        3804 :     if ( min( sts[0]->old_corr, sts[1]->old_corr ) < 0.85f && max( sts[0]->old_corr, sts[1]->old_corr < 0.92f ) &&
     666        3284 :          ( *tdm_LT_es_em > 2.0f || es_em > 2.5f ) && ( sts[0]->hVAD->hangover_cnt <= 1 && sts[1]->hVAD->hangover_cnt <= 3 && sts[0]->tdm_LRTD_flag == 0 ) )
     667             :     {
     668           3 :         tmp_SM_flag = 1;
     669             :     }
     670        3804 :     if ( IsSideMono == 0 )
     671             :     {
     672        3791 :         *tdm_NOOP_SM_flag_loc = tdm_SM_flag_loc;
     673             :     }
     674             : 
     675        3804 :     if ( tmp_SM_flag != tdm_SM_flag_loc )
     676             :     {
     677          15 :         if ( ( *tdm_hyst_cnt )++ >= 2 && tmp_SM_flag == 1 && ( sts[0]->tdm_pc > PC_LIMIT || sts[1]->tdm_pc > PC_LIMIT ) )
     678             :         {
     679           1 :             *tdm_NOOP_SM_flag_loc = tmp_SM_flag;
     680           1 :             *tdm_hyst_cnt = 0;
     681             :         }
     682          14 :         else if ( ( *tdm_hyst_cnt )++ >= 20 && tmp_SM_flag == 0 &&
     683           3 :                   ( sts[0]->tdm_pc > PC_LIMIT || sts[1]->tdm_pc > PC_LIMIT ) && ( *tdm_LT_es_em <= 0.5f || es_em < -10.0f ) )
     684             :         {
     685           0 :             *tdm_NOOP_SM_flag_loc = tmp_SM_flag;
     686           0 :             *tdm_hyst_cnt = 0;
     687             :         }
     688             :     }
     689             :     else
     690             :     {
     691        3789 :         *tdm_hyst_cnt = 0;
     692             :     }
     693             : 
     694        3804 :     return tmp_SM_flag;
     695             : }
     696             : 
     697             : 
     698             : /*-------------------------------------------------------------------*
     699             :  * Function NOOP_decision()
     700             :  *
     701             :  * Set Near Out Of Phase decision
     702             :  *-------------------------------------------------------------------*/
     703             : 
     704        3791 : static void NOOP_decision(
     705             :     CPE_ENC_HANDLE hCPE,
     706             :     const int16_t tdm_NOOP_flag_loc,
     707             :     const int16_t tmp_SM_flag,
     708             :     const float rms_L,
     709             :     const float rms_R,
     710             :     int16_t *tdm_SM_flag_loc )
     711             : {
     712             :     int16_t tdm_NOOP_switch_flag;
     713             :     STEREO_TD_ENC_DATA_HANDLE hStereoTD;
     714             :     Encoder_State **sts;
     715             : 
     716        3791 :     hStereoTD = hCPE->hStereoTD;
     717        3791 :     sts = hCPE->hCoreCoder;
     718             : 
     719        3791 :     tdm_NOOP_switch_flag = 0;
     720        3791 :     hStereoTD->tdm_NOOP_cnt++;
     721        3791 :     if ( hCPE->hCoreCoder[0]->sp_aud_decision0 == 0 )
     722             :     {
     723        3791 :         if ( ( ( hStereoTD->tdm_SM_last2_clas[0] > VOICED_TRANSITION && ( hStereoTD->tdm_SM_last_clas[0] == UNVOICED_CLAS || hStereoTD->tdm_SM_last_clas[0] == VOICED_TRANSITION ) ) ||
     724        3791 :                ( hStereoTD->tdm_SM_last2_clas[1] > VOICED_TRANSITION && ( hStereoTD->tdm_SM_last_clas[1] == UNVOICED_CLAS || hStereoTD->tdm_SM_last_clas[1] == VOICED_TRANSITION ) ) ) &&
     725         351 :              ( !( sts[0]->last_coder_type_raw == VOICED || sts[1]->last_coder_type_raw == VOICED ) && hStereoTD->tdm_NOOP_cnt > 5 ) )
     726             :         {
     727         134 :             tdm_NOOP_switch_flag = 1;
     728         134 :             hStereoTD->tdm_NOOP_cnt = 0;
     729             :         }
     730        3657 :         else if ( ( hStereoTD->tdm_SM_last_clas[0] == UNVOICED_CLAS || hStereoTD->tdm_SM_last_clas[1] == UNVOICED_CLAS ) &&
     731        1817 :                   ( !( sts[0]->last_coder_type_raw == VOICED || sts[1]->last_coder_type_raw == VOICED ) ) && ( rms_L < 400.0f && rms_R < 400.0f ) && ( hStereoTD->tdm_NOOP_cnt > 5 ) )
     732             :         {
     733          67 :             tdm_NOOP_switch_flag = 1;
     734          67 :             hStereoTD->tdm_NOOP_cnt = 0;
     735             :         }
     736             :     }
     737             :     else
     738             :     {
     739           0 :         if ( sts[0]->ee_old < 5000.f && sts[1]->ee_old < 5000.f )
     740             :         {
     741           0 :             tdm_NOOP_switch_flag = 1;
     742             :         }
     743             :     }
     744             : 
     745        3791 :     if ( *tdm_SM_flag_loc != tdm_NOOP_flag_loc )
     746             :     {
     747           1 :         hStereoTD->tdm_SM_flag = 1;
     748           1 :         if ( hCPE->hCoreCoder[0]->sp_aud_decision0 == 0 )
     749             :         {
     750           1 :             if ( tdm_NOOP_switch_flag == 1 )
     751             :             {
     752           0 :                 *tdm_SM_flag_loc = tdm_NOOP_flag_loc;
     753           0 :                 if ( *tdm_SM_flag_loc )
     754             :                 {
     755           0 :                     hStereoTD->tdm_SM_reset_flag = 1;
     756             :                 }
     757           0 :                 hStereoTD->tdm_SM_flag = 0;
     758             :             }
     759             :         }
     760             :         else
     761             :         {
     762           0 :             if ( tdm_NOOP_switch_flag == 1 )
     763             :             {
     764           0 :                 *tdm_SM_flag_loc = tdm_NOOP_flag_loc;
     765           0 :                 if ( *tdm_SM_flag_loc )
     766             :                 {
     767           0 :                     hStereoTD->tdm_SM_reset_flag = 1;
     768             :                 }
     769           0 :                 hStereoTD->tdm_SM_flag = 0;
     770             :             }
     771             :         }
     772             : 
     773           1 :         if ( tdm_NOOP_flag_loc == 1 )
     774             :         {
     775           1 :             hStereoTD->tdm_hyst_cnt = 2;
     776             :         }
     777             :         else
     778             :         {
     779           0 :             hStereoTD->tdm_hyst_cnt = 20;
     780             :         }
     781             :     }
     782             : 
     783        3791 :     if ( hStereoTD->tdm_SM_flag > 0 && tdm_NOOP_switch_flag == 1 && *tdm_SM_flag_loc != tmp_SM_flag )
     784             :     {
     785           1 :         *tdm_SM_flag_loc = !( *tdm_SM_flag_loc );
     786           1 :         hStereoTD->tdm_SM_flag = 0;
     787           1 :         if ( *tdm_SM_flag_loc )
     788             :         {
     789           1 :             hStereoTD->tdm_SM_reset_flag = 1;
     790             :         }
     791             :     }
     792             : 
     793        3791 :     if ( hStereoTD->tdm_SM_modi_flag == 1 )
     794             :     {
     795           0 :         *tdm_SM_flag_loc = 1;
     796           0 :         hStereoTD->tdm_SM_modi_flag = 0;
     797           0 :         hStereoTD->tdm_SM_reset_flag = 1;
     798             :     }
     799             :     else
     800             :     {
     801        3791 :         if ( *tdm_SM_flag_loc == 1 && hStereoTD->tdm_SM_reset_flag == 1 && hStereoTD->tdm_last_ratio < 0.5 )
     802             :         {
     803           0 :             hStereoTD->tdm_SM_reset_flag = 0;
     804           0 :             *tdm_SM_flag_loc = 0;
     805           0 :             hStereoTD->tdm_SM_modi_flag = 1;
     806             :         }
     807             :     }
     808             : 
     809        3791 :     return;
     810             : }
     811             : 
     812             : 
     813             : /*-------------------------------------------------------------------*
     814             :  * Function Comp_diff_lt_corr()
     815             :  *
     816             :  * Adjust stereo downmixing adaptation rate factor
     817             :  * in function of the signal energy.
     818             :  *-------------------------------------------------------------------*/
     819             : 
     820        3804 : static float Comp_diff_lt_corr(
     821             :     CPE_ENC_HANDLE hCPE,
     822             :     const int16_t IsSideMono,
     823             :     const float rms_L,
     824             :     const float rms_R,
     825             :     const float ener_L_dt,
     826             :     const float ener_R_dt,
     827             :     float corr_LM,
     828             :     float corr_RM,
     829             :     const float tdm_lt_rms_L,
     830             :     const float tdm_lt_rms_R,
     831             :     float *tdm_lt_corr_LM,
     832             :     float *tdm_lt_corr_RM,
     833             :     float *tdm_last_diff_lt_corr,
     834             :     float *inst_ratio_L_out,
     835             :     float *diff_lt_corr )
     836             : {
     837             :     float adaprate, adaprate_tmp, madaprate, d_lt_corr_raw, diff_lt_corr_tmp;
     838             :     float d_lt_corr, inst_ratio_L, diff_lt_corr_LM_tmp, diff_lt_corr_RM_tmp;
     839             :     Encoder_State **sts;
     840             : 
     841        3804 :     sts = hCPE->hCoreCoder;
     842             : 
     843             :     /*----------------------------------------------------------------*
     844             :      * Adjust stereo downmixing adaptation rate factor
     845             :      * in function of the signal energy. If signal energy is low,
     846             :      * adaptation rate factor is lower. This prevent stereo image
     847             :      * move on speech offset
     848             :      *----------------------------------------------------------------*/
     849             : 
     850        3804 :     if ( IsSideMono == 0 && hCPE->hStereoClassif->lrtd_mode == 1 && ( ( tdm_lt_rms_R > 2.0f * tdm_lt_rms_L ) || ( tdm_lt_rms_L > 2.0f * tdm_lt_rms_R ) ) )
     851             :     {
     852        1489 :         adaprate = M_ADAP * max( tdm_lt_rms_R, tdm_lt_rms_L ) + B_ADAP;
     853             :     }
     854             :     else
     855             :     {
     856        2315 :         adaprate = M_ADAP * min( tdm_lt_rms_R, tdm_lt_rms_L ) + B_ADAP;
     857             :     }
     858             : 
     859        3804 :     adaprate = check_bounds( adaprate, MIN_ADAP_FAC, 1.0f );
     860             : 
     861             :     /*----------------------------------------------------------------*
     862             :      * In case of unvoiced content (expect when it is part of an onset),
     863             :      * the adaptation rate is minimal.
     864             :      *----------------------------------------------------------------*/
     865             : 
     866        3804 :     if ( sts[0]->ini_frame > 2 &&
     867        3546 :          ( ( sts[0]->last_clas <= VOICED_TRANSITION && sts[0]->hVAD->hangover_cnt == 0 ) ||
     868        2104 :            ( sts[1]->last_clas <= VOICED_TRANSITION && sts[1]->hVAD->hangover_cnt == 0 ) ) )
     869             :     {
     870        1995 :         adaprate = min( adaprate, LIMIT_ADAP_FAC );
     871             :     }
     872             : 
     873        3804 :     d_lt_corr_raw = 0.0f;
     874        3804 :     if ( IsSideMono == 0 )
     875             :     {
     876        3791 :         if ( hCPE->last_element_mode != IVAS_CPE_TD || ( ( tdm_lt_rms_R < 1.0f || tdm_lt_rms_L < 1.0f ) && hCPE->hStereoClassif->lrtd_mode == 1 && max( tdm_lt_rms_R, tdm_lt_rms_L ) < 10.0f ) )
     877             :         {
     878          71 :             adaprate = 0.98f; /* speed up the adaptation of the long term values to the current values after coming from DFT */
     879             :         }
     880        3791 :         adaprate_tmp = max( adaprate, 0.8f );
     881        3791 :         madaprate = 1.0f - adaprate_tmp; /* madaprate has temporary value, will updated few lines below */
     882             : 
     883        3791 :         d_lt_corr_raw = ( adaprate_tmp * corr_LM + madaprate * *tdm_lt_corr_LM ) -
     884        3791 :                         ( adaprate_tmp * corr_RM + madaprate * *tdm_lt_corr_RM ); /* Short term smooth correlation differences to mono */
     885        3791 :         inst_ratio_L = 0.0f;
     886             :         /*inst_ratio_L = max(diff_lt_corr,-RATIO_MAX);*/
     887        3791 :         inst_ratio_L = max( d_lt_corr_raw, -RATIO_MAX );
     888        3791 :         inst_ratio_L = min( inst_ratio_L, RATIO_MAX );
     889        3791 :         inst_ratio_L = 0.667f * inst_ratio_L + 1.0f;
     890        3791 :         *inst_ratio_L_out = ( 1.0f - cosf( EVS_PI * inst_ratio_L / 2.0f ) ) / 2.0f;
     891             :     }
     892        3804 :     madaprate = 1.0f - adaprate;
     893        3804 :     corr_RM = adaprate * corr_RM + madaprate * *tdm_lt_corr_RM;
     894        3804 :     corr_LM = adaprate * corr_LM + madaprate * *tdm_lt_corr_LM;
     895        3804 :     diff_lt_corr_LM_tmp = ( ALP_REF * *tdm_lt_corr_LM + BET_REF * corr_LM );
     896        3804 :     diff_lt_corr_RM_tmp = ( ALP_REF * *tdm_lt_corr_RM + BET_REF * corr_RM );
     897        3804 :     diff_lt_corr_tmp = diff_lt_corr_LM_tmp - diff_lt_corr_RM_tmp;
     898             : 
     899        3804 :     d_lt_corr = diff_lt_corr_tmp - *tdm_last_diff_lt_corr;
     900        3804 :     *tdm_last_diff_lt_corr = diff_lt_corr_tmp;
     901             : 
     902             :     /*----------------------------------------------------------------*
     903             :      * Correct the estimation depending of channels energies evolution
     904             :      *----------------------------------------------------------------*/
     905             : 
     906        3804 :     if ( IsSideMono == 1 && ( ( rms_L < RMS_MIN2 && rms_R < RMS_MIN2 ) && ( ( tdm_lt_rms_L < 0.8f * rms_L ) && ( tdm_lt_rms_R < 0.8f * rms_R ) ) &&
     907           0 :                               ( ( tdm_lt_rms_L > 2.0f * tdm_lt_rms_R ) || ( tdm_lt_rms_L < 0.5f * tdm_lt_rms_R ) ) ) )
     908             :     {
     909           0 :         *tdm_lt_corr_LM = ALP2 * *tdm_lt_corr_LM + BET2 * corr_LM;
     910           0 :         *tdm_lt_corr_RM = ALP2 * *tdm_lt_corr_RM + BET2 * corr_RM;
     911             : 
     912           0 :         *tdm_lt_corr_LM *= 2.5f;
     913           0 :         *tdm_lt_corr_RM *= 2.5f;
     914             :     }
     915        3804 :     else if ( ( !( ( ener_R_dt > DT_ENER_THR && ener_L_dt < DT_ENER_THR ) || ( ener_R_dt < DT_ENER_THR && ener_L_dt > DT_ENER_THR ) ) /* Energy are going in the same direction */
     916        3100 :                 && ( fabsf( d_lt_corr ) < 0.31f                                                                                       /* small difference regarding the difference gain evolution */
     917         188 :                      || tdm_lt_rms_L > 2 * RMS_MIN2 || tdm_lt_rms_R > 2 * RMS_MIN2 ) )                                                /* Energy of at least one of the channel is not low */
     918             :     )
     919             :     {
     920             :         /* Use estimated results */
     921        2975 :         *tdm_lt_corr_LM = diff_lt_corr_LM_tmp;
     922        2975 :         *tdm_lt_corr_RM = diff_lt_corr_RM_tmp;
     923             :     }
     924             :     else
     925             :     {
     926         829 :         *tdm_lt_corr_LM = ALP1 * *tdm_lt_corr_LM + BET1 * corr_LM;
     927         829 :         *tdm_lt_corr_RM = ALP1 * *tdm_lt_corr_RM + BET1 * corr_RM;
     928             :     }
     929             : 
     930        3804 :     *diff_lt_corr = *tdm_lt_corr_LM - *tdm_lt_corr_RM; /* update the difference */
     931             : 
     932        3804 :     return d_lt_corr_raw;
     933             : }
     934             : 
     935             : 
     936             : /*-------------------------------------------------------------------*
     937             :  * Function limit_idx_Dnwmix()
     938             :  *
     939             :  *
     940             :  *-------------------------------------------------------------------*/
     941             : 
     942         126 : static int16_t limit_idx_Dwnmix(
     943             :     const int16_t idx_in,
     944             :     const int16_t unclr_decision,
     945             :     const int16_t inst_idx,
     946             :     const int16_t previous_idx,
     947             :     const int16_t tdm_last_LRTD_PriCh_cnt,
     948             :     const int16_t tdm_last_LRTD_frame_cnt )
     949             : {
     950             :     int16_t idx;
     951             : 
     952         126 :     idx = idx_in;
     953         126 :     idx = check_bounds_s( idx, 1, 29 );
     954             : 
     955         126 :     if ( unclr_decision == 1 && tdm_last_LRTD_frame_cnt > 1 )
     956             :     {
     957          75 :         if ( tdm_last_LRTD_PriCh_cnt > 0 )
     958             :         {
     959          71 :             if ( idx <= LRTD_STEREO_MID_IS_PRIM && ( inst_idx < LRTD_STEREO_MID_IS_PRIM + 2 ) )
     960             :             {
     961          35 :                 idx = min( 1, idx );
     962             :             }
     963          36 :             else if ( idx >= LRTD_STEREO_MID_IS_PRIM && ( inst_idx > LRTD_STEREO_MID_IS_PRIM - 2 ) )
     964             :             {
     965          29 :                 idx = max( 29, idx );
     966             :             }
     967           7 :             else if ( inst_idx < LRTD_STEREO_MID_IS_PRIM - 4 )
     968             :             {
     969           2 :                 idx = min( 1, idx );
     970             :             }
     971           5 :             else if ( inst_idx > LRTD_STEREO_MID_IS_PRIM + 4 )
     972             :             {
     973           2 :                 idx = max( 29, idx );
     974             :             }
     975             :             else
     976             :             {
     977           3 :                 idx = previous_idx;
     978             :             }
     979             :         }
     980             :         else
     981             :         {
     982           4 :             idx = previous_idx;
     983             :         }
     984             :     }
     985             : 
     986         126 :     return idx;
     987             : }
     988             : 
     989             : 
     990             : /*-------------------------------------------------------------------*
     991             :  * Function limit_idx_NoDwnmix()
     992             :  *
     993             :  *-------------------------------------------------------------------*/
     994             : 
     995        3565 : static int16_t limit_idx_NoDwnmix(
     996             :     const int16_t idx_in,          /* i  : Index */
     997             :     const int16_t side_can_change, /* i  : Primary and secondary channel allowed to change ? */
     998             :     const float d_lt_corr_raw      /* i  : Raw corrrelation differences */
     999             : )
    1000             : {
    1001             :     int16_t idx;
    1002             : 
    1003        3565 :     idx = idx_in;
    1004        3565 :     if ( side_can_change == 0 && idx_in > 10 && idx_in < 20 )
    1005             :     {
    1006           0 :         idx = 30;
    1007           0 :         if ( d_lt_corr_raw < -0.1f )
    1008             :         {
    1009           0 :             idx = 0;
    1010             :         }
    1011             :     }
    1012             :     else
    1013             :     {
    1014        3565 :         if ( idx <= 15 )
    1015             :         {
    1016         268 :             idx = 0;
    1017             :         }
    1018             :         else
    1019             :         {
    1020        3297 :             idx = 30;
    1021             :         }
    1022             :     }
    1023             : 
    1024        3565 :     return idx;
    1025             : }
    1026             : 
    1027             : 
    1028             : /*-------------------------------------------------------------------*
    1029             :  * Function stereo_tdm_ener_analysis_SM()
    1030             :  *
    1031             :  *
    1032             :  *-------------------------------------------------------------------*/
    1033             : 
    1034          13 : static int16_t stereo_tdm_ener_analysis_SM(
    1035             :     CPE_ENC_HANDLE hCPE,       /* i  : CPE encoder structure               */
    1036             :     Encoder_State **sts,       /* i/o: Encoder static variables structure  */
    1037             :     const int16_t input_frame, /* i  : Number of samples                   */
    1038             :     int16_t *tdm_SM_flag       /* i/o: channel combination scheme flag     */
    1039             : )
    1040             : {
    1041             :     float rms_R, rms_L;
    1042             :     float corr_RM, corr_LM, diff_lt_corr, ratio_L, dist;
    1043             :     int16_t i, side_can_change;
    1044             :     int16_t idx, tdm_SM_flag_loc;
    1045          13 :     float es_em = 0.01f;
    1046             :     float ener_R_dt, ener_L_dt;
    1047          13 :     int16_t desired_idx = 0;
    1048             :     STEREO_TD_ENC_DATA_HANDLE hStereoTD;
    1049             : 
    1050          13 :     hStereoTD = hCPE->hStereoTD;
    1051             : 
    1052             :     /*----------------------------------------------------------------*
    1053             :      * set SM flag
    1054             :      *----------------------------------------------------------------*/
    1055             : 
    1056             :     /* Simple logic to set SM flag, should be done in the frequency domain for low SM correlation signal, especially for music item such as Music_1_org_s */
    1057          13 :     tdm_SM_flag_loc = hStereoTD->tdm_last_SM_flag_noop;
    1058             : 
    1059             :     /*----------------------------------------------------------------*
    1060             :      * Compute L and R energy and Long term RMS of each channel
    1061             :      *----------------------------------------------------------------*/
    1062             : 
    1063          13 :     Get_LR_rms( sts[0]->input, sts[1]->input, input_frame, &rms_L, &rms_R );
    1064             : 
    1065             :     /*----------------------------------------------------------------*
    1066             :      * Compute the 1st order energy difference difference
    1067             :      * Compute the gain of L&R channel compared to mono
    1068             :      * - estimate the long term evolution of the L to Mono gain
    1069             :      * - estimate the long term evolution of the R to Mono gain
    1070             :      * - estimate the long term difference between the long term
    1071             :      * - evolution of the L and R to Mono gain
    1072             :      *----------------------------------------------------------------*/
    1073             : 
    1074          13 :     Get_dt_lt_ener( hCPE, 1, input_frame, hStereoTD->tdm_last_SM_flag_noop, rms_L, rms_R,
    1075             :                     &hStereoTD->tdm_lt_rms_L_SM, &hStereoTD->tdm_lt_rms_R_SM, &hStereoTD->tdm_last_ener_lt_L_SM, &hStereoTD->tdm_last_ener_lt_R_SM, &hStereoTD->tdm_LT_es_em_SM, &hStereoTD->tdm_hyst_cnt_SM, &tdm_SM_flag_loc,
    1076             :                     &ener_R_dt, &ener_L_dt, &corr_LM, &corr_RM );
    1077             : 
    1078          13 :     hStereoTD->tdm_SM_reset_flag = 0;
    1079             : 
    1080             :     /*----------------------------------------------------------------*
    1081             :      * Adjust stereo downmixing adaptation rate factor
    1082             :      * in function of the signal energy. If signal energy is low,
    1083             :      * adaptation rate factor is lower. This prevent stereo image
    1084             :      * move on speech offset
    1085             :      *----------------------------------------------------------------*/
    1086             : 
    1087          13 :     Comp_diff_lt_corr( hCPE, 1, rms_L, rms_R, ener_L_dt, ener_R_dt, corr_LM, corr_RM, hStereoTD->tdm_lt_rms_L_SM, hStereoTD->tdm_lt_rms_R_SM, &hStereoTD->tdm_lt_corr_LM_SM,
    1088             :                        &hStereoTD->tdm_lt_corr_RM_SM, &( hStereoTD->tdm_last_diff_lt_corr_SM ), NULL, &diff_lt_corr );
    1089             : 
    1090          13 :     side_can_change = 0;
    1091             : 
    1092             :     /*----------------------------------------------------------------*
    1093             :      * When the energies of channels are low enough, compute the ratio
    1094             :      * of L and R needed to create new mono/side signals
    1095             :      *----------------------------------------------------------------*/
    1096             : 
    1097          13 :     if ( ( hStereoTD->tdm_lt_rms_L_SM <= RMS_MIN && hStereoTD->tdm_lt_rms_R_SM <= 2 * RMS_MIN ) || ( hStereoTD->tdm_lt_rms_R_SM <= RMS_MIN && hStereoTD->tdm_lt_rms_L_SM <= 2 * RMS_MIN ) )
    1098             :     {
    1099          13 :         if ( ( sts[0]->old_corr < CORR_THRES && sts[1]->old_corr < CORR_THRES ) || ( hStereoTD->tdm_lt_rms_L_SM <= RMS_MIN2 && hStereoTD->tdm_lt_rms_R_SM <= RMS_MIN2 ) )
    1100             :         {
    1101          13 :             side_can_change = 1;
    1102             :         }
    1103             :     }
    1104             : 
    1105          13 :     if ( ( hStereoTD->tdm_lt_rms_L_SM <= RMS_MIN2 && hStereoTD->tdm_lt_rms_R_SM <= 2 * RMS_MIN2 ) || ( hStereoTD->tdm_lt_rms_R_SM <= RMS_MIN2 && hStereoTD->tdm_lt_rms_L_SM <= 2 * RMS_MIN2 ) )
    1106             :     {
    1107          13 :         if ( ( ( hStereoTD->tdm_last_SM_flag_noop != tdm_SM_flag_loc ) && hStereoTD->tdm_noop_cnt == 0 ) ||
    1108          13 :              hStereoTD->tdm_noop_mov_flag == 1 || hStereoTD->tdm_prev_desired_idx_SM != hStereoTD->tdm_prev_stable_idx_SM )
    1109             :         {
    1110           3 :             hStereoTD->tdm_noop_mov_flag = 1;
    1111           3 :             if ( hStereoTD->tdm_last_ratio_idx_SM != 0 && hStereoTD->tdm_last_ratio_idx_SM != ( TDM_NQ - 1 ) )
    1112             :             {
    1113           3 :                 side_can_change = 1;
    1114             :             }
    1115             :         }
    1116             :     }
    1117             : 
    1118          13 :     if ( side_can_change == 0 && tdm_SM_flag_loc == 1 && es_em > 15.0f )
    1119             :     {
    1120           0 :         side_can_change = 1;
    1121             :     }
    1122             : 
    1123          13 :     if ( side_can_change )
    1124             :     {
    1125          13 :         ratio_L = max( diff_lt_corr, -RATIO_MAX );
    1126          13 :         ratio_L = min( ratio_L, RATIO_MAX );
    1127             : 
    1128          13 :         if ( ratio_L > 0.5f * RATIO_MAX )
    1129             :         {
    1130           0 :             ratio_L = 1.08f * ratio_L + 0.38f;
    1131             :         }
    1132          13 :         else if ( ratio_L < -0.5f * RATIO_MAX )
    1133             :         {
    1134           0 :             ratio_L = 0.64f * ratio_L + 1.28f;
    1135             :         }
    1136             :         else
    1137             :         {
    1138          13 :             ratio_L = 0.26f * ratio_L + 0.995f;
    1139             :         }
    1140             : 
    1141          13 :         ratio_L = ( 1.0f - cosf( EVS_PI * ratio_L / 2.0f ) ) / 2.0f;
    1142             : 
    1143          13 :         dist = fabsf( ratio_L - tdm_ratio_tabl[0] );
    1144             : 
    1145          13 :         desired_idx = 0;
    1146         403 :         for ( i = 1; i < TDM_NQ; i++ )
    1147             :         {
    1148         390 :             if ( fabsf( ratio_L - tdm_ratio_tabl[i] ) <= dist )
    1149             :             {
    1150         195 :                 dist = fabsf( ratio_L - tdm_ratio_tabl[i] );
    1151         195 :                 desired_idx = i;
    1152             :             }
    1153             :         }
    1154             : 
    1155          13 :         idx = stereo_smooth_LR_transition( &hStereoTD->tdm_prev_stable_idx_SM, &hStereoTD->tdm_noop_mov_flag, hStereoTD->tdm_last_ratio_idx_SM, &hStereoTD->tdm_prev_desired_idx_SM, &hStereoTD->tdm_noop_cnt, tdm_SM_flag_loc, desired_idx );
    1156             : 
    1157          13 :         idx = (int16_t) ( idx * 0.8f + hStereoTD->tdm_last_ratio_idx_SM * 0.2f );
    1158             : 
    1159          13 :         ratio_L = tdm_ratio_tabl[idx];
    1160             :     }
    1161             :     else
    1162             :     {
    1163           0 :         ratio_L = hStereoTD->tdm_last_ratio_SM;
    1164           0 :         idx = hStereoTD->tdm_last_ratio_idx_SM;
    1165             :     }
    1166             : 
    1167          13 :     if ( ( hStereoTD->tdm_noop_mov_flag == 1 && hStereoTD->tdm_noop_cnt >= 31 ) || ( ( hStereoTD->tdm_last_SM_flag_noop == tdm_SM_flag_loc ) && ( idx == hStereoTD->tdm_prev_stable_idx_SM ) ) )
    1168             :     {
    1169          10 :         hStereoTD->tdm_noop_cnt = 0;
    1170          10 :         hStereoTD->tdm_noop_mov_flag = 0;
    1171             :     }
    1172             : 
    1173          13 :     if ( hStereoTD->tdm_noop_mov_flag == 0 || tdm_SM_flag_loc == 0 )
    1174             :     {
    1175          13 :         hStereoTD->tdm_prev_stable_idx_SM = idx;
    1176             :     }
    1177             : 
    1178          13 :     hStereoTD->tdm_last_SM_flag_noop = tdm_SM_flag_loc;
    1179          13 :     *tdm_SM_flag = tdm_SM_flag_loc;
    1180             : 
    1181          13 :     return ( idx );
    1182             : }
    1183             : 
    1184             : 
    1185             : /*-------------------------------------------------------------------*
    1186             :  * tdm_lp_comparison()
    1187             :  *
    1188             :  * Perform the comparison of the 2 sets of LP coefficients
    1189             :  *-------------------------------------------------------------------*/
    1190             : 
    1191             : /*! r: replication decision; 1 = Use old LP */
    1192        3791 : int16_t tdm_lp_comparison(
    1193             :     STEREO_TD_ENC_DATA_HANDLE hStereoTD,  /* i/o: TD stereo encoder handle        */
    1194             :     STEREO_CLASSIF_HANDLE hStereoClassif, /* i/o: stereo classifier structure     */
    1195             :     Encoder_State *st,                    /* i/o: Encoder structure               */
    1196             :     const float *speech,                  /* i  : Current speech frame            */
    1197             :     const float *A_PCh,                   /* i  : primary channel LP coefficients */
    1198             :     const float *A_SCh,                   /* i  : secondary channel LP coeff.     */
    1199             :     const int16_t m,                      /* i  : filter length                   */
    1200             :     const float *isp_PCh,                 /* i  : primary channel LSPs            */
    1201             :     const float *isp_SCh,                 /* i  : secondary channel LSPs          */
    1202             :     const int16_t L_frame,                /* i  : frame length                    */
    1203             :     const int32_t element_brate_wo_meta   /* i  : element bitrate without metadata*/
    1204             : )
    1205             : {
    1206             :     float predgain_SCh, pred_gain_reuse_PCh, ener_sig;
    1207             :     float res[L_FRAME16k];
    1208             :     int16_t LP_mode;
    1209             :     float dist, ftmp;
    1210             :     int16_t i;
    1211             : 
    1212             :     /* Find prediction gain for current LP filter */
    1213        3791 :     residu( A_SCh, m, speech, res, L_frame );
    1214        3791 :     ener_sig = log10f( sum2_f( speech, L_frame ) + 0.01f );
    1215        3791 :     predgain_SCh = 10.0f * ( ener_sig - log10f( sum2_f( res, L_frame ) + 0.01f ) );
    1216             : 
    1217             :     /* Find prediction gain when resuing the Primary Channel LP filter */
    1218        3791 :     residu( A_PCh, m, speech, res, L_frame );
    1219        3791 :     pred_gain_reuse_PCh = 10.0f * ( ener_sig - log10f( sum2_f( res, L_frame ) + 0.01f ) );
    1220             : 
    1221             :     /* Find Euclidian distance between the 2 filters */
    1222        3791 :     dist = 0;
    1223       64447 :     for ( i = 0; i < m; i++ )
    1224             :     {
    1225       60656 :         ftmp = isp_SCh[i] - isp_PCh[i];
    1226       60656 :         dist += ftmp * ftmp;
    1227             :     }
    1228        3791 :     ener_sig *= 10.0f;
    1229             : 
    1230             :     /* Verification of the filters similartiies and prediction gain obtained for each channel */
    1231             :     /* Threshold are more relax if alpha is close to 0.5  (Valid if ICA is used )             */
    1232        3791 :     if ( ( ( pred_gain_reuse_PCh >= RATIO_PG * predgain_SCh && dist < EUCLDST )                                                                       /* Prediction gain are close & Euclidian dist is small */
    1233        2890 :            || ( predgain_SCh < PG2ND && dist < EUCLDST2 ) )                                                                                           /* Prediction gain if the secondary channel is low  & Euclidian dist is not too large */
    1234        2716 :          || ( hStereoTD->tdm_last_ratio_idx >= ( LRTD_STEREO_MID_IS_PRIM - 2 ) && hStereoTD->tdm_last_ratio_idx <= ( LRTD_STEREO_MID_IS_PRIM + 2 ) && /* ratio between 0.4 and 0.6 */
    1235           0 :               ( ( pred_gain_reuse_PCh >= RATIO_PG2 * predgain_SCh && dist < EUCLDST2 ) || predgain_SCh < PG2ND2 ) )                                   /* Prediction gain are not far  & Euclidian dist is not too large or  Prediction gain if the secondary channel is low  */
    1236        2716 :          || ener_sig <= 30.0f                                                                                                                         /* secondary channel has low energy */
    1237             :     )
    1238             :     {
    1239        1075 :         LP_mode = 1;
    1240             : 
    1241        1075 :         if ( ( element_brate_wo_meta >= IVAS_48k && !( pred_gain_reuse_PCh >= RATIO_PG_HR * predgain_SCh && dist < EUCLDST ) ) ||
    1242        1075 :              ( hStereoClassif->lrtd_mode == 1 && element_brate_wo_meta < IVAS_16k4 && !( pred_gain_reuse_PCh >= RATIO_PG_HR * predgain_SCh && dist < EUCLDST / 2.0f ) ) ||
    1243        1075 :              ( hStereoClassif->lrtd_mode == 1 && element_brate_wo_meta >= IVAS_16k4 && !( pred_gain_reuse_PCh >= RATIO_PG_LRTD * predgain_SCh && dist < EUCLDST / 4.0f ) ) || st->tc_cnt > 0 )
    1244             :         {
    1245         925 :             LP_mode = 0;
    1246             :         }
    1247             :     }
    1248             :     else
    1249             :     {
    1250             :         /* Prediction or and filters are too different -> quantize the difference*/
    1251        2716 :         LP_mode = 0;
    1252             :     }
    1253             : 
    1254        3791 :     return LP_mode;
    1255             : }
    1256             : 
    1257             : 
    1258             : /*-------------------------------------------------------------------*
    1259             :  * tdm_ol_pitch_comparison()
    1260             :  *
    1261             :  * Perform the comparison of the 2 sets of OL pitch
    1262             :  *-------------------------------------------------------------------*/
    1263             : 
    1264             : /*! r: replication decision; 1 = Use old LP */
    1265        3791 : void tdm_ol_pitch_comparison(
    1266             :     CPE_ENC_HANDLE hCPE,                     /* i  : CPE encoder structure                   */
    1267             :     float pitch_fr[CPE_CHANNELS][NB_SUBFR],  /* i/o: fractional pitch values                 */
    1268             :     float voicing_fr[CPE_CHANNELS][NB_SUBFR] /* i/o: fractional pitch gains                  */
    1269             : )
    1270             : {
    1271             :     int16_t tmp_diff;
    1272        3791 :     int16_t diff_thr = 6;
    1273             :     Encoder_State *st0, *st1;
    1274             : 
    1275        3791 :     st0 = hCPE->hCoreCoder[0]; /* Encoder structure - primary channel     */
    1276        3791 :     st1 = hCPE->hCoreCoder[1]; /* Encoder structure - secondary channel   */
    1277             : 
    1278        3791 :     if ( hCPE->element_brate > IVAS_13k2 )
    1279             :     {
    1280        3791 :         diff_thr = 3;
    1281             :     }
    1282             : 
    1283        3791 :     if ( hCPE->element_brate >= IVAS_48k || hCPE->hStereoTD->tdm_LRTD_flag == 1 )
    1284             :     {
    1285        3665 :         diff_thr = 1;
    1286             :     }
    1287             : 
    1288        3791 :     hCPE->hStereoTD->tdm_Pitch_reuse_flag = 0;
    1289             : 
    1290        3791 :     if ( ( ( st0->sp_aud_decision1 == 0 && st0->sp_aud_decision2 == 0 ) && /* Pitch is not recycled in case of music coding*/
    1291        3249 :            ( hCPE->element_brate <= IVAS_16k4 || ( hCPE->element_brate <= IVAS_24k4 && st0->coder_type == VOICED && st1->coder_type == VOICED ) ) ) ||
    1292        3089 :          hCPE->element_brate < IVAS_13k2 )
    1293             :     {
    1294         702 :         if ( hCPE->hStereoClassif->lrtd_mode == 1 )
    1295             :         {
    1296             :             float voicmin[4];
    1297             : 
    1298         702 :             minimum( st0->voicing, 3, voicmin );
    1299         702 :             minimum( st1->voicing, 3, voicmin + 1 );
    1300         702 :             minimum( voicing_fr[0], 4, voicmin + 2 );
    1301         702 :             minimum( voicing_fr[1], 4, voicmin + 3 );
    1302             : 
    1303         702 :             tmp_diff = 10;
    1304         702 :             if ( voicmin[0] >= .9f && voicmin[1] >= .9f && voicmin[2] >= .85f && voicmin[3] >= .85f )
    1305             :             {
    1306          41 :                 tmp_diff = (int16_t) ( abs( ( st0->pitch[0] - st1->pitch[0] ) ) + abs( ( st0->pitch[1] - st1->pitch[1] ) ) + abs( ( st0->pitch[2] - st1->pitch[2] ) ) );
    1307             :             }
    1308             :         }
    1309             :         else
    1310             :         {
    1311           0 :             tmp_diff = (int16_t) abs( ( st0->pitch[0] + st0->pitch[1] + st0->pitch[2] ) - ( st1->pitch[0] + st1->pitch[1] + st1->pitch[2] ) );
    1312             :         }
    1313             : 
    1314         702 :         if ( tmp_diff <= diff_thr )
    1315             :         {
    1316          33 :             hCPE->hStereoTD->tdm_Pitch_reuse_flag = 1;
    1317             : 
    1318             :             /* 1/4 pitch precision update*/
    1319          33 :             mvs2s( st0->pitch, st1->pitch, 3 );
    1320          33 :             mvr2r( st0->voicing, st1->voicing, 3 );
    1321             : 
    1322             :             /* Update some parameters accordingly */
    1323          33 :             st1->old_corr = st0->old_corr;
    1324          33 :             st1->old_thres = st0->old_thres;
    1325          33 :             st1->delta_pit = st0->delta_pit;
    1326             : 
    1327             :             /* Updates for adaptive lag window memory */
    1328          33 :             st1->old_pitch_la = st0->old_pitch_la;
    1329             :             /* 1/4 pitch precision update*/
    1330          33 :             mvr2r( pitch_fr[0], pitch_fr[1], NB_SUBFR );
    1331          33 :             mvr2r( voicing_fr[0], voicing_fr[1], NB_SUBFR );
    1332             :         }
    1333             :     }
    1334             : 
    1335        3791 :     return;
    1336             : }
    1337             : 
    1338             : 
    1339             : /*-------------------------------------------------------------------*
    1340             :  * Function Get_corr_n()
    1341             :  *
    1342             :  *
    1343             :  *-------------------------------------------------------------------*/
    1344             : 
    1345        3804 : static void Get_corr_n(
    1346             :     const float L[],               /* i  : Left signal                                             */
    1347             :     const float R[],               /* i  : Right signal                                            */
    1348             :     float *ic_Lm,                  /* o  : Right signal                                            */
    1349             :     float *ic_Rm,                  /* o  : Right signal                                            */
    1350             :     const int16_t len,             /* i  : segment length                                          */
    1351             :     float *es_em,                  /* o  : return the difference between the side and mono energy  */
    1352             :     const int16_t tdm_SM_calc_flag /* i  : Flag that indicates that it is for SM mode              */
    1353             : )
    1354             : {
    1355             :     float corrL, corrR, ener, mono_i;
    1356             :     int16_t i;
    1357             :     float ener_side, side_i;
    1358             : 
    1359        3804 :     corrL = 0;
    1360        3804 :     corrR = 0;
    1361        3804 :     ener = 1e-6f;
    1362        3804 :     ener_side = 1e-6f;
    1363             : 
    1364             :     /*----------------------------------------------------------------*
    1365             :      * Find the normalized correlation between: left/mono and right/mono based
    1366             :      *----------------------------------------------------------------*/
    1367             : 
    1368        3804 :     if ( tdm_SM_calc_flag )
    1369             :     {
    1370        8333 :         for ( i = 0; i < len; i++ )
    1371             :         {
    1372        8320 :             mono_i = ( L[i] - R[i] ) / 2.0f;
    1373        8320 :             corrL += fabsf( L[i] ) * fabsf( mono_i );
    1374        8320 :             corrR += fabsf( R[i] ) * fabsf( mono_i );
    1375        8320 :             ener += mono_i * mono_i;
    1376        8320 :             side_i = ( L[i] + R[i] ) / 2.0f;
    1377        8320 :             ener_side += side_i * side_i;
    1378             :         }
    1379             :     }
    1380             :     else
    1381             :     {
    1382     2520591 :         for ( i = 0; i < len; i++ )
    1383             :         {
    1384     2516800 :             mono_i = ( L[i] + R[i] ) / 2.0f;
    1385     2516800 :             corrL += L[i] * mono_i;
    1386     2516800 :             corrR += R[i] * mono_i;
    1387     2516800 :             ener += mono_i * mono_i;
    1388     2516800 :             side_i = ( L[i] - R[i] ) / 2.0f;
    1389     2516800 :             ener_side += side_i * side_i;
    1390             :         }
    1391             :     }
    1392             : 
    1393        3804 :     *ic_Lm = corrL / ener;
    1394        3804 :     *ic_Rm = corrR / ener;
    1395             : 
    1396        3804 :     *es_em = 10 * ( log10f( sqrtf( ener_side / len ) ) - log10f( sqrtf( ener / len ) ) );
    1397             : 
    1398        3804 :     return;
    1399             : }
    1400             : 
    1401             : 
    1402             : /*-------------------------------------------------------------------*
    1403             :  * Function stereo_smooth_LR_transition()
    1404             :  *
    1405             :  *-------------------------------------------------------------------*/
    1406             : 
    1407             : /*! r: smoothed position */
    1408         139 : static int16_t stereo_smooth_LR_transition(
    1409             :     int16_t *tdm_prev_stable_idx,           /* i/o: Previous Transmitted ratio index                */
    1410             :     int16_t *tdm_ratio_transition_mov_flag, /* i/o: Flag that indicates that L-R energy is changing */
    1411             :     int16_t tdm_last_ratio_idx,             /* i  : last TDM ratio index                            */
    1412             :     int16_t *tdm_prev_desired_idx,          /* i/o: Previous Transmitted ratio index                */
    1413             :     int16_t *tdm_ratio_transition_cnt,      /* i/o: Counter                                         */
    1414             :     const int16_t tdm_SM_flag,              /* i  : channel combination scheme flag for current frame */
    1415             :     int16_t desired_idx                     /* i  : desired final position                          */
    1416             : )
    1417             : {
    1418             :     int16_t idx;
    1419             : 
    1420         139 :     if ( tdm_SM_flag == 1 )
    1421             :     {
    1422          13 :         desired_idx = 15;
    1423             :     }
    1424             : 
    1425         139 :     if ( desired_idx != *tdm_prev_stable_idx )
    1426             :     {
    1427         128 :         *tdm_ratio_transition_mov_flag = 1;
    1428             :     }
    1429             : 
    1430         139 :     if ( *tdm_ratio_transition_mov_flag == 1 )
    1431             :     {
    1432         130 :         if ( desired_idx != *tdm_prev_desired_idx )
    1433             :         {
    1434         126 :             *tdm_prev_stable_idx = tdm_last_ratio_idx;
    1435         126 :             *tdm_ratio_transition_cnt = 0;
    1436             :         }
    1437             : 
    1438         130 :         *tdm_ratio_transition_cnt += 4;
    1439         130 :         if ( desired_idx < *tdm_prev_stable_idx - 2 )
    1440             :         {
    1441          39 :             idx = *tdm_prev_stable_idx - *tdm_ratio_transition_cnt;
    1442          39 :             idx = max( desired_idx, idx );
    1443             :         }
    1444          91 :         else if ( desired_idx > *tdm_prev_stable_idx + 2 )
    1445             :         {
    1446          73 :             idx = *tdm_prev_stable_idx + *tdm_ratio_transition_cnt;
    1447          73 :             idx = min( desired_idx, idx );
    1448             :         }
    1449             :         else
    1450             :         {
    1451          18 :             idx = desired_idx;
    1452             :         }
    1453             :     }
    1454             :     else
    1455             :     {
    1456           9 :         idx = desired_idx;
    1457             :     }
    1458             : 
    1459         139 :     *tdm_prev_desired_idx = desired_idx;
    1460             : 
    1461         139 :     return idx;
    1462             : }

Generated by: LCOV version 1.14