LCOV - code coverage report
Current view: top level - lib_lc3plus - sns_quantize_scf.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 0 225 0.0 %
Date: 2025-05-23 08:37:30 Functions: 0 13 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             : static void pvq_dec(LC3_INT k, LC3_INT m, LC3_INT LS_ind, LC3_INT MPVQ_ind, LC3_INT* pulses);
      15             : static LC3_INT  find_last_indice_le(LC3_INT compare, const LC3_INT* array, LC3_INT len);
      16             : static void idct_II(LC3_FLOAT* in, LC3_FLOAT* out, LC3_INT len);
      17             : 
      18           0 : void idct_II(LC3_FLOAT* in, LC3_FLOAT* out, LC3_INT len)
      19             : {
      20             :     LC3_INT i;
      21             :     LC3_FLOAT norm1, sum;
      22             : 
      23           0 :     norm1 = 0.353553390593274; /* sqrt(2 / 16) */
      24             :     
      25           0 :     for (i = 0; i < len; i++) {
      26           0 :         sum = mac_loop(in, idct_lookup[i], len);
      27           0 :         out[i] = norm1 * sum;
      28             :     }
      29           0 : }
      30             : 
      31           0 : static LC3_INT pvq_pulse_search(LC3_FLOAT *xabs, LC3_FLOAT *ener, LC3_FLOAT *corr, LC3_INT *y, LC3_INT start, LC3_INT end)
      32             : {
      33             :     LC3_INT i;
      34             :     LC3_INT nBest;
      35             :     LC3_FLOAT bestCorrSq, bestEn;
      36             :     LC3_FLOAT corrSq, currCorr, currEn;
      37             : 
      38           0 :     nBest = 0;
      39           0 :     bestCorrSq = 0.0;
      40           0 :     bestEn = 0.0;
      41             : 
      42           0 :     *ener += 1; // Added once for the entire loop
      43             : 
      44           0 :     i = start;
      45             : 
      46           0 :     currCorr = *corr + xabs[i];
      47           0 :     currEn = *ener + (2 * y[i]);
      48             : 
      49           0 :     corrSq = currCorr * currCorr;
      50             : 
      51           0 :     bestEn = currEn;
      52           0 :     bestCorrSq = corrSq;
      53           0 :     nBest = i;
      54             : 
      55             :     /* Iterative max search as recommended in the spec */
      56           0 :     for (; i < end; i++)
      57             :     {
      58           0 :         currCorr = *corr + xabs[i];
      59           0 :         currEn = *ener + (2 * y[i]);
      60             : 
      61           0 :         corrSq = currCorr * currCorr;
      62             : 
      63           0 :         if ((corrSq * bestEn) > (bestCorrSq * currEn))
      64             :         {
      65           0 :             bestEn = currEn;
      66           0 :             bestCorrSq = corrSq;
      67           0 :             nBest = i;
      68             :         }
      69             :     }
      70             : 
      71           0 :     *corr += xabs[nBest];
      72           0 :     *ener += (2 * y[nBest]);
      73             : 
      74           0 :     y[nBest] += 1; /* Add the selected unit pulse */
      75             : 
      76           0 :     return nBest;
      77             : }
      78             : 
      79           0 : static void pvq_enc_vec_normalize(LC3_FLOAT *vec, LC3_INT N)
      80             : {
      81           0 :     LC3_FLOAT mag = 0.0, norm_fac;
      82             :     LC3_INT i;
      83             : 
      84           0 :     for (i = 0; i < N; i++)
      85             :     {
      86           0 :         mag += (vec[i] * vec[i]);
      87             :     }
      88             : 
      89           0 :     norm_fac = 1.0 / LC3_SQRT(mag);
      90             : 
      91           0 :     for (i = 0; i < N; i++)
      92             :     {
      93           0 :         vec[i] = vec[i] * norm_fac;
      94             :     }
      95             : 
      96           0 :     return;
      97             : }
      98             : 
      99           0 : static void pvq_enc_search(LC3_FLOAT* x_in, LC3_INT y[4][M])
     100             : {
     101             :     LC3_INT i, N, K, pulse_total, N_setA;
     102             :     LC3_FLOAT abs_sum, projfac;
     103             :     LC3_FLOAT xabs[16];
     104             :     LC3_FLOAT yy, xy;
     105             : 
     106           0 :     abs_sum = 0.0;
     107             : 
     108             :     /* Step 1 : Projection to pyramid N=16, K=6 */
     109           0 :     N = 16;
     110           0 :     K = 6;
     111           0 :     pulse_total = 0;
     112           0 :     N_setA = 10;
     113             : 
     114           0 :     yy = xy = 0.0f;
     115             : 
     116           0 :     for (i = 0; i < N; i++)
     117             :     {
     118           0 :         xabs[i] = LC3_FABS(x_in[i]);
     119           0 :         abs_sum += xabs[i];
     120             :     }
     121             : 
     122           0 :     projfac = (K - 1) / abs_sum;
     123             : 
     124           0 :     for (i = 0; i < N; i++)
     125             :     {
     126           0 :         y[3][i] = floor(xabs[i] * projfac);
     127             : 
     128           0 :         pulse_total += y[3][i];
     129             : 
     130           0 :         yy += (y[3][i] * y[3][i]);
     131           0 :         xy += (xabs[i] * y[3][i]);
     132             :     }
     133             : 
     134             :     /* Step 2: Adding unit pulses up to K = 6 */
     135           0 :     for (; pulse_total < K; pulse_total++)
     136             :     {
     137           0 :         pvq_pulse_search(xabs, &yy, &xy, y[3], 0, N);
     138             :     }
     139             : 
     140             :     /* Step 3: Adding unit pulses up to K = 8 */
     141           0 :     memcpy(y[2], y[3], sizeof(LC3_INT)*N);
     142           0 :     K = 8;
     143             : 
     144           0 :     for (; pulse_total < K; pulse_total++)
     145             :     {
     146           0 :         pvq_pulse_search(xabs, &yy, &xy, y[2], 0, N);
     147             :     }
     148             : 
     149           0 :     memcpy(y[1], y[2], sizeof(LC3_INT)*N_setA);
     150             : 
     151             :     /* Step 4: Remove unit pulses not belonging to set A */
     152           0 :     for (i = N_setA; i < N; i++)
     153             :     {
     154           0 :         y[1][i] = 0;
     155             :     }
     156             : 
     157             :     /* Step 5: Update yy and xy terms to reflect y1 */
     158           0 :     yy = 0;
     159           0 :     xy = 0;
     160           0 :     pulse_total = 0;
     161             : 
     162           0 :     for (i = 0; i < N_setA; i++)
     163             :     {
     164           0 :         yy += (y[1][i] * y[1][i]);
     165           0 :         xy += (xabs[i] * y[1][i]);
     166             : 
     167           0 :         pulse_total += y[1][i];
     168             :     }
     169             : 
     170             :     /* Step 6: Add unit pulses until K = 10 over N = 10 */
     171           0 :     K = 10;
     172           0 :     for (; pulse_total < K; pulse_total++)
     173             :     {
     174           0 :         pvq_pulse_search(xabs, &yy, &xy, y[1], 0, N_setA);
     175             :     }
     176             : 
     177           0 :     memcpy(y[0], y[1], sizeof(LC3_INT)*N);
     178             : 
     179             :     /* Step 7: Add unit pulses until K = 1 over N = 6 in set B*/
     180           0 :     pvq_pulse_search(xabs, &yy, &xy, y[0], N_setA, N);
     181             : 
     182             :     /* Step 8: Add signs to each of the 4 vectors from x */
     183           0 :     for (i = 0; i < N; i++)
     184             :     {
     185           0 :         if (x_in[i] < 0)
     186             :         {
     187           0 :             y[0][i] = -y[0][i];
     188           0 :             y[1][i] = -y[1][i];
     189           0 :             y[2][i] = -y[2][i];
     190           0 :             y[3][i] = -y[3][i];
     191             :         }
     192             :     }
     193             : 
     194           0 :     return;
     195             : }
     196             : 
     197           0 : static inline LC3_FLOAT calc_mse(LC3_FLOAT *t2rot, LC3_FLOAT *y, LC3_FLOAT gain, LC3_INT N)
     198             : {
     199             :     LC3_FLOAT mse;
     200             :     LC3_INT i;
     201             : 
     202           0 :     mse = 0.0;
     203             : 
     204           0 :     for (i = 0; i < N; i++)
     205             :     {
     206           0 :         LC3_FLOAT err = (t2rot[i] - gain * y[i]);
     207           0 :         mse += (err * err);
     208             :     }
     209             : 
     210           0 :     return mse;
     211             : }
     212             : 
     213           0 : static void sns_quant_adj_gain_shape_search(LC3_FLOAT *t2rot, LC3_INT y[4][M] ,
     214             :     LC3_INT *gain_idx, LC3_INT *shape_idx, LC3_FLOAT *y_norm, LC3_FLOAT *scq_gain)
     215             : {
     216             :     LC3_INT gidx, sidx;
     217             :     LC3_FLOAT min_mse, mse;
     218             :     LC3_INT N;
     219             :     LC3_FLOAT yCur[4][16];
     220             :     LC3_INT i;
     221             : 
     222           0 :     const LC3_INT gain_levels[4] = { 2, 4, 4, 8 };
     223           0 :     const LC3_FLOAT *sns_vq_gains[4] = { sns_vq_reg_adj_gains_fl , sns_vq_reg_lf_adj_gains_fl ,
     224             :         sns_vq_near_adj_gains_fl , sns_vq_far_adj_gains_fl };
     225             : 
     226           0 :     min_mse = -1.0;
     227           0 :     N = 16;
     228             : 
     229             : 
     230           0 :     *gain_idx = *shape_idx = 0;
     231             : 
     232           0 :     for (sidx = 0; sidx < 4; sidx++)
     233             :     {
     234           0 :         for (i = 0; i < N; i++)
     235             :         {
     236           0 :             yCur[sidx][i] = (LC3_FLOAT)y[sidx][i];
     237             :         }
     238             : 
     239             :         /* Step 9: Normalize the vectors */
     240           0 :         pvq_enc_vec_normalize(yCur[sidx], N);
     241             : 
     242           0 :         for (gidx = 0; gidx < gain_levels[sidx]; gidx++)
     243             :         {
     244           0 :             mse = calc_mse(t2rot, yCur[sidx], sns_vq_gains[sidx][gidx], N);
     245             : 
     246           0 :             if ((mse < min_mse)  || (min_mse < 0))
     247             :             {
     248           0 :                 *gain_idx = gidx;
     249           0 :                 *shape_idx = sidx;
     250           0 :                 min_mse = mse;
     251             :             }
     252             :         }
     253             :     }
     254             : 
     255           0 :     for (i = 0; i < N; i++)
     256             :     {
     257           0 :         y_norm[i] = yCur[*shape_idx][i];
     258             :     }
     259             : 
     260           0 :     *scq_gain = sns_vq_gains[*shape_idx][*gain_idx];
     261             : 
     262           0 :     return;
     263             : }
     264             : 
     265           0 : static void enc_push_sign(LC3_FLOAT val, LC3_UINT32 *next_sign_ind, LC3_INT *index)
     266             : {
     267           0 :     if (((*next_sign_ind & 0x80000000U) == 0) && (val != 0)) {
     268           0 :         *index = 2 * (*index) + *next_sign_ind;
     269             :     }
     270           0 :     if (val < 0) {
     271           0 :         *next_sign_ind = 1;
     272             :     }
     273           0 :     if (val > 0) {
     274           0 :         *next_sign_ind = 0;
     275             :     }
     276             : 
     277           0 :     return;
     278             : }
     279             : 
     280           0 : static void MPVQ_enum(LC3_INT dim, LC3_INT *sns_vec, LC3_INT *index_val, LC3_INT *lead_sign_ind)
     281             : {
     282             :     LC3_UINT32 next_sign_ind;
     283             :     LC3_INT k_val_acc;
     284             :     LC3_INT pos;
     285             :     LC3_INT index, n;
     286             :     LC3_INT const *row_ptr;
     287             : 
     288             :     /* MPVQ-index composition loop */
     289             :     LC3_INT tmp_h_row;
     290             :     LC3_INT tmp_val;
     291             : 
     292           0 :     next_sign_ind = 0x80000000U;
     293           0 :     k_val_acc = 0;
     294           0 :     pos = dim;
     295           0 :     index = 0;
     296           0 :     n = 0;
     297             : 
     298           0 :     row_ptr = (LC3_INT const *)&(pvq_enc_A[n]);
     299           0 :     tmp_h_row = row_ptr[0];
     300             : 
     301           0 :     for (pos--; pos >= 0; pos--)
     302             :     {
     303           0 :         tmp_val = sns_vec[pos];
     304           0 :         enc_push_sign(tmp_val, &next_sign_ind, &index);
     305             : 
     306           0 :         index += tmp_h_row;
     307           0 :         k_val_acc += abs(tmp_val);
     308           0 :         if (pos != 0) {
     309           0 :             n += 1; /* switch row in offset table MPVQ_offsets(n, k) */
     310             :         }
     311           0 :         row_ptr = (LC3_INT const *)&(pvq_enc_A[n]);
     312             : 
     313           0 :         tmp_h_row = row_ptr[k_val_acc];
     314             :     }
     315             : 
     316           0 :     *index_val = index;
     317           0 :     *lead_sign_ind = next_sign_ind;
     318             : 
     319           0 :     return;
     320             : }
     321             : 
     322           0 : static LC3_INT MSEsearch (LC3_FLOAT *scf, const LC3_FLOAT sns_CB[8][32])
     323             : {
     324             :     LC3_FLOAT distance, mse;
     325             :     LC3_INT i, n, ind;
     326             : 
     327           0 :     ind = 0;
     328             : 
     329           0 :     distance = (LC3_FLOAT) LC3_CONST_POW_2_100;
     330           0 :     for (i = 0; i < 32; i++) {
     331           0 :         mse = 0;
     332           0 :         for (n = 0; n < 8; n++) {
     333           0 :             mse += (scf[n] - sns_CB[n][i]) * (scf[n] - sns_CB[n][i]);
     334             :         }
     335             : 
     336           0 :         if (mse < distance) {
     337           0 :             distance = mse;
     338           0 :             ind      = i;
     339             :         }
     340             :     }
     341           0 :     return ind;
     342             : }
     343             : 
     344           0 : void process_snsQuantizesScf_Enc(LC3_FLOAT* env, LC3_INT* index, LC3_FLOAT* envq, Dct2 dct2structSNS)
     345             : {
     346             :     LC3_FLOAT stage2_en1_norm_sub[M];
     347             :     LC3_INT i, j;
     348             :     LC3_FLOAT st1_vector[M];
     349             :     LC3_FLOAT pvq_target_pre[M];
     350             :     LC3_FLOAT pvq_target[M];
     351             :     LC3_FLOAT stage2_en1_norm_pre_sub[M];
     352             :     LC3_INT gain, shape;
     353             :     LC3_FLOAT scfq_gain;
     354             :     LC3_INT y[4][M];
     355             : 
     356             :     /* Stage 1 split VQ */
     357           0 :     index[0] = MSEsearch(&env[0], sns_LFCB);  /* ind_LF */
     358           0 :     index[1] = MSEsearch(&env[8], sns_HFCB);  /* ind_HF */
     359             : 
     360           0 :     j = 8;
     361           0 :     for (i = 0; i < 8; i++, j++) {
     362           0 :         st1_vector[i] = sns_LFCB[i][index[0]];
     363           0 :         st1_vector[j] = sns_HFCB[i][index[1]];
     364             :     }
     365             : 
     366             :     /* STAGE 2 */
     367           0 :     for (i = 0; i < 16; i++) {
     368           0 :         pvq_target_pre[i] = env[i] - st1_vector[i];
     369             :     }
     370             : 
     371           0 :     dct2_apply(&dct2structSNS, pvq_target_pre, pvq_target);
     372           0 :     pvq_enc_search(pvq_target, y);
     373           0 :     sns_quant_adj_gain_shape_search(pvq_target, y, &gain, &shape, stage2_en1_norm_pre_sub, &scfq_gain);
     374             : 
     375             :     /* Inverse transform */
     376           0 :     idct_II(stage2_en1_norm_pre_sub, stage2_en1_norm_sub, M);
     377             : 
     378           0 :     index[2] = shape;
     379           0 :     index[3] = gain;
     380             : 
     381           0 :     if (shape < 2) {
     382           0 :         MPVQ_enum(10, y[shape], &index[5], &index[4]);
     383             :     }
     384             :     else {
     385           0 :         MPVQ_enum(M, y[shape], &index[5], &index[4]);
     386             :     }
     387             : 
     388           0 :     if (shape == 0) {
     389             :         LC3_INT ls_ind, ind;
     390           0 :         MPVQ_enum(6, &y[shape][10], &ind, &ls_ind);
     391           0 :         index[6] = ind * 2 + ls_ind;
     392             :     }
     393           0 :     else if (shape == 2) {
     394           0 :         index[6] = -1;
     395             :     }
     396             :     else {
     397           0 :         index[6] = -2;
     398             :     }
     399             : 
     400           0 :     for (i = 0; i < M; i++) {
     401           0 :         envq[i] = st1_vector[i] + (stage2_en1_norm_sub[i] * scfq_gain);
     402             :     }
     403           0 : }
     404             : 
     405           0 : LC3_INT find_last_indice_le(LC3_INT compare, const LC3_INT* array, LC3_INT len)
     406             : {
     407           0 :     LC3_INT idx = 0, i = 0;
     408             : 
     409           0 :     for (i = 0; i < len; i++) {
     410           0 :         if (compare >= array[i]) {
     411           0 :             idx++;
     412             :         }
     413             :     }
     414             : 
     415           0 :     if (idx > 0) {
     416           0 :         idx--;
     417             :     }
     418             : 
     419           0 :     return idx;
     420             : }
     421             : 
     422           0 : void pvq_dec(LC3_INT k, LC3_INT m, LC3_INT LS_ind, LC3_INT MPVQ_ind, LC3_INT* pulses)
     423             : {
     424           0 :     LC3_INT leading_sign, idx, k_delta = 0, pos;
     425             : 
     426           0 :     leading_sign = 1 - 2 * LS_ind;
     427             : 
     428             :     /* Decoding loop */
     429             : 
     430           0 :     for (pos = 0; pos < m; pos++) {
     431           0 :         if (MPVQ_ind != 0) {
     432             :             /* Find last indice */
     433           0 :             idx      = find_last_indice_le(MPVQ_ind, &pvq_enc_A[m - pos - 1][0], k + 1);
     434           0 :             MPVQ_ind = MPVQ_ind - pvq_enc_A[m - pos - 1][idx];
     435           0 :             k_delta  = k - idx;
     436             :         } else {
     437           0 :             pulses[pos] = leading_sign * k;
     438           0 :             break;
     439             :         }
     440             : 
     441           0 :         if (k_delta != 0) {
     442           0 :             pulses[pos] = leading_sign * k_delta;
     443           0 :             if ((MPVQ_ind % 2) != 0) {
     444           0 :                 leading_sign = -1;
     445             :             } else {
     446           0 :                 leading_sign = 1;
     447             :             }
     448             : 
     449           0 :             MPVQ_ind = floor(MPVQ_ind / 2);
     450           0 :             k        = k - k_delta;
     451             :         }
     452             :     }
     453           0 : }
     454             : 
     455           0 : void process_snsQuantizesScf_Dec(LC3_INT* scf_idx, LC3_FLOAT* scf_q)
     456             : {
     457             :     LC3_INT   i, submode;
     458           0 :     LC3_INT   pulses2[6] = {0}, pulses[M] = {0};
     459           0 :     LC3_FLOAT st2_vector[M], st2_vector_idct[M], sum = 0;
     460             : 
     461             :     /* Decode first stage */
     462             : 
     463           0 :     for (i = 0; i < 8; i++) {
     464           0 :         scf_q[i]     = sns_LFCB[i][scf_idx[0]];
     465           0 :         scf_q[i + 8] = sns_HFCB[i][scf_idx[1]];
     466             :     }
     467             : 
     468             :     /* STAGE 2 */
     469             :     /* Decode submode */
     470             : 
     471           0 :     submode = scf_idx[2];
     472             : 
     473             :     /* Decode pulses */
     474             : 
     475           0 :     if (submode < 2) {
     476           0 :         pvq_dec(10, 10, scf_idx[4], scf_idx[5], pulses);
     477             : 
     478           0 :         if (submode == 0) {
     479           0 :             pvq_dec(1, 6, (scf_idx[6] % 2), floor(scf_idx[6] / 2), pulses2);
     480             : 
     481           0 :             move_int(&pulses[10], pulses2, 6);
     482             : 
     483             :         } else {
     484           0 :             pulses[15] = 0;
     485             :         }
     486           0 :     } else if (submode == 2) {
     487           0 :         pvq_dec(8, 16, scf_idx[4], scf_idx[5], pulses);
     488             :     } else {
     489           0 :         pvq_dec(6, 16, scf_idx[4], scf_idx[5], pulses);
     490             :     }
     491             : 
     492             :     /* Normalization */
     493             : 
     494           0 :     for (i = 0; i < M; i++) {
     495           0 :         sum += pulses[i] * pulses[i];
     496             :     }
     497             : 
     498           0 :     sum = 1.0 / LC3_SQRT(sum);
     499             : 
     500           0 :     for (i = 0; i < M; i++) {
     501           0 :     st2_vector[i] = pulses[i] * sum;
     502             :     }
     503             : 
     504             :     /* Inverse transform */
     505           0 :     idct_II(st2_vector, st2_vector_idct, M);
     506             : 
     507             :     /* Gain */
     508             :     /* Add stage 1 and stage 2 */
     509           0 :     for (i = 0; i < M; i++) {
     510           0 :         scf_q[i] += st2_vector_idct[i] * sns_dec_gains[submode][scf_idx[3]];
     511             :     }
     512           0 : }

Generated by: LCOV version 1.14