LCOV - code coverage report
Current view: top level - lib_lc3plus - pc_apply_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 115 0.0 %
Date: 2025-08-23 01:22:27 Functions: 0 2 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 "constants.h"
      12             : #include "functions.h"
      13             : 
      14             : #ifdef ENABLE_HR_MODE
      15             : static Word16 getScaleFactor32_withNegativeScaling(Word32 *data32, Word16 dataLen);
      16             : #else
      17             : static Word16 getScaleFactor16_withNegativeScaling(Word16 *data16, Word16 dataLen);
      18             : #endif
      19             : 
      20             : 
      21           0 : void processPCapply_fx(Word16 yLen, Word16 q_old_res_fx[], Word16 *q_old_res_fx_exp,
      22             : #ifdef ENABLE_HR_MODE
      23             :                        Word32 q_res_fx[],
      24             : #else
      25             :                        Word16 q_res_fx[],
      26             : #endif
      27             :                        Word16 q_old_d_fx[], Word16 spec_inv_idx, Word16 *fac, Word16 *fac_e, Word32 q_d_fx[],
      28             :                        Word16 *q_fx_exp, Word16 gg_idx, Word16 gg_idx_off, Word16 prev_gg, Word16 prev_gg_e,
      29             :                        Word16 *pc_nbLostFramesInRow)
      30             : {
      31             :     Counter i;
      32             :     Word16  s, s2, s3, c, tmp16, tmp16_2, inv_gain, thr;
      33             :     Word32  ener_curr, ener_prev, mean_nrg_high, mean_nrg_low;
      34             :     Word16  global_gain, global_gain_e, gg2, gg2_e, prev_gg2, prev_gg2_e;
      35             :     Word32  tmp32, ener_curr_gg2, ener_prev_gg2;
      36             :     Word16 fac_local, fac_local_e;
      37             : 
      38             : #ifdef DYNMEM_COUNT
      39             :     struct _dynmem
      40             :     {
      41             :         Counter i;
      42             :         Word16  s, s2, s3, c, tmp16, tmp16_2, inv_gain, thr;
      43             :         Word32  ener_curr, ener_prev, mean_nrg_high, mean_nrg_low;
      44             :         Word16  global_gain, global_gain_e, gg2, gg2_e, prev_gg2, prev_gg2_e;
      45             :         Word32  tmp32, ener_curr_gg2, ener_prev_gg2;
      46             :         Word16  fac_local, fac_local_e;
      47             :     };
      48             :     Dyn_Mem_In("processPCapply_fx", sizeof(struct _dynmem));
      49             : #endif
      50             : 
      51           0 :     assert(spec_inv_idx >= 0);
      52             : 
      53           0 :     *pc_nbLostFramesInRow = add(*pc_nbLostFramesInRow, 1);
      54             : 
      55           0 :     tmp32         = L_shl_pos(L_mult0(add(gg_idx, gg_idx_off), 0x797D), 7);
      56           0 :     global_gain_e = add(extract_l(L_shr_pos(tmp32, 25)), 1);
      57           0 :     global_gain   = round_fx(BASOP_Util_InvLog2_lc3plus(L_or(tmp32, 0xFE000000)));
      58             : 
      59             :     /** Calculate rescaling factor **/
      60             : 
      61             :     /*  mean_nrg_low  = mean(q_d_prev(1:spec_inv_idx-1).^2);
      62             :         mean_nrg_high = mean(q_d_prev(spec_inv_idx:end).^2); */
      63           0 :     s = getScaleFactor16(q_old_d_fx, yLen);
      64             : 
      65           0 :     mean_nrg_low = 0;
      66           0 :     move32();
      67           0 :     FOR (i = 0; i < spec_inv_idx; i++)
      68             :     {
      69           0 :         tmp16        = shl_sat(q_old_d_fx[i], sub(s, 4));
      70           0 :         mean_nrg_low = L_mac0(mean_nrg_low, tmp16, tmp16); /* exp = 2s - 8 */
      71             :     }
      72             : 
      73           0 :     mean_nrg_high = 0;
      74           0 :     move32();
      75           0 :     FOR (i = spec_inv_idx; i < yLen; i++)
      76             :     {
      77           0 :         tmp16         = shl_sat(q_old_d_fx[i], sub(s, 4));
      78           0 :         mean_nrg_high = L_mac0(mean_nrg_high, tmp16, tmp16); /* exp = 2s - 8 */
      79             :     }
      80             : 
      81           0 :     IF (sub(spec_inv_idx, sub(yLen, spec_inv_idx)) < 0)
      82             :     {
      83           0 :         c             = div_s(spec_inv_idx, sub(yLen, spec_inv_idx));
      84           0 :         mean_nrg_high = Mpy_32_16_lc3plus(mean_nrg_high, c); /* exp = 2s - 8 */
      85             :     }
      86             :     ELSE
      87             :     {
      88           0 :         c            = div_s(sub(yLen, spec_inv_idx), spec_inv_idx);
      89           0 :         mean_nrg_low = Mpy_32_16_lc3plus(mean_nrg_low, c); /* exp = 2s - 8 */
      90             :     }
      91             : 
      92             :     /* ener_prev     = sum(q_old_res(1:spec_inv_idx-1).^2);
      93             :        ener_curr     = sum(    q_res(1:spec_inv_idx-1).^2); */
      94           0 :     s         = getScaleFactor16(q_old_res_fx, spec_inv_idx);
      95           0 :     ener_prev = 0;  move32();
      96           0 :     FOR (i = 0; i < spec_inv_idx; i++)
      97             :     {
      98           0 :         tmp16     = shl_sat(q_old_res_fx[i], sub(s, 4));
      99           0 :         ener_prev = L_mac0(ener_prev, tmp16, tmp16); /* exp = - (2s - 8 - 2**q_old_res_fx_exp) */
     100             :     }
     101             : 
     102           0 :     ener_curr = 0;
     103           0 :     move32();
     104             : 
     105             : #ifdef ENABLE_HR_MODE
     106           0 :       s2 = getScaleFactor32_lc3plus(q_res_fx, spec_inv_idx);
     107           0 :       FOR (i = 0; i < spec_inv_idx; i++)
     108             :       {
     109           0 :           tmp16     = extract_h(L_shl_sat(q_res_fx[i], sub(s2, 4)));
     110           0 :           ener_curr = L_mac0(ener_curr, tmp16, tmp16); /* exp = - (2s2 - 8) */
     111             :       }
     112           0 :       s2 = s2 - 16;
     113             : #else
     114             :     s2        = getScaleFactor16(q_res_fx, spec_inv_idx);
     115             :     FOR (i = 0; i < spec_inv_idx; i++)
     116             :     {
     117             :         tmp16     = shl_sat(q_res_fx[i], sub(s2, 4));
     118             :         ener_curr = L_mac0(ener_curr, tmp16, tmp16); /* exp = - (2s2 - 8) */
     119             :     }
     120             : #endif
     121             :     
     122             : 
     123           0 :     s  = shl(sub(s, *q_old_res_fx_exp), 1);
     124           0 :     s2 = shl(s2, 1);
     125           0 :     s3        = s_max(s, s2);
     126           0 :     ener_prev = L_shr_sat(ener_prev, sub(s3, s2));
     127           0 :     ener_curr = L_shr_sat(ener_curr, sub(s3,  s));
     128             : 
     129             :     /* fac = 1; */
     130           0 :     *fac = 1;
     131             :     /* if ener_prev > 0 */
     132           0 :     IF ( ener_prev > 0 )
     133             :     {
     134             :         /* fac = sqrt(ener_curr/ener_prev); */
     135           0 :         s       = getScaleFactor32_lc3plus(&ener_prev, 1);
     136           0 :         s2      = getScaleFactor32_lc3plus(&ener_curr, 1);
     137           0 :         s3      = s_min(s, s2);
     138           0 :         tmp16   = extract_h(L_shl_sat(ener_curr, s3));
     139           0 :         tmp16_2 = extract_h(L_shl_sat(ener_prev, s3));
     140             :         
     141           0 :         *fac_e = 0;  move16();
     142           0 :         if ( tmp16_2 == 0) {
     143           0 :             tmp16_2 = 32767;  move16();
     144           0 :             *fac_e = 15;  move16();
     145             :         } else {
     146           0 :             tmp16_2 = Inv16_lc3plus(tmp16_2, fac_e);
     147             :         }
     148             :         
     149           0 :         *fac = mult(tmp16, tmp16_2);
     150             :         
     151           0 :         IF (sub(*fac, 32767) < 0)
     152             :         {
     153           0 :             *fac = Sqrt16_lc3plus(*fac, fac_e); move16();
     154             :         }
     155             :     }
     156             : 
     157             :     /* fac_local = fac; */
     158           0 :     fac_local = *fac;
     159           0 :     fac_local_e = *fac_e;
     160             : 
     161             :     /* if (mean_nrg_low > mean_nrg_high) && (ener_prev * prev_gg^2 > ener_curr * gg^2) */
     162           0 :     prev_gg2   = mult(prev_gg, prev_gg);
     163           0 :     prev_gg2_e = shl(prev_gg_e, 1);
     164           0 :     ener_prev_gg2 = Mpy_32_16_lc3plus(ener_prev, prev_gg2); /* exp =  prev_gg2_e */
     165             : 
     166           0 :     gg2   = mult(global_gain, global_gain);
     167           0 :     gg2_e = shl(global_gain_e, 1);
     168           0 :     ener_curr_gg2 = Mpy_32_16_lc3plus(ener_curr, gg2);      /* exp =  gg2_e */
     169             : 
     170           0 :     s3            = s_max(prev_gg2_e, gg2_e);
     171           0 :     ener_prev_gg2 = L_shr_sat(ener_prev_gg2, sub(s3, prev_gg2_e));
     172           0 :     ener_curr_gg2 = L_shr_sat(ener_curr_gg2, sub(s3, gg2_e));
     173             : 
     174             : 
     175           0 :     test();
     176           0 :     IF ( (L_sub(mean_nrg_low, mean_nrg_high) <= 0) || (L_sub(ener_prev_gg2, ener_curr_gg2) <= 0) )
     177             :     {
     178             :         /* fac = prev_gg/gg; */
     179           0 :         s = global_gain_e;  move16();
     180           0 :         inv_gain  = Inv16_lc3plus(global_gain, &s);
     181           0 :         fac_local = mult(prev_gg, inv_gain);
     182           0 :         fac_local_e = add(s, prev_gg_e);
     183             :     }
     184             : 
     185             :     /* write synthesized samples */
     186           0 :     *q_old_res_fx_exp = add(*q_old_res_fx_exp, fac_local_e);
     187           0 :     thr               = shl_sat(20480, sub(-15, *q_old_res_fx_exp));
     188           0 :     FOR (i = spec_inv_idx; i < yLen; i++)
     189             :     {
     190           0 :         q_res_fx[i] = extract_h(L_mult(q_old_res_fx[i]  /* exp = q_old_res_fx_exp' */, fac_local /* exp = fac_e */)); /* exp = q_old_res_fx_exp */
     191             : 
     192           0 :         IF (sub(abs_s(q_res_fx[i]), thr) < 0)
     193             :         {
     194           0 :             q_res_fx[i] = 0;
     195           0 :             move16();
     196             :         }
     197             :     }
     198             : 
     199             : #ifdef ENABLE_HR_MODE
     200           0 :     s  = getScaleFactor32_withNegativeScaling(&q_res_fx[0], spec_inv_idx)  - 16; /* exp = 0 */
     201           0 :     s2 = getScaleFactor32_withNegativeScaling(&q_res_fx[spec_inv_idx],
     202           0 :                                               sub(yLen, spec_inv_idx)) - 16; /* exp = q_old_res_fx_exp */
     203             : #else
     204             :     s  = getScaleFactor16_withNegativeScaling(&q_res_fx[0], spec_inv_idx); /* exp = 0 */
     205             :     s2 = getScaleFactor16_withNegativeScaling(&q_res_fx[spec_inv_idx],
     206             :                                               sub(yLen, spec_inv_idx)); /* exp = q_old_res_fx_exp */
     207             : #endif
     208             :                                               
     209           0 :     s3 = add(s, *q_old_res_fx_exp);
     210           0 :     IF (sub(s3, s2) > 0)
     211             :     {
     212           0 :         tmp16 = sub(s3, s2);
     213           0 :         s     = sub(s, tmp16);
     214           0 :         s3    = sub(s3, tmp16);
     215             :     }
     216           0 :     *q_fx_exp = sub(15, s);
     217           0 :     move16();
     218             :     
     219             : #ifdef ENABLE_HR_MODE
     220           0 :     s = add(s, 16);
     221           0 :     s3 = add(s3, 16);
     222             : #endif
     223             : 
     224           0 :     s = s_max(s, -31);
     225           0 :     s = s_min(s, 31);
     226           0 :     s3 = s_max(s3, -31);
     227           0 :     s3 = s_min(s3, 31);
     228             : 
     229           0 :     FOR (i = 0; i < spec_inv_idx; i++)
     230             :     {
     231             : #ifdef ENABLE_HR_MODE
     232           0 :         q_d_fx[i] = L_shl(q_res_fx[i], s);
     233             : #else
     234             :         q_d_fx[i] = L_shl(L_deposit_h(q_res_fx[i]), s);
     235             : #endif
     236           0 :         move32();
     237             :     }
     238           0 :     FOR (; i < yLen; i++)
     239             :     {
     240             : #ifdef ENABLE_HR_MODE
     241           0 :         q_d_fx[i] = L_shl(q_res_fx[i], s3);
     242             : #else
     243             :         q_d_fx[i] = L_shl(L_deposit_h(q_res_fx[i]), s3);
     244             : #endif
     245           0 :         move32();
     246             :     }
     247             : 
     248             : 
     249             : #ifdef DYNMEM_COUNT
     250             :     Dyn_Mem_Out();
     251             : #endif
     252           0 : }
     253             : 
     254             : #ifndef ENABLE_HR_MODE
     255             : static Word16 getScaleFactor16_withNegativeScaling(Word16 *data16, Word16 dataLen)
     256             : {
     257             :     Counter i;
     258             :     Dyn_Mem_Deluxe_In(Word16 tmp, shift; Word16 x_min, x_max;);
     259             : 
     260             :     x_max = 0;
     261             :     move16();
     262             :     x_min = 0;
     263             :     move16();
     264             : 
     265             :     FOR (i = 0; i < dataLen; i++)
     266             :     {
     267             :         if (data16[i] > 0)
     268             :             x_max = s_max(x_max, data16[i]);
     269             :         if (data16[i] < 0)
     270             :             x_min = s_min(x_min, data16[i]);
     271             :     }
     272             : 
     273             :     tmp   = s_max(x_max, negate(x_min));
     274             :     shift = norm_s(tmp);
     275             :     if (tmp == 0)
     276             :     {
     277             :         shift = 15;
     278             :         move16();
     279             :     }
     280             : 
     281             :     Dyn_Mem_Deluxe_Out();
     282             : 
     283             :     return shift;
     284             : }
     285             : 
     286             : #else
     287           0 : static Word16 getScaleFactor32_withNegativeScaling(Word32 *data32, Word16 dataLen)
     288             : {
     289             :     Counter i;
     290             :     Dyn_Mem_Deluxe_In(Word32 tmp, shift; Word32 x_min, x_max;);
     291             : 
     292           0 :     x_max = L_add(0, 0);
     293           0 :     x_min = L_add(0, 0);
     294             : 
     295           0 :     FOR (i = 0; i < dataLen; i++)
     296             :     {
     297           0 :         if (data32[i] >= 0)
     298           0 :             x_max = L_max(x_max, data32[i]);
     299           0 :         if (data32[i] < 0)
     300           0 :             x_min = L_min(x_min, data32[i]);
     301             :     }
     302             : 
     303           0 :     tmp   = L_max(x_max, L_negate(x_min));
     304           0 :     shift = norm_l(tmp);
     305           0 :     if (tmp == 0)
     306             :     {
     307           0 :         shift = 31;
     308           0 :         move16();
     309             :     }
     310             : 
     311             :     Dyn_Mem_Deluxe_Out();
     312             : 
     313           0 :     return shift;
     314             : }
     315             : #endif

Generated by: LCOV version 1.14