LCOV - code coverage report
Current view: top level - lib_lc3plus - plc_update_aft_imdct_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 116 0.0 %
Date: 2025-08-23 01:22:27 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             : *                        ETSI TS 103 634 V1.5.1                               *
       3             : *              Low Complexity Communication Codec Plus (LC3plus)              *
       4             : *                                                                             *
       5             : * Copyright licence is solely granted through ETSI Intellectual Property      *
       6             : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
       7             : * estoppel or otherwise.                                                      *
       8             : ******************************************************************************/
       9             : 
      10             : #include "defines.h"
      11             : #include "functions.h"
      12             : 
      13             : static void processPLCcomputeStabFac(Word16 scf_q[], Word16 old_scf_q[], Word16 prev_bfi, Word16 *stab_fac);
      14             : 
      15           0 : void processPLCUpdateAfterIMDCT_fx(Word16 x_fx[], Word16 q_fx_exp, Word16 concealMethod, Word16 xLen, Word16 fs_idx,
      16             :    Word16 *nbLostFramesInRow, Word16 *prev_prev_bfi, Word16 *prev_bfi, Word16 bfi, Word16 scf_q[],
      17             :    Word16 *ns_cum_alpha, AplcSetup *plcAd)
      18             : {
      19             :    Word16  oldLen, usedHistlen;
      20             :    Word16  scale_fac_old, scale_fac_new, q_theo_new_old, q_theo_new_new, q_new, shift_old, shift_new;
      21             :    Word16 frontLen, pastLen;
      22             :    Word16 marginOldPast;
      23             :    Word16   marginNewXlen, marginOldFront;
      24             : 
      25             : #ifdef DYNMEM_COUNT
      26             :    Dyn_Mem_In("processPLCUpdateAfterIMDCT_fx", sizeof(struct {
      27             :       Word16  oldLen, usedHistlen;
      28             :       Counter i;
      29             :       Word16 scale_fac_old, scale_fac_new, q_theo_new_old, q_theo_new_new, q_new, shift_old, shift_new;
      30             :       Word16 frontLen, pastLen;
      31             :       Word16 marginOldPast;
      32             :       Word16 scale_fac_old_dual;
      33             :       Word16   marginNewXlen, marginOldFront;
      34             :    }));
      35             : #endif
      36             : 
      37             : 
      38             : 
      39             :     
      40             : #ifdef WMOPS
      41             :       push_wmops("processPLCUpdateAfterIMDCT ");
      42             : #endif
      43             :    
      44             :   
      45           0 :    if (plcAd)
      46             :    {
      47             :       /* for  short NB frames(2.5 ms)  TDC-filtering  requires  more PCM samples than  the plc_xcorr function */
      48           0 :       usedHistlen = plcAd->max_len_pcm_plc;
      49             : 
      50             : 
      51           0 :       logic16();
      52           0 :       IF( (sub(bfi,1) == 0) && sub(concealMethod, LC3_CON_TEC_PHASE_ECU) == 0 && xLen == (Word16)(((double)LprotSzPtr[fs_idx])*0.625))
      53             :       {   /* % reduced buffering update length during concealment method 2 as Xsav_fx is stored in the  joint  q_old_fx and pcmbufHist buffer */
      54           0 :          usedHistlen = sub(usedHistlen, sub(LprotSzPtr[fs_idx], s_min(MAX_BW_BIN, xLen)));
      55           0 :          ASSERT(xLen == (Word16)(((double)LprotSzPtr[fs_idx])*0.625)); /*/ only enter here for 10 ms cases */
      56             : 
      57             :          /* actually one can  select to always update xLen(10 ms)  less  samples of x_old_tot,  also in  TDC-PLC bfi frames ,, and for PhECU.PLC  */
      58             :       }
      59           0 :       oldLen = sub(usedHistlen, xLen);
      60             : 
      61             :       /* update ltpf-free pcm history buffer for TD-PLC */
      62             : 
      63           0 :       basop_memmove(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen],
      64           0 :          &plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen + xLen], oldLen * sizeof(Word16));
      65             : 
      66           0 :       basop_memcpy(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - xLen], &x_fx[0], xLen * sizeof(Word16));
      67             : 
      68             : #ifdef ENABLE_HR_MODE
      69           0 :       frontLen = 0;
      70           0 :       IF (sub(fs_idx, 5) < 0)
      71             : #endif
      72             :       {
      73           0 :           frontLen = sub(LprotSzPtr[fs_idx], xLen);  /*16-10 =  6ms  of the  prev_synth/xfp part  */
      74             :       }
      75           0 :       pastLen = sub(oldLen, frontLen);          /* ~11.8 ms*/
      76             : 
      77           0 :       marginOldPast = getScaleFactor16_0(&(plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen]), pastLen);
      78           0 :       marginOldFront = getScaleFactor16_0(&(plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen + pastLen]), frontLen);
      79             : 
      80           0 :       scale_fac_old = s_min(marginOldFront, marginOldPast);
      81             :       
      82           0 :       frontLen = 0; move16();
      83           0 :       logic16();  logic16();
      84           0 :       IF(bfi == 1 && *prev_bfi == 0 && sub(concealMethod, LC3_CON_TEC_PHASE_ECU) == 0)
      85             :       {   /* prepare localized margin_xfp value  for a next bad concealment Method 2 frame   */
      86           0 :          frontLen = *nbLostFramesInRow;
      87           0 :          frontLen = add(hamm_len2Tab[fs_idx], shr(hamm_len2Tab[fs_idx], 2)); /*  find margin in the   3.75 ms front part   */
      88           0 :          pastLen = sub(xLen, frontLen);
      89           0 :          scale_fac_new = getScaleFactor16_0(&(x_fx[0]), pastLen);
      90           0 :          marginNewXlen = getScaleFactor16_0(&(x_fx[0]) + pastLen, frontLen); /* for pHEcuprev_synth  in 2nd+  bfi frame */
      91             : 
      92           0 :          scale_fac_new = s_min(scale_fac_new, marginNewXlen);
      93             :       }
      94             :       ELSE
      95             :       { /* prepare margin value for any coming  good frame  or  any coming first bad frame  */
      96             : 
      97           0 :           marginNewXlen = getScaleFactor16_0(&(x_fx[0]),xLen);  /* prevsynth  in first bfi frame */
      98           0 :           scale_fac_new = marginNewXlen; move16();
      99             :       }
     100             : 
     101           0 :       q_theo_new_old = s_max(plcAd->q_fx_old_exp - scale_fac_old, 0);
     102           0 :       q_theo_new_new = s_max(q_fx_exp - scale_fac_new, 0);
     103             : 
     104           0 :       q_new = s_max(q_theo_new_old, q_theo_new_new);
     105             : 
     106           0 :       shift_old = plcAd->q_fx_old_exp - q_new;
     107           0 :       shift_new = q_fx_exp - q_new;
     108             : 
     109           0 :       IF(shift_old != 0)
     110             :       {
     111           0 :          Scale_sig(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - usedHistlen], oldLen, shift_old);
     112           0 :          logic16();
     113           0 :          test();
     114           0 :          IF ((sub(bfi,1) == 0) && (sub(concealMethod, LC3_CON_TEC_TDPLC) == 0))
     115             :          {
     116           0 :             plcAd->harmonicBuf_Q -= shift_old;
     117           0 :             plcAd->tdc_gain_c = L_shl_sat(plcAd->tdc_gain_c, shift_old);
     118             :          }
     119           0 :          move16(); /* count move to static RAM */
     120             : 
     121           0 :          marginOldFront = s_min(16, sub(marginOldFront, shift_old));
     122             :       }
     123           0 :       IF(shift_new)
     124             :       {
     125           0 :          Scale_sig(&plcAd->x_old_tot_fx[plcAd->max_len_pcm_plc - xLen], xLen, shift_new); /* positive shift_new means upshift=less margin  */
     126           0 :          marginNewXlen = s_min(16, sub(marginNewXlen, shift_new));
     127             :       }
     128             : 
     129           0 :       plcAd->q_fx_old_exp = sub(q_fx_exp, shift_new);
     130             : 
     131           0 :       plcAd->PhECU_margin_xfp = s_min(marginNewXlen, marginOldFront);  move16(); /* for pHECU winEncalc xfp energy calculations */
     132           0 :       if (frontLen != 0)
     133             :       {  /* prepare margin value for a first pHECU(16 ms)  or a consecutive bad PhEcu frame (3.75ms)  */
     134           0 :          plcAd->PhECU_margin_xfp = marginNewXlen; move16();
     135             :       }
     136           0 :       if (sub(plcAd->PhECU_margin_xfp, 16) == 0)
     137             :       {
     138           0 :          plcAd->PhECU_margin_xfp = 1;   move16();  /* "1" --> does not rescale the   all-zero vector, inside PhECU  */
     139             :       }
     140             :    }
     141             : 
     142             :    /* Update PLC params */
     143           0 :    IF(sub(bfi, 1) != 0)
     144             :    {
     145             :       /* % reset counters in GF  */
     146           0 :       *nbLostFramesInRow = 0;  move16();
     147           0 :       *ns_cum_alpha = 32767;  move16();
     148             : 
     149           0 :       if (plcAd)
     150             :       {
     151           0 :          basop_memmove(plcAd->old_old_scf_q, plcAd->old_scf_q, M * sizeof(Word16));
     152           0 :          basop_memmove(plcAd->old_scf_q, scf_q, M * sizeof(Word16));
     153             : 
     154             :          /* PLC fullband transient detector setting for non-bfi frames */
     155           0 :          plcAd->PhECU_short_flag_prev = 0;  move16(); /* fullband transient not active   */
     156             :       }
     157             :    }
     158             :  
     159             :    /* values may be {0,1,2} */
     160           0 :    *prev_prev_bfi = *prev_bfi;  move16();
     161           0 :    *prev_bfi = bfi;  move16();
     162             : 
     163             : #ifdef WMOPS
     164             :     pop_wmops();
     165             : #endif
     166             : 
     167             : #ifdef DYNMEM_COUNT
     168             :     Dyn_Mem_Out();
     169             : #endif
     170           0 : }
     171             : 
     172           0 : void processPLCcomputeStabFac_main(Word16 scf_q[], Word16 old_scf_q[], Word16 old_old_scf_q[], Word16 bfi, Word16 prev_bfi,
     173             :                                    Word16 prev_prev_bfi, Word16 *stab_fac)
     174             : {
     175           0 :     IF (sub(bfi, 1) == 0)
     176             :     {
     177           0 :         IF (sub(prev_bfi, 1) != 0)
     178             :         {
     179           0 :             processPLCcomputeStabFac(old_scf_q, old_old_scf_q, prev_prev_bfi, stab_fac);
     180             :         }
     181             :     }
     182           0 :     ELSE IF(sub(bfi, 2) == 0)
     183             :     {
     184           0 :         processPLCcomputeStabFac(scf_q, old_scf_q, prev_bfi, stab_fac);
     185             :     }
     186           0 : }
     187             : 
     188           0 : static void processPLCcomputeStabFac(Word16 scf_q[], Word16 old_scf_q[], Word16 prev_bfi, Word16 *stab_fac)
     189             : {
     190             :     Counter i;
     191             :     Word32  tmp32;
     192             :     Word16  d;
     193             : 
     194             : #ifdef DYNMEM_COUNT
     195             :     Dyn_Mem_In("calculateStabFac", sizeof(struct {
     196             :                    Counter i;
     197             :                    Word32  tmp32;
     198             :                    Word16  d;
     199             :                }));
     200             : #endif
     201             : 
     202             :     /* calculate stability factor */
     203           0 :     IF (sub(prev_bfi, 1) == 0)
     204             :     {
     205           0 :         *stab_fac = 26214; move16();
     206             :     }
     207             :     ELSE
     208             :     {
     209           0 :         tmp32 = 0; move32();
     210           0 :         FOR (i = 0; i < M; i++)
     211             :         {
     212           0 :             d     = sub(scf_q[i], old_scf_q[i]);
     213           0 :             tmp32 = L_mac_sat(tmp32, d, d);
     214             :         }
     215           0 :         tmp32 = L_shl_sat(tmp32, 3);
     216           0 :         IF (tmp32 > 0x7D000000 /*1.25*25*/)
     217             :         {
     218           0 :             *stab_fac = 0; move16();
     219             :         }
     220           0 :         ELSE IF (tmp32 < 0x19003E82 /*0.25*25*/)
     221             :         {
     222           0 :             *stab_fac = 0x7FFF; move16();
     223             :         }
     224             :         ELSE
     225             :         {
     226           0 :             tmp32     = L_shl_pos(L_sub(0x50000000 /*1.25/2*/, Mpy_32_16_lc3plus(tmp32, 0x51EC /*16/25*/)), 1);
     227           0 :             *stab_fac = round_fx(tmp32); move16();
     228             :         }
     229             :     }
     230             : 
     231             : #ifdef DYNMEM_COUNT
     232             :     Dyn_Mem_Out();
     233             : #endif
     234           0 : }
     235             : 
     236           0 : void processPLCUpdateXFP_w_E_hist_fx(Word16 prev_bfi, Word16 bfi, Word16 *xfp_fx, Word16 xfp_exp_fx, Word16 margin_xfp, 
     237             :                                      Word16 fs_idx,
     238             :                                      Word32 *L_oold_xfp_w_E_fx, Word16 *oold_xfp_w_E_exp_fx, 
     239             :                                      Word32 *L_old_xfp_w_E_fx, Word16 *old_xfp_w_E_exp_fx,
     240             :                                     
     241             :                                      Word16 *oold_Ltot_exp_fx ,Word16 *old_Ltot_exp_fx )    
     242             : 
     243             : {
     244             :     Word32 L_tot  ; 
     245             :     Word16 dn_scale, exp_shift;
     246             :     Word16 used_xfp_exp_fx;
     247             :     Word16 exp_out  ; 
     248             : 
     249             : #ifdef DYNMEM_COUNT
     250             :     Dyn_Mem_In("PLCUpdateXFP_w_E_hist", sizeof(struct {  
     251             :         Word32 L_tot;
     252             :         Word16 dn_scale, exp_shift;
     253             :         Word16 used_xfp_exp_fx;
     254             :         Word16 exp_out; 
     255             :     }));
     256             : #endif
     257             : #ifdef WMOPS
     258             :     push_wmops("PhECU::UpdateXfp_w_E_hist_fx");
     259             : #endif
     260             : 
     261           0 :     IF (sub(bfi,1) != 0)
     262             :     {
     263             : 
     264           0 :         if (sub(prev_bfi,1) == 0)
     265             :         {
     266             :           /* only a single historic frame available in the next  frame  
     267             :                , force artifical update of oold energy to be the same as old */
     268           0 :            *old_xfp_w_E_exp_fx = LTOT_INIT_FLAG ;  move16();
     269             :         }
     270             : 
     271             :         /* Time shift energy state and xfp exp */ 
     272           0 :         IF (sub_sat(*old_xfp_w_E_exp_fx, LTOT_INIT_FLAG ) ==  0) 
     273             :         {
     274           0 :             *L_oold_xfp_w_E_fx   =   LTOT_MIN_MAN  ;                             move32();   
     275           0 :             *oold_xfp_w_E_exp_fx =  UNINIT_OR_UNSAFE_OOLD_SENTINEL ; move16();  
     276             :         }
     277             :         ELSE
     278             :         {
     279           0 :             *L_oold_xfp_w_E_fx   = *L_old_xfp_w_E_fx;   move32();  /* regular update */
     280           0 :             *oold_xfp_w_E_exp_fx = *old_xfp_w_E_exp_fx; move16();
     281             :         }
     282             : 
     283             :         /* Time shift L_tot energy state and L_tot_exp  */
     284           0 :         IF (sub_sat(*old_Ltot_exp_fx, LTOT_INIT_FLAG ) ==  0) 
     285             :         {
     286           0 :             *L_oold_xfp_w_E_fx   =   LTOT_MIN_MAN  ;                             move32();   
     287           0 :             *oold_Ltot_exp_fx    =   UNINIT_OR_UNSAFE_OOLD_SENTINEL ;    move16();  
     288             :         }
     289             :         ELSE
     290             :         {
     291           0 :             *L_oold_xfp_w_E_fx   = *L_old_xfp_w_E_fx;   move32();  /* regular update */
     292           0 :             *oold_Ltot_exp_fx    = *old_Ltot_exp_fx;        move16();
     293             :         }
     294             : 
     295             :        
     296           0 :         dn_scale        = e_tot_headroom[fs_idx]; /* allowed minimum dn_scale for a max upshifted signal */
     297           0 :         used_xfp_exp_fx = xfp_exp_fx;      
     298             :  
     299           0 :         IF( margin_xfp > 0 ) /* xfp_fx was normalized on a larger area than 16ms part of  pcmBuffer  */
     300             :         {     
     301           0 :              ASSERT(bfi !=1) ; /* if bfi was set the margin_xfp  does not reflect the correct 16ms part of pcm_buf hist, prev_synth */
     302           0 :              dn_scale =  s_max(0, sub(e_tot_headroom[fs_idx], margin_xfp)); 
     303             : 
     304           0 :              exp_shift = sub(e_tot_headroom[fs_idx], dn_scale);
     305           0 :              used_xfp_exp_fx = sub(xfp_exp_fx, exp_shift); /* the virtual change of the xfp_buffer due to reduced downscaling in L_tot calc  */
     306             :         }
     307             :         
     308             :         /* use semifixed dn_scale as adjusted by margin_xfp in 16 ms region */
     309           0 :         exp_out = xfp_exp_fx;     move16();
     310           0 :         L_tot = winEnCalc(xfp_fx, dn_scale , PhECU_wins[fs_idx][0], rectLengthTab[fs_idx], hamm_len2Tab[fs_idx], &exp_out );
     311             :            
     312           0 :         *L_old_xfp_w_E_fx   = L_tot;      move32();
     313             : 
     314           0 :         *old_xfp_w_E_exp_fx = used_xfp_exp_fx   ;  move16();   
     315             :        /* this now needs to be in Q1 , used_fx_exp , (exp_out-1-2*e_tot_headroom[fs_idx])/2  */
     316             : 
     317           0 :         *old_Ltot_exp_fx  = exp_out;  /* new proper _Ltot value from winEnCalc function */ 
     318             : 
     319             :        
     320             :          /* use true Word32 exponent of L_tot */
     321             :             
     322             : 
     323             :         /* restart oold and old from same  state for init or prevBFI cases  */   
     324           0 :         logic16();
     325           0 :         IF (sub_sat(*oold_xfp_w_E_exp_fx, UNINIT_OR_UNSAFE_OOLD_SENTINEL)  <= 0  ||  /* old xfp_Exp */
     326             :             sub_sat(*oold_Ltot_exp_fx, UNINIT_OR_UNSAFE_OOLD_SENTINEL)  <= 0     )    /* new L_tot_exp */
     327             :         {
     328           0 :             *L_oold_xfp_w_E_fx   = L_tot;       move32();
     329           0 :             *oold_xfp_w_E_exp_fx = used_xfp_exp_fx;  move16();  
     330           0 :             *oold_Ltot_exp_fx    = *old_Ltot_exp_fx;     /* use   Ltot exp value */ 
     331             :         }
     332             :     }
     333             : 
     334             : #ifdef WMOPS
     335             :     pop_wmops();
     336             : #endif
     337             : #ifdef DYNMEM_COUNT
     338             :     Dyn_Mem_Out();
     339             : #endif
     340           0 : }
     341             : 
     342             : 
     343             : 

Generated by: LCOV version 1.14