LCOV - code coverage report
Current view: top level - lib_lc3plus - tns_coder_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 188 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 "functions.h"
      11             : 
      12             : static void   Parcor2Index(const Word16 parCoeff[] /*Q15*/, Word16 index[], Word16 order);
      13             : static void   Index2Parcor(const Word16 index[], Word16 parCoeff[], Word16 order);
      14             : static Word32 FIRLattice(Word16 order, const Word16 *parCoeff /*Q15*/, Word32 *state, Word32 x /* Q0 */);
      15             : 
      16             : /*************************************************************************/
      17             : 
      18           0 : void processTnsCoder_fx(Word16 *bits, Word16 indexes[], Word32 x[], Word16 BW_cutoff_idx, Word16 order[],
      19             :                         Word16 *numfilters, Word16 enable_lpc_weighting, Word16 nSubdivisions, Word16 frame_dms,
      20             :                         Word16 maxLen, Word8 *scratchBuffer
      21             : #ifdef ENABLE_HR_MODE
      22             :                         , Word16 hrmode
      23             : #endif
      24             :                        , Word16 near_nyquist_flag   
      25             : )
      26             : {
      27             :     Dyn_Mem_Deluxe_In(Word16 * tmpbuf; Word32 * rxx, epsP, *state, L_tmp, *A, predictionGain, alpha; Word16 * RC, inv;
      28             :                       Word16 n, n2, headroom, shift, tmp, shifts, facs, facs_e, stopfreq, xLen, maxOrder;
      29             :                       Word16 startfreq[TNS_NUMFILTERS_MAX]; const Word16 *subdiv_startfreq, *subdiv_stopfreq;
      30             :                       Counter i, j, iSubdivisions, lag; Word8 * LevinsonBuffer;);
      31             : 
      32             :     /* Buffer alignment */
      33           0 :     tmpbuf = (Word16 *)scratchAlign(scratchBuffer, 0); /* Size = 2 * MAX_LEN */
      34             : 
      35           0 :     rxx = (Word32 *)scratchAlign(tmpbuf, sizeof(*tmpbuf) * maxLen); /* Size = 4 * (MAXLAG + 1) = 36 bytes */
      36             : 
      37           0 :     state = (Word32 *)scratchAlign(rxx, sizeof(*rxx) * (MAXLAG + 1)); /* Size = 4 * MAXLAG = 32 bytes */
      38             : 
      39           0 :     A = (Word32 *)scratchAlign(state, sizeof(*state) * MAXLAG); /* Size = 4 * (MAXLAG + 1) = 36 bytes */
      40             : 
      41           0 :     RC = (Word16 *)scratchAlign(A, sizeof(*A) * (MAXLAG + 1)); /* Size = 2 * MAXLAG = 16 bytes */
      42             : 
      43           0 :     LevinsonBuffer = (Word8 *)scratchAlign(RC, sizeof(*RC) * (MAXLAG)); /* Size = 4 * (M_LTPF + 1) = 100 bytes */
      44             : 
      45             :     /* Init */
      46           0 :     *bits = 0;
      47           0 :     move16();
      48           0 :     maxOrder = MAXLAG;
      49           0 :     move16();
      50           0 :     *numfilters = 1;
      51           0 :     move16();
      52             : 
      53             : #ifdef ENABLE_HR_MODE
      54           0 :     if (hrmode)
      55             :     {
      56           0 :         xLen = BW_cutoff_bin_all_HR[BW_cutoff_idx];
      57             :     }
      58             :     else
      59             : #endif
      60             :     {
      61           0 :         xLen = BW_cutoff_bin_all[BW_cutoff_idx];
      62             :     }
      63           0 :     move16();
      64             : 
      65           0 :     SWITCH (frame_dms)
      66             :     {
      67           0 :     case 25:
      68           0 :         startfreq[0] = 3;
      69           0 :         move16();
      70             :         
      71             : #ifdef ENABLE_HR_MODE
      72           0 :         if (hrmode)
      73             :         {
      74           0 :             subdiv_startfreq = tns_subdiv_startfreq_2_5ms_HR[BW_cutoff_idx - 4];
      75           0 :             move16();
      76           0 :             subdiv_stopfreq = tns_subdiv_stopfreq_2_5ms_HR[BW_cutoff_idx - 4];
      77           0 :             move16();
      78             :         }
      79             :         else
      80             : #endif
      81             :         {
      82           0 :             subdiv_startfreq = tns_subdiv_startfreq_2_5ms[BW_cutoff_idx];
      83           0 :             move16();
      84           0 :             subdiv_stopfreq = tns_subdiv_stopfreq_2_5ms[BW_cutoff_idx];
      85           0 :             move16();
      86             :         }
      87           0 :         xLen     = shr_pos(xLen, 2);
      88           0 :         maxOrder = 4;
      89           0 :         move16();
      90           0 :         BREAK;
      91           0 :     case 50:
      92           0 :         startfreq[0] = 6;
      93           0 :         move16();
      94             :         
      95             : #ifdef ENABLE_HR_MODE
      96           0 :         if (hrmode)
      97             :         {
      98           0 :             subdiv_startfreq = tns_subdiv_startfreq_5ms_HR[BW_cutoff_idx - 4];
      99           0 :             move16();
     100           0 :             subdiv_stopfreq = tns_subdiv_stopfreq_5ms_HR[BW_cutoff_idx - 4];
     101           0 :             move16();
     102             :         }
     103             :         else
     104             : #endif
     105             :         {
     106           0 :             subdiv_startfreq = tns_subdiv_startfreq_5ms[BW_cutoff_idx];
     107           0 :             move16();
     108           0 :             subdiv_stopfreq = tns_subdiv_stopfreq_5ms[BW_cutoff_idx];
     109           0 :             move16();
     110             :         }
     111           0 :         xLen     = shr_pos(xLen, 1);
     112           0 :         maxOrder = 4;
     113           0 :         BREAK;
     114           0 :     case 75:
     115           0 :         startfreq[0] = 9;
     116           0 :         move16();
     117           0 :         subdiv_startfreq = tns_subdiv_startfreq_7_5ms[BW_cutoff_idx];
     118           0 :         move16();
     119           0 :         subdiv_stopfreq = tns_subdiv_stopfreq_7_5ms[BW_cutoff_idx];
     120           0 :         move16();
     121           0 :         tmp      = shr_pos(xLen, 2);
     122           0 :         xLen     = add(tmp, add(tmp, tmp));
     123           0 :         maxOrder = 8;
     124           0 :         BREAK;
     125           0 :     default: /* 100 */
     126           0 :         startfreq[0] = 12;
     127           0 :         move16();
     128             :         
     129             : #ifdef ENABLE_HR_MODE
     130           0 :         if (hrmode)
     131             :         {
     132           0 :             subdiv_startfreq = tns_subdiv_startfreq_HR[BW_cutoff_idx - 4];
     133           0 :             move16();
     134           0 :             subdiv_stopfreq = tns_subdiv_stopfreq_HR[BW_cutoff_idx - 4];
     135           0 :             move16();
     136             :         }
     137             :         else
     138             : #endif
     139             :         {
     140           0 :             subdiv_startfreq = tns_subdiv_startfreq[BW_cutoff_idx];
     141           0 :             move16();
     142           0 :             subdiv_stopfreq = tns_subdiv_stopfreq[BW_cutoff_idx];
     143           0 :             move16();
     144             :         }
     145           0 :         BREAK;
     146             :     }
     147             : 
     148           0 :     IF (sub(BW_cutoff_idx, 3) >= 0 && frame_dms >= 50)
     149             :     {
     150           0 :         *numfilters  = 2;
     151           0 :         startfreq[1] = shr_pos(xLen, 1);
     152             :     }
     153             : 
     154           0 :     basop_memset(state, 0, MAXLAG * sizeof(*state));
     155             : 
     156           0 :     FOR (j = 0; j < *numfilters; j++)
     157             :     {
     158           0 :         basop_memset(rxx, 0, (maxOrder + 1) * sizeof(*rxx));
     159             : 
     160           0 :         FOR (iSubdivisions = 0; iSubdivisions < nSubdivisions; iSubdivisions++)
     161             :         {
     162           0 :             n = sub(subdiv_stopfreq[nSubdivisions * j + iSubdivisions],
     163           0 :                     subdiv_startfreq[nSubdivisions * j + iSubdivisions]);
     164             : 
     165             :             /*norms[iFilter][iSubdivisions] = norm2FLOAT(pSpectrum+iStartLine, iEndLine-iStartLine);*/
     166           0 :             headroom = getScaleFactor32_lc3plus(x + subdiv_startfreq[nSubdivisions * j + iSubdivisions], n);
     167             : 
     168             :             /* Calculate norm of spectrum band */
     169           0 :             L_tmp = Norm32Norm(x + subdiv_startfreq[nSubdivisions * j + iSubdivisions], headroom, n, &shift);
     170             : 
     171             :             /* Rounding to avoid overflow when computing the autocorrelation below */
     172           0 :             tmp   = sub(norm_l(L_tmp), 1);
     173           0 :             L_tmp = L_shl(L_tmp, tmp);
     174           0 :             shift = sub(shift, tmp);
     175           0 :             L_tmp = L_add(L_tmp, 0x8000);
     176           0 :             L_tmp = L_and(L_tmp, 0x7FFF0000);
     177             : 
     178           0 :             IF (L_tmp == 0)
     179             :             {
     180           0 :                 rxx[0] = 0x7FFFFFFF;
     181           0 :                 move32();
     182           0 :                 basop_memset(&rxx[1], 0, (maxOrder) * sizeof(*rxx));
     183           0 :                 BREAK;
     184             :             }
     185             : 
     186             :             /* get pre-shift for autocorrelation */
     187           0 :             tmp    = sub(shift, norm_l(L_tmp)); /* exponent for normalized L_tmp */
     188           0 :             tmp    = shr_pos(sub(1, tmp), 1);   /* pre-shift to apply before autocorrelation */
     189           0 :             shifts = s_min(tmp, headroom);
     190             : 
     191             :             /* calc normalization factor */
     192           0 :             facs_e = shl_pos(sub(tmp, shifts), 1);
     193             : 
     194           0 :             SWITCH (frame_dms)
     195             :             {
     196           0 :             case 25: facs_e = add(facs_e, 1); BREAK;
     197           0 :             case 50: facs_e = add(facs_e, 1); BREAK;
     198           0 :             case 75: BREAK;
     199           0 :             case 100: BREAK;
     200             :             }
     201             : 
     202           0 :             tmp   = sub(1, shl_pos(tmp, 1));       /* exponent of autocorrelation */
     203           0 :             L_tmp = L_shl(L_tmp, sub(shift, tmp)); /* shift L_tmp to that exponent */
     204             :             /* calc factor (with 2 bits headroom for sum of 3 subdivisions) */
     205           0 :             facs = div_s(0x2000, round_fx(L_tmp)); /* L_tmp is >= 0x2000000 */
     206             : 
     207           0 :             FOR (i = 0; i < n; i++)
     208             :             {
     209           0 :                 tmpbuf[i] = round_fx_sat(L_shl_sat(x[subdiv_startfreq[nSubdivisions * j + iSubdivisions] + i], shifts));
     210           0 :                 move16();
     211             :             }
     212             : 
     213           0 :             FOR (lag = 0; lag <= maxOrder; lag++)
     214             :             {
     215           0 :                 n2 = sub(n, lag);
     216           0 :                 L_tmp = L_deposit_l(0);
     217           0 :                 FOR (i = 0; i < n2; i++)
     218             :                 {
     219           0 :                     L_tmp = L_mac0(L_tmp, tmpbuf[i], tmpbuf[i + lag]);
     220             :                 }
     221           0 :                 if (lag != 0)
     222           0 :                     L_tmp = Mpy_32_32_lc3plus(L_tmp, tnsAcfWindow_lc3plus[lag - 1]);
     223             : 
     224           0 :                 L_tmp = Mpy_32_16_lc3plus(L_tmp, facs);
     225           0 :                 L_tmp = L_shl(L_tmp, facs_e);
     226             : 
     227           0 :                 rxx[lag] = L_add(rxx[lag], L_tmp);
     228           0 :                 move32();
     229             :             }
     230             :         }
     231             : 
     232             :         /* Levinson-Durbin */
     233           0 :         processLevinson_fx(A, rxx, maxOrder, RC, &epsP, LevinsonBuffer);
     234             : 
     235             :         /* Prediction Gain */
     236           0 :         shift          = norm_l(epsP);
     237           0 :         inv            = div_s(16383, extract_h(L_shl_pos(epsP, shift)));
     238           0 :         predictionGain = Mpy_32_32_lc3plus(rxx[0], Mpy_32_16_lc3plus(L_sub(MAX_32, Mpy_32_16_lc3plus(L_shl(epsP, shift), inv)), inv));
     239             : 
     240           0 :         IF (L_sub(predictionGain, L_shr_pos_pos(0x30000000, shift)) > 0 && near_nyquist_flag == 0)
     241             :         {
     242             :             /* If Prediction Gain is low */
     243           0 :             test();
     244           0 :             IF (enable_lpc_weighting != 0 && L_sub(predictionGain, L_shr_pos_pos(0x40000000, shift)) < 0)
     245             :             {
     246             :                 /* LPC weighting */
     247           0 :                 alpha = L_add(0x6CCCCCCD,
     248             :                               Mpy_32_32_lc3plus(0x13333333, L_shl_pos(L_sub(L_shl_pos(predictionGain, shift), 0x30000000), 3)));
     249           0 :                 L_tmp = alpha;
     250           0 :                 FOR (i = 1; i < maxOrder; i++)
     251             :                 {
     252           0 :                     A[i] = Mpy_32_32_lc3plus(A[i], L_tmp);
     253           0 :                     move32();
     254           0 :                     L_tmp = Mpy_32_32_lc3plus(L_tmp, alpha);
     255             :                 }
     256           0 :                 A[maxOrder] = Mpy_32_32_lc3plus(A[maxOrder], L_tmp);
     257           0 :                 move32();
     258             : 
     259             :                 /* LPC -> RC */
     260           0 :                 lpc2rc(A, RC, maxOrder);
     261             :             }
     262             : 
     263             :             /* Reflection Coefficients Quantization */
     264           0 :             Parcor2Index(RC, &indexes[MAXLAG * j], maxOrder);
     265             : 
     266             :             /* reduce filter order by truncating trailing zeros */
     267           0 :             i = sub(maxOrder, 1);
     268           0 :             WHILE ((i >= 0) && (indexes[MAXLAG * j + i] == INDEX_SHIFT))
     269             :             {
     270           0 :                 i = sub(i, 1);
     271             :             }
     272           0 :             order[j] = add(i, 1);
     273             : 
     274             :             // Disable TNS if order is 0:
     275           0 :             IF (order[j] == 0) {
     276             :                 // Jump to else statement
     277           0 :                 goto tns_disabled;
     278             :             }
     279             :             /* Count bits */
     280           0 :             L_tmp = L_deposit_l(ac_tns_order_bits[enable_lpc_weighting][order[j] - 1]);
     281           0 :             FOR (i = 0; i < order[j]; i++)
     282             :             {
     283           0 :                 L_tmp = L_add(L_tmp, L_deposit_l(ac_tns_coef_bits[i][indexes[MAXLAG * j + i]]));
     284             :             }
     285           0 :             *bits = add(*bits, add(2, extract_l(L_shr_pos(L_sub(L_tmp, 1), 11))));
     286           0 :             move16();
     287             : 
     288             :             /* Unquantize Reflection Coefficients */
     289           0 :             Index2Parcor(&indexes[MAXLAG * j], RC, order[j]);
     290             : 
     291             :             /* Stop frequency */
     292           0 :             stopfreq = xLen;
     293           0 :             move16();
     294           0 :             IF (sub(*numfilters, 2) == 0 && j == 0)
     295             :             {
     296           0 :                 stopfreq = startfreq[1];
     297             :             }
     298             : 
     299             :             /* Filter */
     300           0 :             FOR (i = startfreq[j]; i < stopfreq; i++)
     301             :             {
     302           0 :                 x[i] = FIRLattice(order[j], RC, state, x[i]);
     303           0 :                 move32();
     304             :             }
     305             :         }
     306             :         ELSE
     307             :         {
     308           0 : tns_disabled:
     309             :             /* TNS disabled */
     310           0 :             *bits    = add(*bits, 1);
     311           0 :             order[j] = 0;
     312             :         }
     313             :     }
     314             : 
     315             :     Dyn_Mem_Deluxe_Out();
     316           0 : }
     317             : 
     318             : /*************************************************************************/
     319             : 
     320           0 : static void Parcor2Index(const Word16 parCoeff[] /*Q15*/, Word16 index[], Word16 order)
     321             : {
     322             :     Dyn_Mem_Deluxe_In(Counter i; Word16 iIndex; Word16 x;);
     323             : 
     324           0 :     FOR (i = 0; i < order; i++)
     325             :     {
     326           0 :         move16();
     327           0 :         move16();
     328           0 :         iIndex = 1;
     329           0 :         x      = parCoeff[i];
     330             : 
     331           0 :         WHILE ((iIndex < TNS_COEF_RES) && (x > tnsQuantThr[iIndex - 1]))
     332             :         {
     333           0 :             iIndex = add(iIndex, 1);
     334             :         }
     335           0 :         index[i] = sub(iIndex, 1);
     336           0 :         move16();
     337             :     }
     338             : 
     339             :     Dyn_Mem_Deluxe_Out();
     340           0 : }
     341             : 
     342           0 : static void Index2Parcor(const Word16 index[], Word16 parCoeff[], Word16 order)
     343             : {
     344             :     Counter i;
     345           0 :     FOR (i = 0; i < order; i++)
     346             :     {
     347           0 :         parCoeff[i] = tnsQuantPts[index[i]];
     348           0 :         move16();
     349             :     }
     350           0 : }
     351             : 
     352           0 : static Word32 FIRLattice(Word16 order, const Word16 *parCoeff /*Q15*/, Word32 *state, Word32 x /* Q0 */)
     353             : {
     354             :     Dyn_Mem_Deluxe_In(Counter i; Word32 tmpSave, tmp;);
     355             : 
     356           0 :     tmpSave = L_add(x, 0);
     357             : 
     358           0 :     FOR (i = 0; i < order - 1; i++)
     359             :     {
     360           0 :         tmp      = L_add(state[i], Mpy_32_16_lc3plus(x, parCoeff[i]));
     361           0 :         x        = L_add(x, Mpy_32_16_lc3plus(state[i], parCoeff[i])); /* exponent: 31+0 */
     362           0 :         state[i] = tmpSave;
     363           0 :         move32();
     364           0 :         tmpSave = L_add(tmp, 0);
     365             :     }
     366             : 
     367             :     /* last stage: only need half operations */
     368           0 :     x                = L_add(x, Mpy_32_16_lc3plus(state[order - 1], parCoeff[order - 1]));
     369           0 :     state[order - 1] = tmpSave;
     370           0 :     move32();
     371             :     Dyn_Mem_Deluxe_Out();
     372           0 :     return x;
     373             : }
     374             : 

Generated by: LCOV version 1.14