LCOV - code coverage report
Current view: top level - lib_lc3plus - ltpf_coder_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 161 0.0 %
Date: 2025-08-23 01:22:27 Functions: 0 1 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 "functions.h"
      11             : 
      12             : /*************************************************************************/
      13             : 
      14             : 
      15           0 : void process_ltpf_coder_fx(Word16 *bits, Word16 ol_pitch, Word16 ltpf_enable, Word16 *mem_in_exp, Word16 mem_in[],
      16             :                            Word16 mem_in_len, Word16 param[], Word16 *xin, Word16 len, Word16 *mem_normcorr,
      17             :                            Word16 *mem_mem_normcorr, Word16 ol_normcorr, Word16 *mem_ltpf_on, Word16 *mem_ltpf_pitch,
      18             :                            Word16 xin_exp, Word16 frame_dms, Word8 *scratchBuffer
      19             :                            , Word16 hrmode
      20             : )
      21             : {
      22             :     Word16  pitch_index, scale0, scale1, scale2, *x, x_exp, shift, prod_exp, ltpf_pitch;
      23             :     Word32  L_tmp, cor_max32, sum0, sum1, sum2, prod, inv;
      24             :     Word32 *ac32;
      25             :     Word16 *ac, *currFrame, *predFrame;
      26             :     Word16  min_pitch, max_pitch, ac_min_pitch, ac_max_pitch, ac_max;
      27             :     Word16  pitch, pitch_res, min_pitch_fr, pitch_int, pitch_fr, norm_corr, ltpf_active;
      28             :     Counter n, m, fr;
      29             :     Word16  tmp, acflen;
      30             : 
      31             : #ifdef DYNMEM_COUNT
      32             :     Dyn_Mem_In("process_ltpf_coder_fx", sizeof(struct {
      33             :         Word16  pitch_index, scale0, scale1, scale2, *x, x_exp, shift, prod_exp, ltpf_pitch;
      34             :         Word32  L_tmp, cor_max32, sum0, sum1, sum2, prod, inv;
      35             :         Word32 *ac32;
      36             :         Word16 *ac, *currFrame, *predFrame;
      37             :         Word16  min_pitch, max_pitch, ac_min_pitch, ac_max_pitch, ac_max;
      38             :         Word16  pitch, pitch_res, min_pitch_fr, pitch_int, pitch_fr, norm_corr, ltpf_active;
      39             :         Counter n, m, fr;
      40             :         Word16  tmp, acflen;
      41             :      }));
      42             : #endif
      43             : 
      44             : 
      45             : 
      46           0 :     ac32      = (Word32 *)scratchAlign(scratchBuffer, 0);                         /* Size = 4 * 17 = 68 bytes;   */
      47           0 :     ac        = (Word16 *)scratchAlign(ac32, sizeof(*ac32) * 17);                 /* Size = 2 * 17 = 34 bytes    */
      48           0 :     currFrame = (Word16 *)scratchAlign(scratchBuffer, 0);                         /* Size = 2 * 128 = 256 bytes  */
      49           0 :     predFrame = (Word16 *)scratchAlign(currFrame, sizeof(*currFrame) * LEN_12K8); /* Size = 2 * 128 = 256 bytes  */
      50             :     /* Buffers 'overlap' since they are not used at the same time */              /* Total size used = 512 bytes */
      51             : 
      52           0 :     ltpf_active = 0; move16();
      53           0 :     norm_corr   = 0; move16();
      54             : 
      55             :     /* Input buffer */
      56           0 :     x = mem_in + mem_in_len;
      57             : 
      58           0 :     basop_memmove(x, xin, (len + 1) * sizeof(Word16));
      59             : 
      60           0 :     ASSERT(mem_in_len + len + 1 <= LTPF_MEMIN_LEN + LEN_12K8 + 1);
      61             : 
      62             :     /* Scaling */
      63           0 :     scale0      = sub(getScaleFactor16_0(mem_in, mem_in_len), 3);
      64           0 :     *mem_in_exp = sub(*mem_in_exp, scale0); move16();
      65           0 :     scale1      = sub(getScaleFactor16_0(x, len + 1), 3);
      66           0 :     x_exp       = sub(xin_exp, scale1);
      67           0 :     scale2      = sub(*mem_in_exp, x_exp);
      68           0 :     IF (scale2 > 0)
      69             :     {
      70           0 :         Scale_sig(x, len + 1, sub(scale1, scale2));
      71           0 :         Scale_sig(mem_in, mem_in_len, scale0);
      72           0 :         x_exp = *mem_in_exp; move16();
      73             :     }
      74             :     ELSE
      75             :     {
      76           0 :         Scale_sig(x, len + 1, scale1);
      77           0 :         Scale_sig(mem_in, mem_in_len, add(scale0, scale2));
      78           0 :         *mem_in_exp = x_exp; move16();
      79             :     }
      80             : 
      81           0 :     Word32 normCorrTh = 0; 
      82           0 :     if (hrmode) {
      83           0 :         normCorrTh = 13107;
      84             :     } else {
      85           0 :         normCorrTh = 19660;
      86             :     }
      87             : 
      88           0 :     IF (sub(ol_normcorr, normCorrTh) > 0)
      89             :     {
      90             :         /* Autocorrelation Bounds */
      91           0 :         min_pitch    = sub(ol_pitch, 4);
      92           0 :         max_pitch    = add(ol_pitch, 4);
      93           0 :         min_pitch    = s_max(min_pitch, MIN_PITCH_12K8);
      94           0 :         max_pitch    = s_min(max_pitch, MAX_PITCH_12K8);
      95           0 :         ac_min_pitch = sub(min_pitch, 4);
      96           0 :         ac_max_pitch = add(max_pitch, 4);
      97           0 :         acflen       = len; move16();
      98           0 :         if (sub(frame_dms, 25) == 0)
      99             :         {
     100           0 :             acflen = shl(len, 1);
     101           0 :             x      = x - len;
     102             :         }
     103             : 
     104             :         /* Compute norm */
     105           0 :         sum1 = L_mac0(1, x[0], x[0]);
     106           0 :         sum2 = L_mac0(1, x[-ac_min_pitch], x[-ac_min_pitch]);
     107           0 :         FOR (m = 1; m < acflen; m++)
     108             :         {
     109           0 :             sum1 = L_mac0(sum1, x[m], x[m]);
     110           0 :             sum2 = L_mac0(sum2, x[m - ac_min_pitch], x[m - ac_min_pitch]);
     111             :         }
     112           0 :         scale1   = norm_l(sum1);
     113           0 :         sum1     = L_shl_pos(sum1, scale1);
     114             : 
     115             :         /* Compute Autocorrelation */
     116           0 :         FOR (n = ac_min_pitch; n <= ac_max_pitch; n++)
     117             :         {
     118           0 :             sum0 = L_mac0(0L, x[0], x[0 - n]);
     119           0 :             FOR (m = 1; m < acflen; m++)
     120             :             {
     121           0 :                 sum0 = L_mac0(sum0, x[m], x[m - n]);
     122             :             }
     123           0 :             if (n > ac_min_pitch)
     124             :             {
     125           0 :               sum2 = L_msu0(sum2, x[acflen - 1 - (n - 1)], x[acflen - 1 - (n - 1)]);
     126           0 :               sum2 = L_mac0_sat(sum2, x[-n], x[-n]);
     127             :             }
     128           0 :             scale2   = norm_l(sum2);
     129           0 :             L_tmp    = L_shl_pos(sum2, scale2);
     130           0 :             prod     = Mpy_32_32_lc3plus(sum1, L_tmp);
     131           0 :             shift    = norm_l(prod);
     132           0 :             prod     = L_shl_pos(prod, shift);
     133           0 :             prod_exp = sub(62, add(add(scale1, scale2), shift));
     134           0 :             inv      = Isqrt_lc3plus(prod, &prod_exp);
     135           0 :             scale0   = norm_l(sum0);
     136           0 :             sum0     = L_shl_pos(sum0, scale0);
     137           0 :             prod     = Mpy_32_32_lc3plus(sum0, inv);
     138           0 :             prod_exp = add(sub(31, scale0), prod_exp);
     139           0 :             test();
     140           0 :             IF (prod == 0 || sub(norm_l(prod), prod_exp) >= 0)
     141             :             {
     142           0 :                 ac[n - ac_min_pitch] = s_max(0, round_fx_sat(L_shl_sat(prod, prod_exp))); move16();
     143             :             }
     144             :             ELSE
     145             :             {
     146           0 :                 ac[n - ac_min_pitch] = 32767; move16();
     147             :             }
     148             :         }
     149             : 
     150             :         /* Find maximum */
     151           0 :         ac_max = ac[min_pitch - ac_min_pitch]; move16();
     152           0 :         pitch  = min_pitch;                    move16();
     153           0 :         FOR (n = min_pitch + 1; n <= max_pitch; n++)
     154             :         {
     155           0 :             tmp = sub_sat(ac[n - ac_min_pitch], ac_max);
     156           0 :             if (tmp > 0)
     157             :             {
     158           0 :                 pitch = n; move16();
     159             :             }
     160           0 :             ac_max = s_max(ac_max, ac[n - ac_min_pitch]);
     161             :         }
     162           0 :         pitch_int   = pitch; move16();
     163           0 :         pitch_fr    = 0;     move16();
     164           0 :         pitch_index = add(pitch_int, 283);
     165             : 
     166             :         /* If the pitch is low -> estimate a fractional part */
     167           0 :         IF (sub(pitch, RES2_PITCH_12K8) < 0)
     168             :         {
     169           0 :             IF (sub(pitch, RES4_PITCH_12K8) < 0)
     170             :             {
     171           0 :                 pitch_res    = 1;  move16();
     172           0 :                 min_pitch_fr = -3; move16();
     173             :             }
     174             :             ELSE
     175             :             {
     176           0 :                 pitch_res    = 2;  move16();
     177           0 :                 min_pitch_fr = -2; move16();
     178             :             }
     179           0 :             if (sub(pitch, min_pitch) == 0)
     180             :             {
     181           0 :                 min_pitch_fr = 0;
     182             :             }
     183           0 :             cor_max32 = MIN_32;
     184           0 :             FOR (fr = min_pitch_fr; fr < 4; fr += pitch_res)
     185             :             {
     186           0 :                 sum0 = L_mult0(ac[pitch_int - ac_min_pitch - 4], ltpf_ac_interp_filt[fr + 3][0]);
     187           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch - 3], ltpf_ac_interp_filt[fr + 3][1]);
     188           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch - 2], ltpf_ac_interp_filt[fr + 3][2]);
     189           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch - 1], ltpf_ac_interp_filt[fr + 3][3]);
     190           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch + 0], ltpf_ac_interp_filt[fr + 3][4]);
     191           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch + 1], ltpf_ac_interp_filt[fr + 3][5]);
     192           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch + 2], ltpf_ac_interp_filt[fr + 3][6]);
     193           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch + 3], ltpf_ac_interp_filt[fr + 3][7]);
     194           0 :                 sum0 = L_mac0(sum0, ac[pitch_int - ac_min_pitch + 4], ltpf_ac_interp_filt[fr + 3][8]);
     195             : 
     196           0 :                 L_tmp = L_sub_sat(sum0, cor_max32);
     197           0 :                 if (L_tmp > 0)
     198             :                 {
     199           0 :                     pitch_fr = fr; move16();
     200             :                 }
     201           0 :                 cor_max32 = L_max(cor_max32, sum0);
     202             :             }
     203           0 :             IF (pitch_fr < 0)
     204             :             {
     205           0 :                 pitch_int = sub(pitch_int, 1);
     206           0 :                 pitch_fr  = add(pitch_fr, 4);
     207             :             }
     208           0 :             IF (sub(pitch_int, 127) >= 0)
     209             :             {
     210           0 :                 pitch_index = add(add(shl_pos(pitch_int, 1), shr_pos(pitch_fr, 1)), 126);
     211             :             }
     212             :             ELSE
     213             :             {
     214           0 :                 pitch_index = sub(add(shl_pos(pitch_int, 2), pitch_fr), 128);
     215             :             }
     216             :         }
     217           0 :         ltpf_pitch = add(shl_pos(pitch_int, 2), pitch_fr);
     218             : 
     219             :         /* Filter current and predicted frame */
     220             : 
     221           0 :         FOR (n = 0; n < acflen; n++)
     222             :         {
     223           0 :             sum0         = L_mult(x[n + 1], inter_filter[0][0][0]);
     224           0 :             sum0         = L_mac(sum0, x[n], inter_filter[0][0][1]);
     225           0 :             currFrame[n] = mac_r(sum0, x[n - 1], inter_filter[0][0][2]);
     226             : 
     227           0 :             sum0         = L_mult(x[n - pitch_int + 1], inter_filter[0][pitch_fr][0]);
     228           0 :             sum0         = L_mac(sum0, x[n - pitch_int], inter_filter[0][pitch_fr][1]);
     229           0 :             sum0         = L_mac(sum0, x[n - pitch_int - 1], inter_filter[0][pitch_fr][2]);
     230           0 :             predFrame[n] = mac_r(sum0, x[n - pitch_int - 2], inter_filter[0][pitch_fr][3]);
     231             :         }
     232             : 
     233             :         /* Normalized Correlation */
     234           0 :         sum0 = L_mult0(currFrame[0], predFrame[0]);
     235           0 :         sum1 = L_mac0(1, predFrame[0], predFrame[0]);
     236           0 :         sum2 = L_mac0(1, currFrame[0], currFrame[0]);
     237           0 :         for (m = 1; m < acflen; m++)
     238             :         {
     239           0 :             sum0 = L_mac0(sum0, currFrame[m], predFrame[m]);
     240           0 :             sum1 = L_mac0(sum1, predFrame[m], predFrame[m]);
     241           0 :             sum2 = L_mac0(sum2, currFrame[m], currFrame[m]);
     242             :         }
     243             : 
     244           0 :         scale1   = norm_l(sum1);
     245           0 :         scale2   = norm_l(sum2);
     246           0 :         sum1     = L_shl_pos(sum1, scale1);
     247           0 :         sum2     = L_shl_pos(sum2, scale2);
     248           0 :         prod     = Mpy_32_32_lc3plus(sum1, sum2);
     249           0 :         shift    = norm_l(prod);
     250           0 :         prod     = L_shl_pos(prod, shift);
     251           0 :         prod_exp = sub(62, add(add(scale1, scale2), shift));
     252           0 :         inv      = Isqrt_lc3plus(prod, &prod_exp);
     253           0 :         scale0   = norm_l(sum0);
     254           0 :         sum0     = L_shl_pos(sum0, scale0);
     255           0 :         prod     = Mpy_32_32_lc3plus(sum0, inv);
     256           0 :         prod_exp = add(sub(31, scale0), prod_exp);
     257           0 :         test();
     258           0 :         IF (prod == 0 || sub(norm_l(prod), prod_exp) >= 0)
     259             :         {
     260           0 :             norm_corr = s_max(0, round_fx_sat(L_shl_sat(prod, prod_exp))); move16();
     261             :         }
     262             :         ELSE
     263             :         {
     264           0 :             norm_corr = 32767; move16();
     265             :         }
     266           0 :         if (norm_corr < 0)
     267             :         {
     268           0 :             norm_corr = 0;
     269             :         }
     270             : 
     271           0 :         IF (sub(ltpf_enable, 1) == 0)
     272             :         {
     273           0 :             test(); test(); test(); test();
     274             :             /* Decision if lptf active */
     275           0 :             IF ((*mem_ltpf_on == 0 && sub(*mem_normcorr, 30802) > 0 && sub(norm_corr, 30802) > 0 &&
     276             :                  (sub(frame_dms, 100) == 0 || sub(*mem_mem_normcorr, 30802) > 0)) ||
     277             :                 (sub(*mem_ltpf_on, 1) == 0 && sub(norm_corr, 29491) > 0) ||
     278             :                 (sub(*mem_ltpf_on, 1) == 0 && sub(abs_s(sub(ltpf_pitch, *mem_ltpf_pitch)), 8) < 0 &&
     279             :                  add(sub(norm_corr, *mem_normcorr), 3277) > 0 && sub(norm_corr, 27525) > 0))
     280             :             {
     281           0 :                 ltpf_active = 1; move16();
     282             :             }
     283             :         }
     284             : 
     285           0 :         param[0] = 1;           move16();
     286           0 :         param[1] = ltpf_active; move16();
     287           0 :         param[2] = pitch_index; move16();
     288           0 :         *bits    = 11;          move16();   
     289             :     }
     290             :     ELSE
     291             :     {
     292           0 :         norm_corr  = ol_normcorr; move16();
     293           0 :         param[0]   = 0;           move16();
     294           0 :         param[1]   = 0;           move16();
     295           0 :         param[2]   = 0;           move16();
     296           0 :         *bits      = 1;           move16();
     297           0 :         ltpf_pitch = 0;           move16();
     298             :     }
     299             : 
     300             : /* Update memory */
     301           0 :     FOR (n = 0; n < mem_in_len; n++)
     302             :     {
     303           0 :         mem_in[n] = mem_in[n + len]; move16();
     304             :     }
     305             : 
     306           0 :     *mem_mem_normcorr = *mem_normcorr; move16();
     307           0 :     *mem_normcorr   = norm_corr;   move16();
     308           0 :     *mem_ltpf_on    = ltpf_active; move16();
     309           0 :     *mem_ltpf_pitch = ltpf_pitch;  move16();
     310             : 
     311             : #ifdef DYNMEM_COUNT
     312             :     Dyn_Mem_Out();
     313             : #endif
     314           0 : }
     315             : 

Generated by: LCOV version 1.14