LCOV - code coverage report
Current view: top level - lib_lc3plus - plc_classify_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 149 0.0 %
Date: 2025-08-23 01:22:27 Functions: 0 6 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 : static Word32 change_bit_at_position(Word32 value, Word8 bit_position, UWord8 bit)
      14             : {
      15           0 :     Word32 helper_mask = ~L_shl_pos(1, bit_position);
      16           0 :     Word32 tmp = L_and(value, helper_mask);
      17           0 :     tmp = L_or(tmp, L_shl_pos(bit, bit_position));
      18           0 :     return tmp;
      19             : }
      20             : 
      21           0 : static void update_bit_and_byte_positions(Word16 longterm_analysis_counter_max_bytebuffer, Word8 *byte_position, Word8 *bit_position)
      22             : {
      23           0 :     IF (sub(*bit_position, 29) == 0)
      24             :     {
      25           0 :         *bit_position = 0; move16();
      26             :         
      27           0 :         if (sub(*byte_position, longterm_analysis_counter_max_bytebuffer) < -1)
      28             :         {
      29           0 :             *byte_position = add(*byte_position, 1);
      30             :         } else {
      31           0 :             *byte_position = 0; move16();
      32             :         }
      33             :     } ELSE {
      34           0 :         *bit_position = add(*bit_position, 1);
      35             :     }
      36           0 : }
      37             : 
      38           0 : static void array_insert_and_shift(Word32 *array, UWord8 value, Word16 longterm_analysis_counter_max, Word16 *overall_counter, Word8 *byte_position, Word8 *bit_position)
      39             : {
      40           0 :     Word32 current_byte = 0;
      41             :     
      42             : #ifdef WMOPS
      43             :     push_wmops("PLC::array_insert_and_shift");
      44             : #endif
      45             : 
      46           0 :     IF( overall_counter != NULL) 
      47             :     {
      48           0 :         *overall_counter = s_min(add(*overall_counter, 1), longterm_analysis_counter_max);
      49             :     }
      50             :     
      51           0 :     current_byte = array[*byte_position]; move16();
      52           0 :     current_byte = change_bit_at_position(current_byte, *bit_position, value);
      53           0 :     array[*byte_position] = current_byte; move16();
      54             :     
      55             : #ifdef WMOPS
      56             :     pop_wmops();
      57             : #endif
      58           0 : }
      59             : 
      60           0 : static void array_calculate(Word32 *array_tdc, Word32 *array_ns, int length, Word16 *counter_tdc, Word16 *counter_ns, Word16 longterm_analysis_counter_max)
      61             : {
      62             :     int i, k;
      63           0 :     Word32 current_byte_tdc = 0, current_byte_ns = 0;
      64           0 :     Word16 counter_loc_tdc = 0, counter_loc_ns = 0, counter_tmp = 0;
      65             :     
      66             : #ifdef WMOPS
      67             :     push_wmops("PLC::array_calculate");
      68             : #endif
      69             : 
      70           0 :     for (i = length - 1; i >= 0; i--)
      71             :     {
      72           0 :         current_byte_tdc = array_tdc[i];
      73           0 :         current_byte_ns = array_ns[i];
      74             :         
      75           0 :         for (k = 0; k < 30; k++)
      76             :         {
      77           0 :             counter_loc_tdc += ((current_byte_tdc >> k) & 1);
      78           0 :             counter_loc_ns += ((current_byte_ns >> k) & 1);
      79           0 :             counter_tmp++;
      80             :             
      81             :             /* Break from both loops if full 2s buffer has been evaluated */
      82           0 :             if (counter_tmp >= longterm_analysis_counter_max)
      83             :             {
      84           0 :                 i = -1;
      85           0 :                 k = 30;
      86           0 :                 break;
      87             :             }
      88             :         }
      89             :     }
      90             :     
      91           0 :     *counter_tdc = counter_loc_tdc;
      92           0 :     *counter_ns = counter_loc_ns;
      93             : 
      94             : #ifdef WMOPS
      95             :     pop_wmops();
      96             : #endif
      97           0 : }
      98             : 
      99             : static Word16 spectral_centroid_fx_lc(Word16 old_scf_q[], const Word16 *band_offsets, Word16 bands_number, Word16 frame_length,
     100             :                                       Word16 fs_idx, Word8 *scratchBuffer
     101             : #ifdef ENABLE_HR_MODE
     102             :                                       , Word16 hrmode
     103             : #endif
     104             :                                       );
     105             : 
     106           0 : void processPLCclassify_fx(Word16 plcMeth, Word16 *concealMethod, Word16 *nbLostFramesInRow, Word16 bfi,
     107             :                            Word16 ltpf_mem_pitch_int, Word16 frame_length, Word16 frame_dms, Word16 fs_idx, Word16 yLen,
     108             :                            Word16 q_old_d_fx[], const Word16 *band_offsets, Word16 bands_number, AplcSetup *plcAd, Word8 *scratchBuffer
     109             : #ifdef ENABLE_HR_MODE
     110             :                            , Word16 hrmode
     111             : #endif
     112             :                            )
     113             : {
     114             :     Dyn_Mem_Deluxe_In(
     115             :         Word16 scQ15;
     116             :         Word32 class;
     117             :     );
     118             : 
     119             : #ifdef WMOPS
     120             :     push_wmops("PLC::processPLCclassify_fx");
     121             : #endif
     122             : 
     123             :     UNUSED(yLen);
     124             :     UNUSED(q_old_d_fx);
     125             : 
     126           0 :     if (plcAd)
     127             :     {
     128           0 :         plcAd->norm_corrQ15_fx = 0; move16();
     129             :     }
     130             :     
     131             :     /*  assert(bfi != 2 && "Error bfi flag value, state of fadeout cntr   is affected by PartialConcealment  here "); */
     132             :     /* Save statistics for 24 kHz, 48 kHz and 96 kHz */
     133           0 :     IF((sub(bfi, 1) == 0) || (((bfi >= 0) && (sub(bfi, 2) <= 0)) && ((sub(fs_idx, 2) == 0) || (sub(fs_idx, 4) == 0) || (sub(fs_idx, 5) == 0))))  /* note  for PC  bfi==2  is possible */
     134             :     {
     135             :         /* increase counter of lost-frames-in-a-row */
     136           0 :         IF (sub(bfi, 1) == 0)
     137             :         {
     138           0 :             *nbLostFramesInRow = add(*nbLostFramesInRow, 1);
     139           0 :             *nbLostFramesInRow = s_min(*nbLostFramesInRow, 0x100);
     140             :         }
     141             : 
     142             :         /*assert((bfi != 2) && "PartialConcealment checked vs bfi==0 can cause issues "); */
     143           0 :         IF ((sub(*nbLostFramesInRow, 1) == 0) || (bfi != 1) )  /* was "|| (bfi==0)"  ,  NB only test bfi vs "1" as bfi can have the states [0(good),1(bad),2(good,partialConcealment) }  */
     144             :         {
     145           0 :             *concealMethod = plcMeth; move16();
     146             : 
     147           0 :             IF(sub(plcMeth, 1) == 0)
     148             :             {
     149           0 :                 IF(ltpf_mem_pitch_int > 0)
     150             :                 {
     151           0 :                     *concealMethod = LC3_CON_TEC_TDPLC; move16(); /* TD-PLC */
     152             :                     /* Calculate Features */
     153             : 
     154           0 :                     plcAd->norm_corrQ15_fx = plc_xcorr_lc_fx(plcAd->x_old_tot_fx, plcAd->max_len_pcm_plc, ltpf_mem_pitch_int, fs_idx);
     155           0 :                     scQ15 = spectral_centroid_fx_lc(plcAd->old_scf_q, band_offsets, bands_number, frame_length,
     156             :                         fs_idx, scratchBuffer
     157             : #ifdef ENABLE_HR_MODE
     158             :                         , hrmode
     159             : #endif
     160             :                     );
     161             : 
     162             :                     /* Classify */
     163           0 :                     class = L_mult(plcAd->norm_corrQ15_fx, 7640);
     164           0 :                     class = L_mac(class, scQ15, -32768);
     165           0 :                     class = L_add_sat(class, -335020208);
     166             : 
     167           0 :                     IF(class <= 0)
     168             :                     {
     169             : #ifdef ENABLE_HR_MODE
     170           0 :                         IF((frame_dms == 100) && (hrmode == 0))
     171             : #else
     172             :                         IF(frame_dms == 100)
     173             : #endif
     174             :                         {
     175           0 :                             *concealMethod = LC3_CON_TEC_PHASE_ECU; move16(); /* Phase ECU selected */
     176           0 :                             array_insert_and_shift(plcAd->plc_longterm_advc_tdc, 0, plcAd->longterm_analysis_counter_max, &plcAd->overall_counter, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     177           0 :                             array_insert_and_shift(plcAd->plc_longterm_advc_ns, 0, plcAd->longterm_analysis_counter_max, NULL, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     178             :                         }
     179             :                         ELSE
     180             :                         {
     181           0 :                             array_insert_and_shift(plcAd->plc_longterm_advc_tdc, 0, plcAd->longterm_analysis_counter_max, &plcAd->overall_counter, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     182           0 :                             array_insert_and_shift(plcAd->plc_longterm_advc_ns, 0, plcAd->longterm_analysis_counter_max, NULL, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     183             :                         }
     184             :                     }
     185             :                     ELSE {
     186           0 :                         array_insert_and_shift(plcAd->plc_longterm_advc_tdc, 1, plcAd->longterm_analysis_counter_max, &plcAd->overall_counter, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     187           0 :                         array_insert_and_shift(plcAd->plc_longterm_advc_ns, 0, plcAd->longterm_analysis_counter_max, NULL, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     188             :                     }
     189             :                 }
     190             :                 ELSE
     191             :                 {
     192           0 :                     *concealMethod = LC3_CON_TEC_NS_ADV; move16(); /* Noise Substitution */
     193           0 :                     array_insert_and_shift(plcAd->plc_longterm_advc_tdc, 0, plcAd->longterm_analysis_counter_max, &plcAd->overall_counter, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     194           0 :                     array_insert_and_shift(plcAd->plc_longterm_advc_ns, 1, plcAd->longterm_analysis_counter_max, NULL, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     195             :                 }
     196             :             
     197           0 :             array_calculate(plcAd->plc_longterm_advc_tdc, plcAd->plc_longterm_advc_ns, plcAd->longterm_analysis_counter_max_bytebuffer, &plcAd->longterm_counter_plcTdc, &plcAd->longterm_counter_plcNsAdv, plcAd->longterm_analysis_counter_max);
     198           0 :             update_bit_and_byte_positions(plcAd->longterm_analysis_counter_max_bytebuffer, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     199             :             } 
     200             : 
     201             :         }
     202             :     }
     203             : 
     204             :     Dyn_Mem_Deluxe_Out();
     205             : #ifdef WMOPS
     206             :     pop_wmops();
     207             : #endif
     208           0 : }
     209             : 
     210             : 
     211           0 : Word16 spectral_centroid_fx_lc(Word16 old_scf_q[], const Word16 *band_offsets, Word16 bands_number, Word16 frame_length,
     212             :                                Word16 fs_idx, Word8 *scratchBuffer
     213             : #ifdef ENABLE_HR_MODE
     214             :                                , Word16 hrmode
     215             : #endif
     216             :                                )
     217             : {
     218             :     Dyn_Mem_Deluxe_In(
     219             :         Counter i, j;
     220             :         Word32  den32, num32, tmp32;
     221             :         Word16  s, sc, fac, freq, inv, startfreq, stopfreq;
     222             :         Word16  s2;
     223             :         Word16 *old_scf_q_mod;
     224             :         Word16 *old_scf_q_mod_exp;
     225             :         Word16 *band_offsets_local;
     226             :     );
     227             : #ifdef WMOPS
     228             :     push_wmops("PLC::spectral_centroid_fx_lc");
     229             : #endif
     230             :     
     231             : #ifdef ENABLE_HR_MODE
     232           0 :     s2 = 0;
     233             : #else
     234             :     UNUSED(s2);
     235             : #endif
     236             : 
     237             : 
     238           0 :     old_scf_q_mod      = (Word16 *)scratchAlign(scratchBuffer, 0);                          /* Size = 2 * M */
     239           0 :     old_scf_q_mod_exp  = (Word16 *)scratchAlign(old_scf_q_mod, sizeof(*old_scf_q_mod) * M); /* Size = 2 * M */
     240           0 :     band_offsets_local = (Word16 *)scratchAlign(old_scf_q_mod_exp, sizeof(*old_scf_q_mod_exp) * (M)); /* Size = 2 * bands_number */
     241             : 
     242             :     /* Linear Domain */
     243           0 :     FOR (i = 0; i < M; i++)
     244             :     {
     245           0 :         old_scf_q_mod[i] = BASOP_Util_InvLog2_16(old_scf_q[i], &old_scf_q_mod_exp[i]);
     246             :     }
     247             : 
     248             :     /* De-emphasis */
     249           0 :     FOR (i = 0; i < M; i++)
     250             :     {
     251           0 :         old_scf_q_mod[i]     = mult(old_scf_q_mod[i], lpc_warp_dee_emphasis[fs_idx][i]);      move16();
     252           0 :         old_scf_q_mod_exp[i] = add(old_scf_q_mod_exp[i], lpc_warp_dee_emphasis_e[fs_idx][i]); move16();
     253             :     }
     254             : 
     255           0 :     IF (sub(bands_number, 64) == 0)
     256             :     {
     257           0 :         basop_memmove(band_offsets_local, band_offsets, (bands_number + 1) * sizeof(Word16));
     258             :     }
     259           0 :     IF (sub(bands_number, 32) < 0)
     260             :     {
     261           0 :         band_offsets_local[0] = 0; move16();
     262           0 :         s = sub(32, bands_number);
     263           0 :         FOR (i = sub(bands_number, 1); i >= s; i--)
     264             :         {
     265           0 :             band_offsets_local[(i + s) * 2 + 1 + 1] = band_offsets[i + 1]; move16();
     266           0 :             band_offsets_local[(i + s) * 2 + 0 + 1] = band_offsets[i + 1]; move16();
     267             :         }
     268           0 :         FOR (i = sub(s, 1); i >= 0; i--)
     269             :         {
     270           0 :             band_offsets_local[i * 4 + 3 + 1] = band_offsets[i + 1]; move16();
     271           0 :             band_offsets_local[i * 4 + 2 + 1] = band_offsets[i + 1]; move16();
     272           0 :             band_offsets_local[i * 4 + 1 + 1] = band_offsets[i + 1]; move16();
     273           0 :             band_offsets_local[i * 4 + 0 + 1] = band_offsets[i + 1]; move16();
     274             :         }
     275             :     }
     276             :     ELSE
     277           0 :     IF (sub(bands_number, 64) < 0)
     278             :     {
     279           0 :         band_offsets_local[0] = 0; move16();
     280           0 :         s = sub(64, bands_number);
     281           0 :         FOR (i = sub(bands_number, 1); i >= s; i--)
     282             :         {
     283           0 :             band_offsets_local[i + s + 1] = band_offsets[i + 1]; move16();
     284             :         }
     285           0 :         FOR (i = sub(s, 1); i >= 0; i--)
     286             :         {
     287           0 :             band_offsets_local[i * 2 + 1 + 1] = band_offsets[i + 1]; move16();
     288           0 :             band_offsets_local[i * 2 + 0 + 1] = band_offsets[i + 1]; move16();
     289             :         }
     290             :     }
     291             : 
     292           0 :     den32 = 1; move16();
     293           0 :     num32 = 0; move16();
     294           0 :     inv   = div_s(1, frame_length);
     295             : 
     296           0 :     FOR (i = 0; i < M; i++)
     297             :     {
     298           0 :         freq      = 0; move16();
     299           0 :         startfreq = add(band_offsets_local[i * 4], 1);
     300           0 :         stopfreq  = band_offsets_local[i * 4 + 4];
     301             : 
     302             : #ifdef ENABLE_HR_MODE
     303           0 :         IF (hrmode != 0)
     304             :         {
     305           0 :             tmp32 = 0; move32();
     306           0 :             FOR (j = startfreq; j <= stopfreq; j++)
     307             :             {
     308           0 :                 tmp32 = L_add(tmp32, j);
     309             :             }
     310             : 
     311           0 :             s2    = norm_l(tmp32);
     312           0 :             freq  = extract_h(L_shl(tmp32, s2));
     313           0 :             s2    = sub(add(15, s2), 31);
     314           0 :             tmp32 = L_mult(inv, freq);
     315           0 :             s     = norm_l(tmp32);
     316             :         }
     317             :         ELSE
     318             : #endif
     319             :         {
     320           0 :             FOR (j = startfreq; j <= stopfreq; j++)
     321             :             {
     322           0 :                 freq = add(freq, j);
     323             :             }
     324             : 
     325           0 :             tmp32 = L_mult(inv, freq);
     326           0 :             s     = norm_l(tmp32);
     327             :         }
     328             : 
     329           0 :         tmp32 = L_mult(old_scf_q_mod[i], extract_h(L_shl(tmp32, s)));
     330             : 
     331             : #ifdef ENABLE_HR_MODE
     332           0 :         if (hrmode != 0)
     333             :         {
     334           0 :             s = add(s, s2);
     335             :         }
     336             : #endif
     337             : 
     338           0 :         num32 = L_add(num32, L_shl(tmp32, add(add(-15, old_scf_q_mod_exp[i]), sub(15, s))));
     339           0 :         den32 = L_add(den32, L_shl(L_mult(old_scf_q_mod[i], stopfreq - startfreq + 1), old_scf_q_mod_exp[i]));
     340             :     }
     341             : 
     342           0 :     s = norm_l(den32);
     343           0 :     s = sub(16, s);
     344             : 
     345           0 :     sc = div_s(extract_l(L_shr(num32, s)), extract_l(L_shr(den32, s)));
     346             : 
     347           0 :     SWITCH (fs_idx)
     348             :     {
     349           0 :     case 0:
     350           0 :         fac = 5461; move16();
     351           0 :         BREAK;
     352           0 :     case 1:
     353           0 :         fac = 10922; move16();
     354           0 :         BREAK;
     355           0 :     case 2:
     356           0 :         fac = 16384; move16();
     357           0 :         BREAK;
     358           0 :     case 3:
     359           0 :         fac = 21845; move16();
     360           0 :         BREAK;
     361           0 :     default:         /* case 4: */
     362           0 :         fac = 32767; move16();
     363           0 :         BREAK;
     364             :     }
     365           0 :     sc = round_fx(L_mult(sc, fac));
     366             : #ifdef ENABLE_HR_MODE
     367           0 :     if (sub(fs_idx, 5) == 0)
     368             :     {
     369           0 :         sc = shl_pos(sc, 1);
     370             :     }
     371             : #endif
     372             : 
     373             :     Dyn_Mem_Deluxe_Out();
     374             : #ifdef WMOPS
     375             :     pop_wmops();
     376             : #endif
     377           0 :     return sc;
     378             : }
     379             : 
     380             : 

Generated by: LCOV version 1.14