LCOV - code coverage report
Current view: top level - lib_lc3plus - plc_classify.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 0 134 0.0 %
Date: 2025-05-23 08:37:30 Functions: 0 7 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 "options.h"
      11             : #include "wmc_auto.h"
      12             : #include "functions.h"
      13             : 
      14           0 : static LC3_INT32 change_bit_at_position(LC3_INT32 value, LC3_UINT8 bit_position, LC3_INT8 bit)
      15             : {
      16           0 :     LC3_INT32 helper_mask = ~(1 << bit_position);
      17           0 :     LC3_INT32 tmp = value & helper_mask;
      18           0 :     tmp = tmp | (bit << bit_position);
      19           0 :     return tmp;
      20             : }
      21             : 
      22           0 : static void update_bit_and_byte_positions(LC3_INT16 longterm_analysis_counter_max_bytebuffer, LC3_INT8 *byte_position, LC3_INT8 *bit_position)
      23             : {
      24           0 :     if (*bit_position == 29)
      25             :     {
      26           0 :         *bit_position = 0;
      27             :         
      28           0 :         if ((*byte_position - longterm_analysis_counter_max_bytebuffer) < -1)
      29             :         {
      30           0 :             *byte_position = *byte_position + 1;
      31             :         } else {
      32           0 :             *byte_position = 0;
      33             :         }
      34             :     } else {
      35           0 :         *bit_position = *bit_position + 1;
      36             :     }
      37           0 : }
      38             : 
      39           0 : static void array_insert_and_shift(LC3_INT32 *array, LC3_UINT8 value, LC3_INT16 longterm_analysis_counter_max, LC3_INT16 *overall_counter, LC3_INT8 *byte_position, LC3_INT8 *bit_position)
      40             : {
      41           0 :     LC3_INT32 current_byte = 0;
      42             :     
      43           0 :     if (overall_counter != NULL) 
      44             :     {
      45           0 :         *overall_counter = MIN(*overall_counter + 1, longterm_analysis_counter_max);
      46             :     }
      47             :     
      48           0 :     current_byte = array[*byte_position];
      49             :     
      50           0 :     current_byte = change_bit_at_position(current_byte, *bit_position, value);
      51             :     
      52           0 :     array[*byte_position] = current_byte;
      53           0 : }
      54             : 
      55           0 : static void array_calculate(LC3_INT32 *array_tdc, LC3_INT32 *array_ns, int length, LC3_INT16 *counter_tdc, LC3_INT16 *counter_ns, LC3_INT16 longterm_analysis_counter_max)
      56             : {
      57             :     int i, k;
      58           0 :     LC3_INT32 current_byte_tdc = 0, current_byte_ns = 0;
      59           0 :     LC3_INT16 counter_loc_tdc = 0, counter_loc_ns = 0, counter_tmp = 0;
      60             : 
      61           0 :     for (i = length - 1; i >= 0; i--)
      62             :     {
      63           0 :         current_byte_tdc = array_tdc[i];
      64           0 :         current_byte_ns = array_ns[i];
      65             :         
      66           0 :         for (k = 0; k < 30; k++)
      67             :         {
      68           0 :             counter_loc_tdc += ((current_byte_tdc >> k) & 1);
      69           0 :             counter_loc_ns += ((current_byte_ns >> k) & 1);
      70           0 :             counter_tmp++;
      71             :             
      72             :             /* Break from both loops if full 2s buffer has been evaluated */
      73           0 :             if (counter_tmp >= longterm_analysis_counter_max)
      74             :             {
      75           0 :                 i = -1;
      76           0 :                 k = 30;
      77           0 :                 break;
      78             :             }
      79             :         }
      80             :     }
      81             :     
      82           0 :     *counter_tdc = counter_loc_tdc;
      83           0 :     *counter_ns = counter_loc_ns;
      84           0 : }
      85             : 
      86             : static void plc_xcorr_lc(LC3_FLOAT *pcmbufHist, LC3_INT32 max_len_pcm_plc, LC3_INT32 pitch_int, LC3_INT32 framelength, LC3_INT32 frame_dms, LC3_INT32 fs, LC3_FLOAT *xcorr);
      87             : static void spectral_centroid_lc(LC3_FLOAT *gains, LC3_INT32 tilt, const LC3_INT *bands_offset, LC3_INT32 bands_number, LC3_INT32 framelength, LC3_INT32 fs, LC3_FLOAT *sc);
      88             : 
      89           0 : void processPlcClassify_fl(LC3_INT plcMeth, LC3_INT *concealMethod, LC3_INT32 *nbLostCmpt, LC3_INT32 bfi,
      90             :                            LC3_FLOAT *xcorr, LC3_INT32 framelength, LC3_INT32 frame_dms, LC3_INT32 pitch_int,
      91             :                            LC3_INT32 fs, const LC3_INT *band_offsets, LC3_INT32 bands_number, LC3_INT32 tilt, PlcAdvSetup *plcAd
      92             :                            , LC3_INT32 hrmode
      93             : )
      94             : {
      95             :         LC3_FLOAT sc, class;
      96             :         int fs_idx_tmp;
      97             : 
      98           0 :     if (plcAd)
      99             :     {
     100           0 :         *xcorr = 0;
     101             :     }
     102             :     
     103           0 :     fs_idx_tmp = FS2FS_IDX(fs);
     104             :     /* Save statistics for 24 kHz, 48 kHz and 96 kHz */
     105           0 :     if ((bfi == 1) || ((bfi >= 0) && (bfi <= 2) && ((fs_idx_tmp == 2) || (fs_idx_tmp == 4) || (fs_idx_tmp == 5))))   /* Partial Concealment PC(bfi==2) requires allowing value  2 to pass thru  as well */
     106             :     {
     107           0 :         if (bfi == 1)
     108             :         {
     109           0 :             *nbLostCmpt = *nbLostCmpt + 1;
     110             :         }
     111             :         
     112             :         /* Use pitch correlation at ltpf integer lag if available */
     113           0 :         if ((*nbLostCmpt == 1) || (bfi != 1) )/* PC(bfi==2) requires allowing 2 to pass thru  as well */
     114             :         {
     115           0 :             *concealMethod = 4;  /* Noise Substitution */
     116             :             UNUSED(plcMeth);
     117             : 
     118             :             /* Advanced PLC */
     119           0 :             if (pitch_int > 0)
     120             :             {
     121           0 :                 *concealMethod = 3; /* Timedomain PLC assumed */
     122           0 :                 plc_xcorr_lc(plcAd->pcmbufHist, plcAd->max_len_pcm_plc, pitch_int, framelength, frame_dms, fs, xcorr);
     123             : 
     124           0 :                 spectral_centroid_lc(plcAd->scf_q_old, tilt, band_offsets, bands_number, framelength, fs, &sc);
     125           0 :                 class = *xcorr * 7640.0 / 32768.0 - sc - 5112.0 / 32768.0;
     126             :                 
     127           0 :                 if (class <= 0)
     128             :                 {
     129           0 :                     if (frame_dms == 100 && hrmode == 0)
     130             :                     {
     131           0 :                         *concealMethod = 2; /* PhaseEcu selected */
     132           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);
     133           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);
     134             :                     }
     135             :                     else
     136             :                     {
     137           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);
     138           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);
     139             :                     }
     140             :                 }
     141             :                 else {
     142           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);
     143           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);
     144             :                 }
     145             :             }
     146             :             else
     147             :             {
     148           0 :                 *concealMethod = 4; /* Noise Substitution */
     149           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);
     150           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);
     151             :             }
     152             :             
     153           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);
     154           0 :             update_bit_and_byte_positions(plcAd->longterm_analysis_counter_max_bytebuffer, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     155             :         }
     156             :     }
     157           0 : }
     158             : 
     159           0 : static void spectral_centroid_lc(LC3_FLOAT *gains, LC3_INT32 tilt, const LC3_INT *band_offsets, LC3_INT32 bands_number, LC3_INT32 framelength, LC3_INT32 fs, LC3_FLOAT *sc)
     160             : {
     161             :         LC3_FLOAT gains_lin[M], gains_dee[M], numerator, denumerator;
     162             :         LC3_INT32 i, j, sum, len, start, stop;
     163             :         LC3_INT band_offsets_local[MAX_BANDS_NUMBER + 1];
     164             :     
     165           0 :     numerator = 0;
     166             : 
     167           0 :     for (i = 0; i < M; i++)
     168             :     {
     169           0 :         gains_lin[i] = LC3_POW(2, gains[i]);
     170             :     }
     171             :     
     172           0 :     for (i = 0; i < M; i++)
     173             :     {
     174           0 :         gains_dee[i] = gains_lin[i] / LC3_POW(10, i * (LC3_FLOAT) tilt / (LC3_FLOAT) (M - 1) / 10.0);
     175             :     }
     176             :     
     177           0 :     if (bands_number == 64)
     178             :     {
     179           0 :         memmove(band_offsets_local, band_offsets, (bands_number + 1) * sizeof(LC3_INT));
     180             :     }
     181             : 
     182           0 :     if (bands_number < 32)
     183             :     {
     184           0 :         band_offsets_local[0] = 0;
     185           0 :         j = 32 - bands_number;
     186           0 :         for (i = bands_number - 1; i >= j; i--)
     187             :         {
     188           0 :             band_offsets_local[(i + j) * 2 + 1 + 1] = band_offsets[i + 1];
     189           0 :             band_offsets_local[(i + j) * 2 + 0 + 1] = band_offsets[i + 1];
     190             :         }
     191           0 :         for (i = j - 1; i >= 0; i--)
     192             :         {
     193           0 :             band_offsets_local[i * 4 + 3 + 1] = band_offsets[i + 1];
     194           0 :             band_offsets_local[i * 4 + 2 + 1] = band_offsets[i + 1];
     195           0 :             band_offsets_local[i * 4 + 1 + 1] = band_offsets[i + 1];
     196           0 :             band_offsets_local[i * 4 + 0 + 1] = band_offsets[i + 1];
     197             :         }
     198             :     }
     199             :     else
     200           0 :     if (bands_number < 64)
     201             :     {
     202           0 :         band_offsets_local[0] = 0;
     203           0 :         j = 64 - bands_number;
     204           0 :         for (i = bands_number - 1; i >= j; i--)
     205             :         {
     206           0 :             band_offsets_local[i + j + 1] = band_offsets[i + 1];
     207             :         }
     208           0 :         for (i = j - 1; i >= 0; i--)
     209             :         {
     210           0 :             band_offsets_local[i * 2 + 1 + 1] = band_offsets[i + 1];
     211           0 :             band_offsets_local[i * 2 + 0 + 1] = band_offsets[i + 1];
     212             :         }
     213             :     }
     214             : 
     215           0 :     denumerator = 0.001;
     216             :     
     217           0 :     for (i = 0; i < M; i++)
     218             :     {
     219           0 :         sum = 0; len = 0;
     220           0 :         start = band_offsets_local[i * 4] + 1; stop = band_offsets_local[i * 4 + 4];
     221             :         
     222           0 :         for (j = stop; j >= start; j--)
     223             :         {
     224           0 :             sum += j;
     225           0 :             len++;
     226             :         }
     227             :         
     228           0 :         numerator += gains_dee[i] * ((LC3_FLOAT) sum / (LC3_FLOAT) framelength);
     229           0 :         denumerator += gains_dee[i] * len;
     230             :     }
     231             :     
     232           0 :     *sc = numerator / denumerator;
     233           0 :     *sc = *sc * (LC3_FLOAT) fs / 48000.0; /* scaling, because training is for 48kHz */
     234           0 : }
     235             : 
     236           0 : static void plc_xcorr_lc(LC3_FLOAT *pcmbufHist, LC3_INT32 max_len_pcm_plc, LC3_INT32 pitch_int, LC3_INT32 framelength,
     237             :                          LC3_INT32 frame_dms, LC3_INT32 fs, LC3_FLOAT *xcorr)
     238             : {
     239             :         LC3_INT32 max_corr_len, pitch_min, corr_len, min_corr_len, pcm_max_corr_len, range1Start, range2Start, i;
     240             :         LC3_FLOAT norm_w, norm_w_t;
     241             :     
     242           0 :     norm_w_t = 0; norm_w = 0;
     243             : 
     244           0 :     assert(pitch_int >= 0);
     245           0 :     assert(pitch_int <= MAX_LEN*100*MAX_PITCH_12K8/12800);
     246             :     
     247           0 :     *xcorr = 0;
     248             : 
     249           0 :     if (pitch_int > 0)
     250             :     {
     251           0 :         pitch_min = fs * MIN_PITCH_12K8/12800;
     252           0 :         pcm_max_corr_len = max_len_pcm_plc - pitch_int;
     253             : 
     254           0 :         min_corr_len = 2 * pitch_min;              /* at least 5 ms (=2*pitchmin*) corr length */
     255           0 :         max_corr_len = framelength*100/frame_dms;  /* maximum 10 ms */
     256           0 :         max_corr_len = MIN( max_corr_len, pcm_max_corr_len );
     257             : 
     258           0 :         corr_len = MIN( max_corr_len, pitch_int ); /* pitch_int is prefered, but maximum 10ms or left pcm buf size */
     259           0 :         corr_len = MAX( min_corr_len, corr_len );
     260             : 
     261           0 :         range1Start = max_len_pcm_plc - corr_len;
     262           0 :         range2Start = range1Start - pitch_int;
     263             : 
     264           0 :         assert( corr_len >= min_corr_len );
     265           0 :         assert( corr_len <= max_corr_len );
     266           0 :         assert( range2Start >= 0 );
     267             : 
     268           0 :         for (i = 0; i < corr_len; i++)
     269             :         {
     270           0 :             norm_w += pcmbufHist[range1Start + i] * pcmbufHist[range1Start + i];
     271             :         }
     272             : 
     273           0 :         for (i = 0; i < corr_len; i++)
     274             :         {
     275           0 :             norm_w_t += pcmbufHist[range2Start + i] * pcmbufHist[range2Start + i];
     276             :         }
     277             : 
     278           0 :         for (i = 0; i < corr_len; i++)
     279             :         {
     280           0 :             *xcorr = *xcorr + pcmbufHist[range1Start + i] * pcmbufHist[range2Start + i];
     281             :         }
     282             : 
     283           0 :         *xcorr = *xcorr / sqrt(norm_w * norm_w_t + 0.1);
     284           0 :         *xcorr = MAX(0, *xcorr);
     285             :     } else {
     286           0 :         *xcorr = 0;
     287             :     }
     288           0 : }
     289             : 

Generated by: LCOV version 1.14