LCOV - code coverage report
Current view: top level - lib_lc3plus - plc_phecu_lf_peak_analysis_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 65 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 "defines.h"
      11             : #include "functions.h"
      12             : 
      13           0 : void plc_phEcu_LF_peak_analysis_fx(Word16 *      plocs,      /* i/o  0 ... Lprot/2 +1*/
      14             :                                    Word16 *      n_plocs,    /* i/o   0.. MAX_PLOCS  */
      15             :                                    Word32 *      L_f0estQ16, /* i/o  Q16*/
      16             :                                    const Word16 *mag,        /* i: Qx    */
      17             :                                    const Word16 stPhECU_f0hzLtpBinQ7, const Word16 stPhECU_f0gainLtpQ15,
      18             :                                    const Word16 nSubm, Word16 maxPlocs,
      19             :                                    Word8 *scratchBuffer /* Size = 6 * MAX_PLOCS + 42 */
      20             : )
      21             : 
      22             : {
      23             :     Counter i, j;
      24             :     Word16  n_plocs_ana, peakLF_Xval, tmp, f_abs_ind, plocsIntersectFlag;
      25             : 
      26             :     Word32  L_fQ7, *L_f0est_prelQ16;
      27           0 :     Word16  num_prel = 0, *plocs_prel;
      28             :     Word16  prel_low, prel_high, start, fin;
      29             :     Word16 *plocs_old;
      30             :     Word32 *L_plocsi_old;
      31             : 
      32             : #ifdef DYNMEM_COUNT
      33             :     Dyn_Mem_In("plc_phEcu_LF_peak_analysis_fx", sizeof(struct {
      34             :                    Counter i, j;
      35             :                    Word16  n_plocs_ana, peakLF_Xval, tmp, f_abs_ind, plocsIntersectFlag;
      36             :                    Word32  L_fQ7, *L_f0est_prelQ16;
      37             :                    Word16  num_prel, *plocs_prel;
      38             :                    Word16  prel_low, prel_high, start, fin;
      39             :                    Word16 *plocs_old;
      40             :                    Word32 *L_plocsi_old;
      41             :                }));
      42             : #endif
      43             : 
      44             :      
      45             : 
      46           0 :     L_f0est_prelQ16 = (Word32 *)scratchAlign(scratchBuffer, 0);                              /* Size = 4 * 7 */
      47           0 :     plocs_prel      = (Word16 *)scratchAlign(L_f0est_prelQ16, sizeof(*L_f0est_prelQ16) * 7); /* Size = 2 * 7 */
      48           0 :     plocs_old       = (Word16 *)scratchAlign(plocs_prel, sizeof(*plocs_prel) * 7);           /* Size = 2 * MAX_PLOCS */
      49           0 :     L_plocsi_old    = (Word32 *)scratchAlign(plocs_old, sizeof(*plocs_old) * maxPlocs);      /* Size = 4 * MAX_PLOCS */
      50             : 
      51           0 :     test(); test();
      52           0 :     IF ((*n_plocs > 0) && sub(stPhECU_f0gainLtpQ15, ((Word16)(0.25 * 32768.0))) > 0 &&
      53             :         sub(stPhECU_f0hzLtpBinQ7, (Word16)(2.75 * 128.0)) < 0)
      54             :     {
      55             : 
      56             :         /* % analyze/apply  f0Ltp to avoid  intermodulation effects  below  f0  of ~180 Hz
      57             :         % we only do the  f0Ltp-replacement(s)  if  there is already an established
      58             :         % fft peak in the region   ~fRes  to  2.5*fres
      59             :         fft_peak_eval_plocs = 1:3;
      60             :         plocsIntersectFlag = intersect(plocs, fft_peak_eval_plocs );  % check for 1,2,3  in plocs  */
      61             : 
      62           0 :         plocsIntersectFlag = 0; move16();
      63           0 :         peakLF_Xval        = 0; move16();
      64           0 :         n_plocs_ana        = s_min(*n_plocs, 3);
      65           0 :         FOR (i = 0; i < n_plocs_ana; i++)
      66             :         {
      67           0 :             tmp = plocs[i];       move16();
      68           0 :             if (sub(tmp, 2) <= 0) /*  C index  0, 1,2  checked , [DC, 62.5 Hz, 125Hz ] */
      69             :             {
      70           0 :                 plocsIntersectFlag = add(i, 1);
      71             :             }
      72           0 :             peakLF_Xval = s_max(mag[tmp], peakLF_Xval);
      73             :         }
      74             : 
      75           0 :         num_prel = 0; move16();
      76           0 :         IF (plocsIntersectFlag != 0)
      77             :         { /* fft-peak at 0, 62 or 125 Hz  */
      78             :             /*  analyze if  ltp-based f0 need to be added  or not  */
      79           0 :             peakLF_Xval = mult_r(peakLF_Xval, (Word16)(.375 * 32768.0)); /* now as a limit */
      80             : 
      81           0 :             FOR (i = 1; i <= nSubm; i++)
      82             :             {
      83           0 :                 L_fQ7     = L_mult0(i, stPhECU_f0hzLtpBinQ7); /* fractional index stored in L_plocsi */
      84           0 :                 f_abs_ind = L_shr_pos(L_add(L_fQ7, 64), 7);   /* integer bin index stored in plocs */
      85             : 
      86           0 :                 test();
      87           0 :                 IF ((L_sub(L_fQ7, 819) <= 0) && /*  % only apply up to ~400hz , 819 = 400/62.5*128 */
      88             :                     (sub(mag[f_abs_ind], peakLF_Xval) >
      89             :                      0)) /* %  only set as preliminary  if relative peak strength is signficant*/
      90             :                 {
      91           0 :                     L_f0est_prelQ16[num_prel] = L_shl_pos(L_fQ7, 9); move32();
      92           0 :                     plocs_prel[num_prel]      = f_abs_ind;           move16();
      93           0 :                     num_prel                  = add(num_prel, 1);
      94             :                 }
      95             :             }
      96             :         } /*intersectFlag*/
      97             : 
      98             :         /* now replace/ merge new preliminary added peaks with existing plocs and L_f0estQ16 */
      99             :         /* note that a previous fake/merged magnitude-determined peak may be replaced by two separated  side peaks */
     100             : 
     101             :         /* a general non-optimized list-merging solution below */
     102           0 :         test();
     103           0 :         IF ((num_prel > 0) && (sub(add(num_prel, *n_plocs), MAX_PLOCS) <= 0) /* skip in case plocs list is too large */
     104             :         )
     105             :         {
     106           0 :             prel_low  = plocs_prel[0];                move16();
     107           0 :             prel_high = plocs_prel[sub(num_prel, 1)]; move16();
     108             : 
     109             :             /*   initial assumption:: all original peaks (1 or 2 of them)  are positioned   below  prel_low  */   
     110           0 :             start =  (*n_plocs);  /* at this point  'start' is the  location_c where to add any harmonics peaks */      
     111             : 
     112           0 :             FOR (i = sub(*n_plocs, 1); i >= 0; i--)
     113             :             {
     114           0 :                 if (sub(plocs[i], prel_low) >= 0)
     115             :                 {
     116           0 :                     start = i; move16();
     117             :                 }
     118             :             }
     119           0 :             start = sub(start, 1);    /* end of old section to copy before the added/merged section */
     120           0 :             start = s_max(start, -1); /* limit  for loop later */
     121             :                                       /*% dbg check  low part for a sucessful replace/merge  */
     122           0 :             if (start >= 0 && start < *n_plocs)
     123             :             {
     124           0 :                 ASSERT(plocs[start] < plocs_prel[0]);
     125             :             }
     126             : 
     127           0 :             sub(0, 0);
     128           0 :             IF (prel_high < plocs[0])
     129             :             {
     130           0 :                 fin = 0; move16(); /*% keep all plocs , just concat  */
     131             :             }
     132             :             ELSE
     133             :             {
     134           0 :                 fin = *n_plocs;
     135           0 :                 FOR (i = 0; i < *n_plocs; i++)
     136             :                 {
     137           0 :                     sub(0, 0);
     138           0 :                     if (plocs[i] <= prel_high)
     139             :                     {
     140           0 :                         fin = i; move16();
     141             :                     }
     142             :                 }
     143           0 :                 fin = add(fin, 1); /* first element  in high part of old  plocs to be copied  */
     144             :             }
     145             : 
     146             :             /*% dbg check high part for a sucessful replace/merge */
     147           0 :             if (fin >= 0 && fin < *n_plocs)
     148             :             {
     149           0 :                 ASSERT(plocs_prel[sub(num_prel, 1)] < plocs[fin]);
     150             :             }
     151             : 
     152             :             /*
     153             :             % actual replace/merge of added integer locations and fractional freqs. into plocs/f0list  list ;
     154             :             % three loops in BASOP
     155             :             plocs     =  [ plocs(1:(start)) ; plocs_prel ; plocs((fin):end) ];
     156             :             f0est    =   [  f0est(1:(start)) ; f0est_prel; f0est((fin):end) ];
     157             :             */
     158             : 
     159           0 :             FOR (i = 0; i < *n_plocs; i++)
     160             :             {
     161           0 :                 plocs_old[i]    = plocs[i];      move16();
     162           0 :                 L_plocsi_old[i] = L_f0estQ16[i]; move32();
     163             :             }
     164             : 
     165             :             /*
     166             :             j=0;
     167             :             FOR(i=0; i <= start; i++)
     168             :             {
     169             :                 plocs[i] = plocs_old[i];        move16();
     170             :             L_f0estQ16[i] = L_plocsi_old[i]; move32();
     171             :             j++;
     172             :         }
     173             :         */
     174             : 
     175           0 :         j = add(start, 1);
     176             : 
     177           0 :         ASSERT(j>=0);
     178             : 
     179           0 :         FOR (i = 0; i < num_prel; i++) /* NB this section may  both insert or overwrite old plocs   */
     180             :         {
     181           0 :             plocs[j]      = plocs_prel[i];      move16();
     182           0 :             L_f0estQ16[j] = L_f0est_prelQ16[i]; move32();
     183           0 :             j++;
     184             :         }
     185           0 :         FOR (i = fin; i < *n_plocs; i++) /* copy the tail of the list */
     186             :         {
     187           0 :             plocs[j]      = plocs_old[i];    move16();
     188           0 :             L_f0estQ16[j] = L_plocsi_old[i]; move32();
     189           0 :             j++;
     190             :         }
     191             : 
     192           0 :         *n_plocs = j; move16(); /* update total length   */
     193             :     }                            /* num_prel >0*/
     194             : } /* gain/hz Limits */
     195             : 
     196             : #ifdef DYNMEM_COUNT
     197             : Dyn_Mem_Out();
     198             : #endif
     199             :     
     200           0 : }
     201             : 
     202             : 

Generated by: LCOV version 1.14