LCOV - code coverage report
Current view: top level - lib_lc3plus - plc_classify.c (source / functions) Hit Total Coverage
Test: Coverage on main -- conformance test test_26252.py @ a21f94bc6bac334fe001a5bad2f7b32b79038097 Lines: 141 164 86.0 %
Date: 2025-11-01 05:07:43 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             : *                        ETSI TS 103 634 V1.6.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     1174108 : static LC3_INT32 change_bit_at_position(LC3_INT32 value, LC3_UINT8 bit_position, LC3_INT8 bit)
      15             : {
      16     1174108 :     LC3_INT32 helper_mask = ~(1 << bit_position);
      17     1174108 :     LC3_INT32 tmp = value & helper_mask;
      18     1174108 :     tmp = tmp | (bit << bit_position);
      19     1174108 :     return tmp;
      20             : }
      21             : 
      22      587054 : static void update_bit_and_byte_positions(LC3_INT16 longterm_analysis_counter_max_bytebuffer, LC3_INT8 *byte_position, LC3_INT8 *bit_position)
      23             : {
      24      587054 :     if (*bit_position == 29)
      25             :     {
      26       19246 :         *bit_position = 0;
      27             :         
      28       19246 :         if ((*byte_position - longterm_analysis_counter_max_bytebuffer) < -1)
      29             :         {
      30       18058 :             *byte_position = *byte_position + 1;
      31             :         } else {
      32        1188 :             *byte_position = 0;
      33             :         }
      34             :     } else {
      35      567808 :         *bit_position = *bit_position + 1;
      36             :     }
      37      587054 : }
      38             : 
      39     1174108 : 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     1174108 :     LC3_INT32 current_byte = 0;
      42             :     
      43     1174108 :     if (overall_counter != NULL) 
      44             :     {
      45      587054 :         *overall_counter = MIN(*overall_counter + 1, longterm_analysis_counter_max);
      46             :     }
      47             :     
      48     1174108 :     current_byte = array[*byte_position];
      49             :     
      50     1174108 :     current_byte = change_bit_at_position(current_byte, *bit_position, value);
      51             :     
      52     1174108 :     array[*byte_position] = current_byte;
      53     1174108 : }
      54             : 
      55      587054 : 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      587054 :     LC3_INT32 current_byte_tdc = 0, current_byte_ns = 0;
      59      587054 :     LC3_INT16 counter_loc_tdc = 0, counter_loc_ns = 0, counter_tmp = 0;
      60             : 
      61     8581810 :     for (i = length - 1; i >= 0; i--)
      62             :     {
      63     7994756 :         current_byte_tdc = array_tdc[i];
      64     7994756 :         current_byte_ns = array_ns[i];
      65             :         
      66   235829302 :         for (k = 0; k < 30; k++)
      67             :         {
      68   228421600 :             counter_loc_tdc += ((current_byte_tdc >> k) & 1);
      69   228421600 :             counter_loc_ns += ((current_byte_ns >> k) & 1);
      70   228421600 :             counter_tmp++;
      71             :             
      72             :             /* Break from both loops if full 2s buffer has been evaluated */
      73   228421600 :             if (counter_tmp >= longterm_analysis_counter_max)
      74             :             {
      75      587054 :                 i = -1;
      76      587054 :                 k = 30;
      77      587054 :                 break;
      78             :             }
      79             :         }
      80             :     }
      81             :     
      82      587054 :     *counter_tdc = counter_loc_tdc;
      83      587054 :     *counter_ns = counter_loc_ns;
      84      587054 : }
      85             : 
      86             : static void plc_xcorr_lc(LC3_FLOAT *pcmbufHist, LC3_INT32 max_len_pcm_plc, LC3_INT32 pitch_int, LC3_INT32 framelength, LC3PLUS_FrameDuration 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      590506 : void processPlcClassify_fl(LC3_INT plcMeth, LC3_INT *concealMethod, LC3_INT32 *nbLostCmpt, LC3_INT32 bfi,
      90             :                            LC3_FLOAT *xcorr, LC3_INT32 framelength, LC3PLUS_FrameDuration 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             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
      98      590506 :     LC3_INT16 resetClassifierThreshold = 0;
      99      590506 :     LC3_INT16 updateStatistics = 0;
     100             : #endif
     101             : 
     102      590506 :     if (plcAd)
     103             :     {
     104      590506 :         *xcorr = 0;
     105             :     }
     106             :     
     107             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     108      590506 :     switch (frame_dms)
     109             :     {
     110             : #ifdef CR9_C_ADD_1p25MS
     111           0 :         case LC3PLUS_FRAME_DURATION_1p25MS:
     112           0 :             resetClassifierThreshold = 16;
     113           0 :             break;
     114             : #endif
     115           0 :         case LC3PLUS_FRAME_DURATION_2p5MS:
     116           0 :             resetClassifierThreshold = 8;
     117           0 :             break;
     118      558314 :         case LC3PLUS_FRAME_DURATION_5MS:
     119      558314 :             resetClassifierThreshold = 4;
     120      558314 :             break;
     121           0 :         case LC3PLUS_FRAME_DURATION_7p5MS:
     122           0 :             resetClassifierThreshold = 3;
     123           0 :             break;
     124       32192 :         case LC3PLUS_FRAME_DURATION_10MS:
     125       32192 :             resetClassifierThreshold = 2;
     126       32192 :             break;
     127           0 :         case LC3PLUS_FRAME_DURATION_UNDEFINED: assert(0);
     128             :     }
     129             :     
     130      590506 :     if (plcAd->numberOfGoodFrames > resetClassifierThreshold)
     131             :     {
     132      587054 :         updateStatistics = 1;
     133             :     } else {
     134        3452 :         updateStatistics = 0;
     135             :     }
     136             : #endif
     137             :     
     138      590506 :     fs_idx_tmp = FS2FS_IDX(fs);
     139             :     /* Save statistics for 24 kHz, 48 kHz and 96 kHz */
     140      590506 :     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 */
     141             :     {
     142      590506 :         if (bfi == 1)
     143             :         {
     144           0 :             *nbLostCmpt = *nbLostCmpt + 1;
     145             :         }
     146             :         
     147             :         /* Use pitch correlation at ltpf integer lag if available */
     148      590506 :         if ((*nbLostCmpt == 1) || (bfi != 1) )/* PC(bfi==2) requires allowing 2 to pass thru  as well */
     149             :         {
     150      590506 :             *concealMethod = 4;  /* Noise Substitution */
     151             :             UNUSED(plcMeth);
     152             : 
     153             :             /* Advanced PLC */
     154      590506 :             if (pitch_int > 0)
     155             :             {
     156      490406 :                 *concealMethod = 3; /* Timedomain PLC assumed */
     157      490406 :                 plc_xcorr_lc(plcAd->pcmbufHist, plcAd->max_len_pcm_plc, pitch_int, framelength, frame_dms, fs, xcorr);
     158             : 
     159      490406 :                 spectral_centroid_lc(plcAd->scf_q_old, tilt, band_offsets, bands_number, framelength, fs, &sc);
     160      490406 :                 class = *xcorr * 7640.0 / 32768.0 - sc - 5112.0 / 32768.0;
     161             :                 
     162      490406 :                 if (class <= 0)
     163             :                 {
     164      159232 :                     if (frame_dms == LC3PLUS_FRAME_DURATION_10MS && hrmode == 0)
     165             :                     {
     166        7344 :                         *concealMethod = 2; /* PhaseEcu selected */
     167             :                         
     168             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     169        7344 :                         if (updateStatistics == 1)
     170             : #endif
     171             :                         {
     172        7344 :                             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);
     173        7344 :                             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);
     174             :                         }
     175             :                     }
     176             :                     else
     177             :                     {
     178             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     179      151888 :                         if (updateStatistics == 1)
     180             : #endif
     181             :                         {
     182      151631 :                             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);
     183      151631 :                             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);
     184             :                         }
     185             :                     }
     186             :                 }
     187             :                 else {
     188             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     189      331174 :                     if (updateStatistics == 1)
     190             : #endif
     191             :                     {
     192      331101 :                         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);
     193      331101 :                         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);
     194             :                     }
     195             :                 }
     196             :             }
     197             :             else
     198             :             {
     199      100100 :                 *concealMethod = 4; /* Noise Substitution */
     200             :                 
     201             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     202      100100 :                 if (updateStatistics == 1)
     203             : #endif
     204             :                 {
     205       96978 :                     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);
     206       96978 :                     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);
     207             :                 }
     208             :             }
     209             :             
     210             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     211      590506 :             if (updateStatistics == 1)
     212             : #endif
     213             :             {
     214      587054 :                 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);
     215      587054 :                 update_bit_and_byte_positions(plcAd->longterm_analysis_counter_max_bytebuffer, &plcAd->longterm_counter_byte_position, &plcAd->longterm_counter_bit_position);
     216             :             }
     217             :         }
     218             :     }
     219             :     
     220             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     221      590506 :     if (bfi == 1)
     222             :     {
     223           0 :         plcAd->numberOfGoodFrames = 0;
     224             :     } else {
     225      590506 :         plcAd->numberOfGoodFrames = plcAd->numberOfGoodFrames + 1;
     226             :     }
     227             : #endif
     228      590506 : }
     229             : 
     230      490406 : 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)
     231             : {
     232             :         LC3_FLOAT gains_lin[M], gains_dee[M], numerator, denumerator;
     233             :         LC3_INT32 i, j, sum, len, start, stop;
     234             :         LC3_INT band_offsets_local[MAX_BANDS_NUMBER + 1];
     235             :     
     236      490406 :     numerator = 0;
     237             : 
     238     8336902 :     for (i = 0; i < M; i++)
     239             :     {
     240     7846496 :         gains_lin[i] = LC3_POW(2, gains[i]);
     241             :     }
     242             :     
     243     8336902 :     for (i = 0; i < M; i++)
     244             :     {
     245     7846496 :         gains_dee[i] = gains_lin[i] / LC3_POW(10, i * (LC3_FLOAT) tilt / (LC3_FLOAT) (M - 1) / 10.0);
     246             :     }
     247             :     
     248      490406 :     if (bands_number == 64)
     249             :     {
     250       27884 :         memmove(band_offsets_local, band_offsets, (bands_number + 1) * sizeof(LC3_INT));
     251             :     }
     252             : 
     253      490406 :     if (bands_number < 32)
     254             :     {
     255           0 :         band_offsets_local[0] = 0;
     256           0 :         j = 32 - bands_number;
     257           0 :         for (i = bands_number - 1; i >= j; i--)
     258             :         {
     259           0 :             band_offsets_local[(i + j) * 2 + 1 + 1] = band_offsets[i + 1];
     260           0 :             band_offsets_local[(i + j) * 2 + 0 + 1] = band_offsets[i + 1];
     261             :         }
     262           0 :         for (i = j - 1; i >= 0; i--)
     263             :         {
     264           0 :             band_offsets_local[i * 4 + 3 + 1] = band_offsets[i + 1];
     265           0 :             band_offsets_local[i * 4 + 2 + 1] = band_offsets[i + 1];
     266           0 :             band_offsets_local[i * 4 + 1 + 1] = band_offsets[i + 1];
     267           0 :             band_offsets_local[i * 4 + 0 + 1] = band_offsets[i + 1];
     268             :         }
     269             :     }
     270             :     else
     271      490406 :     if (bands_number < 64)
     272             :     {
     273      462522 :         band_offsets_local[0] = 0;
     274      462522 :         j = 64 - bands_number;
     275    21738534 :         for (i = bands_number - 1; i >= j; i--)
     276             :         {
     277    21276012 :             band_offsets_local[i + j + 1] = band_offsets[i + 1];
     278             :         }
     279     4625220 :         for (i = j - 1; i >= 0; i--)
     280             :         {
     281     4162698 :             band_offsets_local[i * 2 + 1 + 1] = band_offsets[i + 1];
     282     4162698 :             band_offsets_local[i * 2 + 0 + 1] = band_offsets[i + 1];
     283             :         }
     284             :     }
     285             : 
     286      490406 :     denumerator = 0.001;
     287             :     
     288     8336902 :     for (i = 0; i < M; i++)
     289             :     {
     290     7846496 :         sum = 0; len = 0;
     291     7846496 :         start = band_offsets_local[i * 4] + 1; stop = band_offsets_local[i * 4 + 4];
     292             :         
     293   111504496 :         for (j = stop; j >= start; j--)
     294             :         {
     295   103658000 :             sum += j;
     296   103658000 :             len++;
     297             :         }
     298             :         
     299     7846496 :         numerator += gains_dee[i] * ((LC3_FLOAT) sum / (LC3_FLOAT) framelength);
     300     7846496 :         denumerator += gains_dee[i] * len;
     301             :     }
     302             :     
     303      490406 :     *sc = numerator / denumerator;
     304      490406 :     *sc = *sc * (LC3_FLOAT) fs / 48000.0; /* scaling, because training is for 48kHz */
     305      490406 : }
     306             : 
     307      490406 : static void plc_xcorr_lc(LC3_FLOAT *pcmbufHist, LC3_INT32 max_len_pcm_plc, LC3_INT32 pitch_int, LC3_INT32 framelength,
     308             :                          LC3PLUS_FrameDuration frame_dms, LC3_INT32 fs, LC3_FLOAT *xcorr)
     309             : {
     310             :         LC3_INT32 max_corr_len, pitch_min, corr_len, min_corr_len, pcm_max_corr_len, range1Start, range2Start, i;
     311             :         LC3_FLOAT norm_w, norm_w_t;
     312             :     
     313      490406 :     norm_w_t = 0; norm_w = 0;
     314             : 
     315      490406 :     assert(pitch_int >= 0);
     316      490406 :     assert(pitch_int <= MAX_LEN*100*MAX_PITCH_12K8/12800);
     317             :     
     318      490406 :     *xcorr = 0;
     319             : 
     320      490406 :     if (pitch_int > 0)
     321             :     {
     322      490406 :         pitch_min = fs * MIN_PITCH_12K8/12800;
     323      490406 :         pcm_max_corr_len = max_len_pcm_plc - pitch_int;
     324             : 
     325      490406 :         min_corr_len = 2 * pitch_min;              /* at least 5 ms (=2*pitchmin*) corr length */
     326      490406 :         max_corr_len = framelength*100/(frame_dms*1.25*10);  /* maximum 10 ms */
     327      490406 :         max_corr_len = MIN( max_corr_len, pcm_max_corr_len );
     328             : 
     329      490406 :         corr_len = MIN( max_corr_len, pitch_int ); /* pitch_int is prefered, but maximum 10ms or left pcm buf size */
     330      490406 :         corr_len = MAX( min_corr_len, corr_len );
     331             : 
     332      490406 :         range1Start = max_len_pcm_plc - corr_len;
     333      490406 :         range2Start = range1Start - pitch_int;
     334             : 
     335      490406 :         assert( corr_len >= min_corr_len );
     336      490406 :         assert( corr_len <= max_corr_len );
     337      490406 :         assert( range2Start >= 0 );
     338             : 
     339   166273062 :         for (i = 0; i < corr_len; i++)
     340             :         {
     341   165782656 :             norm_w += pcmbufHist[range1Start + i] * pcmbufHist[range1Start + i];
     342             :         }
     343             : 
     344   166273062 :         for (i = 0; i < corr_len; i++)
     345             :         {
     346   165782656 :             norm_w_t += pcmbufHist[range2Start + i] * pcmbufHist[range2Start + i];
     347             :         }
     348             : 
     349   166273062 :         for (i = 0; i < corr_len; i++)
     350             :         {
     351   165782656 :             *xcorr = *xcorr + pcmbufHist[range1Start + i] * pcmbufHist[range2Start + i];
     352             :         }
     353             : 
     354      490406 :         *xcorr = *xcorr / sqrt(norm_w * norm_w_t + 0.1);
     355      490406 :         *xcorr = MAX(0, *xcorr);
     356             :     } else {
     357           0 :         *xcorr = 0;
     358             :     }
     359      490406 : }
     360             : 

Generated by: LCOV version 1.14