LCOV - code coverage report
Current view: top level - lib_lc3plus - olpa_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 138 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_olpa_fx(Word16 *mem_s6k4_exp, Word16 mem_s12k8[], Word16 mem_s6k4[], Word16 *pitch, Word16 *s12k8,
      16             :                      Word16 len, Word16 *normcorr, Word16 *mem_pitch, 
      17             :                      Word16 *pitch_flag,                   
      18             :                      Word16 s12k8_exp, Word16 frame_dms, Word8 *scratchBuffer)
      19             : {
      20             :     Word32  sum, sum0, sum1, sum2, prod, inv;
      21             :     Word16  shift, s6k4_exp, prod_exp, min_pitch, max_pitch;
      22             :     Word16  scale0, scale1, scale2, pitch2, normcorr2, len2, acflen, mem_in_len;
      23             :     Word32  max32;
      24             :     Word32 *ac;
      25             :     Word16 *s6k4;
      26             :     Counter n;
      27             : 
      28             :     Counter m;
      29             :     Word32  L_tmp, L_tmp2;
      30             : 
      31             : 
      32             : #ifdef DYNMEM_COUNT
      33             :     Dyn_Mem_In("process_olpa_fx", sizeof(struct {
      34             :                    Word32  sum, sum0, sum1, sum2, prod, inv;
      35             :                    Word16  shift, s6k4_exp, prod_exp, min_pitch, max_pitch;
      36             :                    Word16  scale0, scale1, scale2, pitch2, normcorr2, len2, acflen, mem_in_len;
      37             :                    Word32  max32;
      38             :                    Word32 *ac;
      39             :                    Word16 *s6k4;
      40             :                    Counter n;
      41             :                    Word32  sums[3];
      42             :                    Counter m;
      43             :                    Word32  L_tmp, L_tmp2;
      44             :                }));
      45             : #endif
      46             : 
      47             :     /* Buffer alignment */
      48           0 :     ac = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 4 * RANGE_PITCH_6K4 = 392 bytes */
      49             : 
      50             :     /* Downsample input signal by a factor of 2 (12.8kHz -> 6.4kHz) */
      51           0 :     mem_in_len = MAX_PITCH_6K4;  move16();
      52           0 :     len2       = shr(len, 1);
      53           0 :     acflen     = len2;           move16();
      54             : 
      55           0 :     SWITCH(frame_dms)
      56             :     {
      57           0 :         case 50:
      58           0 :             mem_in_len = add(mem_in_len, 32);
      59           0 :             acflen     = add(acflen, 32);
      60           0 :             break;
      61             : 
      62           0 :         case 25:
      63           0 :             mem_in_len = add(mem_in_len, 48);
      64           0 :             acflen     = add(acflen, 48);
      65           0 :             break;
      66             :     }
      67             : 
      68           0 :     s6k4    = mem_s6k4 + mem_in_len;
      69           0 :     sum     = L_mac(L_mac(L_mult(mem_s12k8[0], 4053), mem_s12k8[1], 7712), mem_s12k8[2], 9239);
      70           0 :     *s6k4++ = round_fx(L_mac_sat(L_mac(sum, s12k8[0], 7712), s12k8[1], 4053)); move16();
      71           0 :     sum     = L_mac(L_mac(L_mult(mem_s12k8[2], 4053), s12k8[0], 7712), s12k8[1], 9239);
      72           0 :     *s6k4++ = round_fx(L_mac_sat(L_mac(sum, s12k8[2], 7712), s12k8[3], 4053)); move16();
      73             : 
      74           0 :     FOR (n = 5; n < len; n += 2)
      75             :     {
      76           0 :         sum     = L_mac(L_mac(L_mult(s12k8[n - 4], 4053), s12k8[n - 3], 7712), s12k8[n - 2], 9239);
      77           0 :         *s6k4++ = round_fx_sat(L_mac_sat(L_mac(sum, s12k8[n - 1], 7712), s12k8[n], 4053)); move16();
      78             :     }
      79             : 
      80           0 :     mem_s12k8[0] = s12k8[len - 3]; move16();
      81           0 :     mem_s12k8[1] = s12k8[len - 2]; move16();
      82           0 :     mem_s12k8[2] = s12k8[len - 1]; move16();
      83             : 
      84             :     /* Scale downsampled signal */
      85           0 :     s6k4          = mem_s6k4 + mem_in_len;
      86           0 :     scale0        = sub(getScaleFactor16_0(mem_s6k4, mem_in_len), 3);
      87           0 :     *mem_s6k4_exp = sub(*mem_s6k4_exp, scale0); move16();
      88           0 :     scale1        = sub(getScaleFactor16_0(s6k4, len2), 3);
      89           0 :     s6k4_exp      = sub(s12k8_exp, scale1);
      90           0 :     scale2        = sub(*mem_s6k4_exp, s6k4_exp);
      91           0 :     IF (scale2 > 0)
      92             :     {
      93           0 :         Scale_sig(s6k4, len2, sub(scale1, scale2));
      94           0 :         shift    = scale0;        move16();
      95           0 :         s6k4_exp = *mem_s6k4_exp; move16();
      96             :     }
      97             :     ELSE
      98             :     {
      99           0 :         Scale_sig(s6k4, len2, scale1);
     100           0 :         shift         = add(scale0, scale2);
     101           0 :         *mem_s6k4_exp = s6k4_exp; move16();
     102             :     }
     103             : 
     104           0 :     SWITCH(frame_dms)
     105             :     {
     106           0 :         case 50:
     107           0 :             s6k4 = s6k4 - 32;
     108           0 :             break;
     109             :         
     110           0 :         case 25:
     111           0 :             s6k4 = s6k4 - 48;
     112           0 :             break;
     113             :     }
     114             : 
     115           0 :     Scale_sig(mem_s6k4, mem_in_len, shift);
     116             : 
     117             :     /* Compute autocorrelation */
     118           0 :     FOR (n = MIN_PITCH_6K4; n <= MAX_PITCH_6K4; n++)
     119             :     {
     120           0 :         sum = L_mult0(s6k4[0], s6k4[0 - n]);
     121           0 :         FOR (m = 1; m < acflen; m++)
     122             :         {
     123           0 :             sum = L_mac0(sum, s6k4[m], s6k4[m - n]);
     124             :         }
     125           0 :         ac[n - MIN_PITCH_6K4] = sum; move32();
     126             :     }
     127             : 
     128             :     /* Weight autocorrelation and find maximum */
     129           0 :     max32  = Mpy_32_16_lc3plus(ac[0], olpa_ac_weighting[0]); move32();
     130           0 :     *pitch = MIN_PITCH_6K4;                          move16();
     131           0 :     FOR (n = MIN_PITCH_6K4 + 1; n <= MAX_PITCH_6K4; n++)
     132             :     {
     133           0 :         L_tmp  = Mpy_32_16_lc3plus(ac[n - MIN_PITCH_6K4], olpa_ac_weighting[n - MIN_PITCH_6K4]);
     134           0 :         L_tmp2 = L_sub_sat(L_tmp, max32);
     135           0 :         if (L_tmp2 > 0)
     136             :         {
     137           0 :             *pitch = n; move16();
     138             :         }
     139           0 :         max32 = L_max(L_tmp, max32);
     140             :     }
     141             : 
     142             :     /* Compute normalized correlation */
     143           0 :     sum0 = L_mult0(s6k4[0], s6k4[0 - *pitch]);
     144           0 :     sum1 = L_mac0(1, s6k4[0 - *pitch], s6k4[0 - *pitch]);
     145           0 :     sum2 = L_mac0(1, s6k4[0], s6k4[0]);
     146           0 :     for (m = 1; m < acflen; m++)
     147             :     {
     148           0 :         sum0 = L_mac0(sum0, s6k4[m], s6k4[m - *pitch]);
     149           0 :         sum1 = L_mac0(sum1, s6k4[m - *pitch], s6k4[m - *pitch]);
     150           0 :         sum2 = L_mac0(sum2, s6k4[m], s6k4[m]);
     151             :     }
     152           0 :     scale1   = norm_l(sum1);
     153           0 :     scale2   = norm_l(sum2);
     154           0 :     sum1     = L_shl_pos(sum1, scale1);
     155           0 :     sum2     = L_shl_pos(sum2, scale2);
     156           0 :     prod     = Mpy_32_32_lc3plus(sum1, sum2);
     157           0 :     shift    = norm_l(prod);
     158           0 :     prod     = L_shl_pos(prod, shift);
     159           0 :     prod_exp = sub(62, add(add(scale1, scale2), shift));
     160           0 :     inv      = Isqrt_lc3plus(prod, &prod_exp);
     161           0 :     scale0   = norm_l(sum0);
     162           0 :     sum0     = L_shl_pos(sum0, scale0);
     163           0 :     prod     = Mpy_32_32_lc3plus(sum0, inv);
     164           0 :     prod_exp = add(sub(31, scale0), prod_exp);
     165           0 :     test();
     166           0 :     IF (prod == 0 || sub(norm_l(prod), prod_exp) >= 0)
     167             :     {
     168           0 :         *normcorr = s_max(0, round_fx_sat(L_shl_sat(prod, prod_exp))); move16();
     169             :     }
     170             :     ELSE
     171             :     {
     172           0 :         *normcorr = 32767; move16();
     173             :     }
     174             : 
     175             :     /* Second try in the neighborhood of the previous pitch */
     176           0 :     min_pitch = s_max(MIN_PITCH_6K4, sub(*mem_pitch, 4));
     177           0 :     max_pitch = s_min(MAX_PITCH_6K4, add(*mem_pitch, 4));
     178             : 
     179           0 :     max32     = ac[min_pitch - MIN_PITCH_6K4]; move32();
     180           0 :     pitch2    = min_pitch;                     move16();
     181           0 :     FOR (n = min_pitch + 1; n <= max_pitch; n++)
     182             :     {
     183           0 :         L_tmp = L_sub_sat(ac[n - MIN_PITCH_6K4], max32);
     184           0 :         if (L_tmp > 0)
     185             :         {
     186           0 :             pitch2 = n; move16();
     187             :         }
     188           0 :         max32 = L_max(ac[n - MIN_PITCH_6K4], max32);
     189             :     }
     190           0 :     IF (sub(*pitch, pitch2) != 0)
     191             :     {
     192           0 :         sum0 = L_mult0(s6k4[0], s6k4[0 - pitch2]);
     193           0 :         sum1 = L_mac0(1, s6k4[0 - pitch2], s6k4[0 - pitch2]);
     194           0 :         sum2 = L_mac0(1, s6k4[0], s6k4[0]);
     195           0 :         for (m = 1; m < acflen; m++)
     196             :         {
     197           0 :             sum0 = L_mac0(sum0, s6k4[m], s6k4[m - pitch2]);
     198           0 :             sum1 = L_mac0(sum1, s6k4[m - pitch2], s6k4[m - pitch2]);
     199           0 :             sum2 = L_mac0(sum2, s6k4[m], s6k4[m]);
     200             :         }
     201           0 :         scale1   = norm_l(sum1);
     202           0 :         scale2   = norm_l(sum2);
     203           0 :         sum1     = L_shl_pos(sum1, scale1);
     204           0 :         sum2     = L_shl_pos(sum2, scale2);
     205           0 :         prod     = Mpy_32_32_lc3plus(sum1, sum2);
     206           0 :         shift    = norm_l(prod);
     207           0 :         prod     = L_shl_pos(prod, shift);
     208           0 :         prod_exp = sub(62, add(add(scale1, scale2), shift));
     209           0 :         inv      = Isqrt_lc3plus(prod, &prod_exp);
     210           0 :         scale0   = norm_l(sum0);
     211           0 :         sum0     = L_shl_pos(sum0, scale0);
     212           0 :         prod     = Mpy_32_32_lc3plus(sum0, inv);
     213           0 :         prod_exp = add(sub(31, scale0), prod_exp);
     214           0 :         test();
     215           0 :         IF (prod == 0 || sub(norm_l(prod), prod_exp) >= 0)
     216             :         {
     217           0 :             normcorr2 = s_max(0, round_fx_sat(L_shl_sat(prod, prod_exp))); move16();
     218             :         }
     219             :         ELSE
     220             :         {
     221           0 :             normcorr2 = 32767; move16();
     222             :         }
     223           0 :         IF (sub(normcorr2, mult_r(*normcorr, 27853)) > 0)
     224             :         {
     225           0 :             *pitch    = pitch2;    move16();
     226           0 :             *normcorr = normcorr2; move16();
     227             :         }
     228             :     }
     229             : 
     230           0 :     SWITCH(frame_dms)
     231             :     {
     232           0 :         case 50:
     233           0 :             if(*pitch_flag == 1) {
     234           0 :                 *mem_pitch = *pitch; move16();
     235           0 :                 *pitch_flag = 0;
     236             :             }
     237             :             else {
     238           0 :                 *pitch_flag += 1;
     239             :             }
     240           0 :             break;
     241             :         
     242           0 :         case 25:
     243           0 :             if (*pitch_flag == 3) {
     244           0 :                 *mem_pitch   = *pitch; move16();
     245           0 :                 *pitch_flag = 0;
     246             :             }
     247             :             else {
     248           0 :                 *pitch_flag += 1;
     249             :             }
     250           0 :             break;
     251             : 
     252           0 :         default:
     253             : 
     254           0 :     *mem_pitch = *pitch; move16();
     255             :     }
     256             :     
     257             :     /* Update memory */
     258           0 :     basop_memmove(mem_s6k4, &mem_s6k4[len2], mem_in_len * sizeof(Word16));
     259             : 
     260             :     /* Upsample pitch by a factor of 2 (6.4kHz -> 12.8kHz) */
     261           0 :     *pitch = shl_pos(*pitch, 1); move16();
     262             : 
     263             : #ifdef DYNMEM_COUNT
     264             :     Dyn_Mem_Out();
     265             : #endif
     266           0 : }
     267             : 

Generated by: LCOV version 1.14