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 @ 867217ee32c8e8cd2cf5aae69e60c58e00160b49 Lines: 146 164 89.0 %
Date: 2025-12-13 06:47:12 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     2325828 : static LC3_INT32 change_bit_at_position(LC3_INT32 value, LC3_UINT8 bit_position, LC3_INT8 bit)
      15             : {
      16     2325828 :     LC3_INT32 helper_mask = ~(1 << bit_position);
      17     2325828 :     LC3_INT32 tmp = value & helper_mask;
      18     2325828 :     tmp = tmp | (bit << bit_position);
      19     2325828 :     return tmp;
      20             : }
      21             : 
      22     1162914 : static void update_bit_and_byte_positions(LC3_INT16 longterm_analysis_counter_max_bytebuffer, LC3_INT8 *byte_position, LC3_INT8 *bit_position)
      23             : {
      24     1162914 :     if (*bit_position == 29)
      25             :     {
      26       37562 :         *bit_position = 0;
      27             :         
      28       37562 :         if ((*byte_position - longterm_analysis_counter_max_bytebuffer) < -1)
      29             :         {
      30       35716 :             *byte_position = *byte_position + 1;
      31             :         } else {
      32        1846 :             *byte_position = 0;
      33             :         }
      34             :     } else {
      35     1125352 :         *bit_position = *bit_position + 1;
      36             :     }
      37     1162914 : }
      38             : 
      39     2325828 : 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     2325828 :     LC3_INT32 current_byte = 0;
      42             :     
      43     2325828 :     if (overall_counter != NULL) 
      44             :     {
      45     1162914 :         *overall_counter = MIN(*overall_counter + 1, longterm_analysis_counter_max);
      46             :     }
      47             :     
      48     2325828 :     current_byte = array[*byte_position];
      49             :     
      50     2325828 :     current_byte = change_bit_at_position(current_byte, *bit_position, value);
      51             :     
      52     2325828 :     array[*byte_position] = current_byte;
      53     2325828 : }
      54             : 
      55     1162914 : 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     1162914 :     LC3_INT32 current_byte_tdc = 0, current_byte_ns = 0;
      59     1162914 :     LC3_INT16 counter_loc_tdc = 0, counter_loc_ns = 0, counter_tmp = 0;
      60             : 
      61    17097854 :     for (i = length - 1; i >= 0; i--)
      62             :     {
      63    15934940 :         current_byte_tdc = array_tdc[i];
      64    15934940 :         current_byte_ns = array_ns[i];
      65             :         
      66   470056026 :         for (k = 0; k < 30; k++)
      67             :         {
      68   455284000 :             counter_loc_tdc += ((current_byte_tdc >> k) & 1);
      69   455284000 :             counter_loc_ns += ((current_byte_ns >> k) & 1);
      70   455284000 :             counter_tmp++;
      71             :             
      72             :             /* Break from both loops if full 2s buffer has been evaluated */
      73   455284000 :             if (counter_tmp >= longterm_analysis_counter_max)
      74             :             {
      75     1162914 :                 i = -1;
      76     1162914 :                 k = 30;
      77     1162914 :                 break;
      78             :             }
      79             :         }
      80             :     }
      81             :     
      82     1162914 :     *counter_tdc = counter_loc_tdc;
      83     1162914 :     *counter_ns = counter_loc_ns;
      84     1162914 : }
      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     1186529 : 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     1186529 :     LC3_INT16 resetClassifierThreshold = 0;
      99     1186529 :     LC3_INT16 updateStatistics = 0;
     100             : #endif
     101             : 
     102     1186529 :     if (plcAd)
     103             :     {
     104     1186529 :         *xcorr = 0;
     105             :     }
     106             :     
     107             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     108     1186529 :     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          48 :         case LC3PLUS_FRAME_DURATION_2p5MS:
     116          48 :             resetClassifierThreshold = 8;
     117          48 :             break;
     118     1136509 :         case LC3PLUS_FRAME_DURATION_5MS:
     119     1136509 :             resetClassifierThreshold = 4;
     120     1136509 :             break;
     121           0 :         case LC3PLUS_FRAME_DURATION_7p5MS:
     122           0 :             resetClassifierThreshold = 3;
     123           0 :             break;
     124       49972 :         case LC3PLUS_FRAME_DURATION_10MS:
     125       49972 :             resetClassifierThreshold = 2;
     126       49972 :             break;
     127           0 :         case LC3PLUS_FRAME_DURATION_UNDEFINED: assert(0);
     128             :     }
     129             :     
     130     1186529 :     if (plcAd->numberOfGoodFrames > resetClassifierThreshold)
     131             :     {
     132     1162914 :         updateStatistics = 1;
     133             :     } else {
     134       23615 :         updateStatistics = 0;
     135             :     }
     136             : #endif
     137             :     
     138     1186529 :     fs_idx_tmp = FS2FS_IDX(fs);
     139             :     /* Save statistics for 24 kHz, 48 kHz and 96 kHz */
     140     1186529 :     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     1186521 :         if (bfi == 1)
     143             :         {
     144        8287 :             *nbLostCmpt = *nbLostCmpt + 1;
     145             :         }
     146             :         
     147             :         /* Use pitch correlation at ltpf integer lag if available */
     148     1186521 :         if ((*nbLostCmpt == 1) || (bfi != 1) )/* PC(bfi==2) requires allowing 2 to pass thru  as well */
     149             :         {
     150     1179479 :             *concealMethod = 4;  /* Noise Substitution */
     151             :             UNUSED(plcMeth);
     152             : 
     153             :             /* Advanced PLC */
     154     1179479 :             if (pitch_int > 0)
     155             :             {
     156      880589 :                 *concealMethod = 3; /* Timedomain PLC assumed */
     157      880589 :                 plc_xcorr_lc(plcAd->pcmbufHist, plcAd->max_len_pcm_plc, pitch_int, framelength, frame_dms, fs, xcorr);
     158             : 
     159      880589 :                 spectral_centroid_lc(plcAd->scf_q_old, tilt, band_offsets, bands_number, framelength, fs, &sc);
     160      880589 :                 class = *xcorr * 7640.0 / 32768.0 - sc - 5112.0 / 32768.0;
     161             :                 
     162      880589 :                 if (class <= 0)
     163             :                 {
     164      372319 :                     if (frame_dms == LC3PLUS_FRAME_DURATION_10MS && hrmode == 0)
     165             :                     {
     166       13793 :                         *concealMethod = 2; /* PhaseEcu selected */
     167             :                         
     168             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     169       13793 :                         if (updateStatistics == 1)
     170             : #endif
     171             :                         {
     172       13777 :                             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       13777 :                             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      358526 :                         if (updateStatistics == 1)
     180             : #endif
     181             :                         {
     182      354714 :                             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      354714 :                             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      508270 :                     if (updateStatistics == 1)
     190             : #endif
     191             :                     {
     192      505885 :                         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      505885 :                         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      298890 :                 *concealMethod = 4; /* Noise Substitution */
     200             :                 
     201             : #ifdef CR13_C_RESET_CLASSIFIER_AFTER_BAD_FRAMES
     202      298890 :                 if (updateStatistics == 1)
     203             : #endif
     204             :                 {
     205      288538 :                     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      288538 :                     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     1179479 :             if (updateStatistics == 1)
     212             : #endif
     213             :             {
     214     1162914 :                 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     1162914 :                 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     1186529 :     if (bfi == 1)
     222             :     {
     223        8287 :         plcAd->numberOfGoodFrames = 0;
     224             :     } else {
     225     1178242 :         plcAd->numberOfGoodFrames = plcAd->numberOfGoodFrames + 1;
     226             :     }
     227             : #endif
     228     1186529 : }
     229             : 
     230      880589 : 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      880589 :     numerator = 0;
     237             : 
     238    14970013 :     for (i = 0; i < M; i++)
     239             :     {
     240    14089424 :         gains_lin[i] = LC3_POW(2, gains[i]);
     241             :     }
     242             :     
     243    14970013 :     for (i = 0; i < M; i++)
     244             :     {
     245    14089424 :         gains_dee[i] = gains_lin[i] / LC3_POW(10, i * (LC3_FLOAT) tilt / (LC3_FLOAT) (M - 1) / 10.0);
     246             :     }
     247             :     
     248      880589 :     if (bands_number == 64)
     249             :     {
     250       39534 :         memmove(band_offsets_local, band_offsets, (bands_number + 1) * sizeof(LC3_INT));
     251             :     }
     252             : 
     253      880589 :     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      880589 :     if (bands_number < 64)
     272             :     {
     273      841055 :         band_offsets_local[0] = 0;
     274      841055 :         j = 64 - bands_number;
     275    39529585 :         for (i = bands_number - 1; i >= j; i--)
     276             :         {
     277    38688530 :             band_offsets_local[i + j + 1] = band_offsets[i + 1];
     278             :         }
     279     8410550 :         for (i = j - 1; i >= 0; i--)
     280             :         {
     281     7569495 :             band_offsets_local[i * 2 + 1 + 1] = band_offsets[i + 1];
     282     7569495 :             band_offsets_local[i * 2 + 0 + 1] = band_offsets[i + 1];
     283             :         }
     284             :     }
     285             : 
     286      880589 :     denumerator = 0.001;
     287             :     
     288    14970013 :     for (i = 0; i < M; i++)
     289             :     {
     290    14089424 :         sum = 0; len = 0;
     291    14089424 :         start = band_offsets_local[i * 4] + 1; stop = band_offsets_local[i * 4 + 4];
     292             :         
     293   198114024 :         for (j = stop; j >= start; j--)
     294             :         {
     295   184024600 :             sum += j;
     296   184024600 :             len++;
     297             :         }
     298             :         
     299    14089424 :         numerator += gains_dee[i] * ((LC3_FLOAT) sum / (LC3_FLOAT) framelength);
     300    14089424 :         denumerator += gains_dee[i] * len;
     301             :     }
     302             :     
     303      880589 :     *sc = numerator / denumerator;
     304      880589 :     *sc = *sc * (LC3_FLOAT) fs / 48000.0; /* scaling, because training is for 48kHz */
     305      880589 : }
     306             : 
     307      880589 : 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      880589 :     norm_w_t = 0; norm_w = 0;
     314             : 
     315      880589 :     assert(pitch_int >= 0);
     316      880589 :     assert(pitch_int <= MAX_LEN*100*MAX_PITCH_12K8/12800);
     317             :     
     318      880589 :     *xcorr = 0;
     319             : 
     320      880589 :     if (pitch_int > 0)
     321             :     {
     322      880589 :         pitch_min = fs * MIN_PITCH_12K8/12800;
     323      880589 :         pcm_max_corr_len = max_len_pcm_plc - pitch_int;
     324             : 
     325      880589 :         min_corr_len = 2 * pitch_min;              /* at least 5 ms (=2*pitchmin*) corr length */
     326      880589 :         max_corr_len = framelength*100/(frame_dms*1.25*10);  /* maximum 10 ms */
     327      880589 :         max_corr_len = MIN( max_corr_len, pcm_max_corr_len );
     328             : 
     329      880589 :         corr_len = MIN( max_corr_len, pitch_int ); /* pitch_int is prefered, but maximum 10ms or left pcm buf size */
     330      880589 :         corr_len = MAX( min_corr_len, corr_len );
     331             : 
     332      880589 :         range1Start = max_len_pcm_plc - corr_len;
     333      880589 :         range2Start = range1Start - pitch_int;
     334             : 
     335      880589 :         assert( corr_len >= min_corr_len );
     336      880589 :         assert( corr_len <= max_corr_len );
     337      880589 :         assert( range2Start >= 0 );
     338             : 
     339   298206465 :         for (i = 0; i < corr_len; i++)
     340             :         {
     341   297325876 :             norm_w += pcmbufHist[range1Start + i] * pcmbufHist[range1Start + i];
     342             :         }
     343             : 
     344   298206465 :         for (i = 0; i < corr_len; i++)
     345             :         {
     346   297325876 :             norm_w_t += pcmbufHist[range2Start + i] * pcmbufHist[range2Start + i];
     347             :         }
     348             : 
     349   298206465 :         for (i = 0; i < corr_len; i++)
     350             :         {
     351   297325876 :             *xcorr = *xcorr + pcmbufHist[range1Start + i] * pcmbufHist[range2Start + i];
     352             :         }
     353             : 
     354      880589 :         *xcorr = *xcorr / sqrt(norm_w * norm_w_t + 0.1);
     355      880589 :         *xcorr = MAX(0, *xcorr);
     356             :     } else {
     357           0 :         *xcorr = 0;
     358             :     }
     359      880589 : }
     360             : 

Generated by: LCOV version 1.14