LCOV - code coverage report
Current view: top level - lib_lc3plus - sns_quantize_scf_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 202 0.0 %
Date: 2025-08-23 01:22:27 Functions: 0 11 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 "functions.h"
      11             : 
      12           0 : static Word16 stage1_base(                    /* o  :  idx                                 */
      13             :                           const Word16 *t,    /* i  :  target SCFs                         */
      14             : #ifdef ENABLE_HR_MODE
      15             :                           const Word32 *cdbk, /* i  :  SCFs cdbk                           */
      16             : #else
      17             :                           const Word16 *cdbk, /* i  :  SCFs cdbk                           */
      18             : #endif
      19             :                           const Word16  R     /* i  :  number of rows in codebook          */
      20             : )
      21             : {
      22             :     Counter row;
      23             :     Word16  k_ptr, idx;
      24             :     Word32  L_min_mse, L_mse;
      25             :     Counter col;
      26             : #ifdef ENABLE_HR_MODE
      27             :     Word32  err;
      28             : #else
      29             :     Word16  err;
      30             : #endif
      31             : 
      32             : #ifdef DYNMEM_COUNT
      33             :     Dyn_Mem_In("stage1_base", sizeof(struct {
      34             :                    Counter row, col;
      35             :                    Word16  k_ptr, idx, err;
      36             :                    Word32  L_min_mse, L_mse;
      37             :                }));
      38             : #endif
      39             : #ifdef WMOPS
      40             :     push_wmops("stage1_base");
      41             : #endif
      42             : 
      43             : /* find first vector error energy for  */
      44             : /* loop probably works with saturation , but it should not occur anyway */
      45           0 :     L_min_mse = L_add(0, 0);          /*  init acc with absolute  min mse sofar */
      46           0 :     FOR (col = 0; col < M / 2; col++) /* fixed to 8 elements */
      47             :     {
      48             : #ifdef ENABLE_HR_MODE
      49           0 :         err = L_sub(cdbk[col], L_deposit_h(t[col])); /* cdbk max abs value is 2048 = 2.^11 , max nb col is 2^3  max
      50             :                                          target is approx similar (2.^14/M)*2  = +/- 2048 , errmax is 4096   */
      51           0 :         L_min_mse = L_add(L_min_mse, Mpy_32_32_lc3plus(err, err));
      52             : #else
      53             :         err = sub(cdbk[col], t[col]); /* cdbk max abs value is 2048 = 2.^11 , max nb col is 2^3  max target is approx
      54             :                                          similar (2.^14/M)*2  = +/- 2048 , errmax is 4096   */
      55             :         L_min_mse = L_mac0(L_min_mse, err, err); /*  max L_min_mse is 8*4096*4096 =2.^(3+12+12) =  2.^27  */
      56             : #endif
      57             :     }
      58             : 
      59           0 :     idx = 0; move16();
      60             : 
      61           0 :     k_ptr = M / 2; move16(); /* ptr init to second row */
      62           0 :     FOR (row = 1; row < R; row++)
      63             :     {
      64             :         /* loop probably works with saturation , but it should not occur anyway */
      65             : 
      66           0 :         L_mse = L_add(L_min_mse, 0);      /* init acc with min mse sofar , */
      67           0 :         FOR (col = 0; col < M / 2; col++) /* fixed to 8 elements */
      68             :         {
      69             : #ifdef ENABLE_HR_MODE
      70           0 :             err = L_sub(cdbk[k_ptr++], L_deposit_h(t[col]));
      71           0 :             L_mse = L_sub(L_mse, Mpy_32_32_lc3plus(err, err));
      72             : #else
      73             :             err   = sub(cdbk[k_ptr++], t[col]);
      74             :             L_mse = L_msu0(L_mse, err,
      75             :                            err); /* NB subtraction  from best MSE error  sofar in acc , saturation may not occur */
      76             : #endif
      77             :         }
      78             : 
      79           0 :         L_min_mse = L_sub(L_min_mse, L_max(L_mse, 0L)); /* ALWAYS update best MSE  error sofar    */
      80             : 
      81           0 :         if (L_mse > 0L) /*  if acc value  still is positive a new lower error energy vector was found in this row   */
      82             :         {
      83           0 :             idx = row; move16(); /* update  1-8 bits idx  */
      84             :         }
      85             : 
      86             :         /* this inner loop(always updating L_min_mse),          (L_msu, if )    consumes AV 19, WC  ~20 STL  cycles  ,
      87             :                                       compared to a conventional(L_mac, IF( ) )          AV 21  WC  ~23 STL  cycles per
      88             :            loop  */
      89             :     }
      90           0 :     ASSERT(idx >= 0 && idx < R);
      91             : 
      92             : #ifdef WMOPS
      93             :     pop_wmops();
      94             : #endif
      95             : #ifdef DYNMEM_COUNT
      96             :     Dyn_Mem_Out();
      97             : #endif
      98             : 
      99           0 :     return idx;
     100             : }
     101             : 
     102           0 : static void first_stage_split_search(
     103             : #ifdef ENABLE_HR_MODE      
     104             :                                      const Word32 *cbk_LF, const Word32 *cbk_HF,
     105             : #else
     106             :                                      const Word16 *cbk_LF, const Word16 *cbk_HF,
     107             : #endif
     108             :                                      const Word16 *target,
     109             :                                      const Word16 nbCbkEntries, Word16 *idxLF, Word16 *idxHF)
     110             : {
     111             :     /* find  base index for  each   SCF split  */
     112           0 :     *idxLF = stage1_base(target, cbk_LF, nbCbkEntries);
     113           0 :     *idxHF = stage1_base((&target[M / 2]), cbk_HF, nbCbkEntries);
     114           0 : }
     115             : 
     116           0 : static void processDeQuantize_stage1ScfDecStage1_fx(
     117             : #ifdef ENABLE_HR_MODE
     118             :                                                     const Word32 *cbk_LF, const Word32 *cbk_HF, 
     119             : #else
     120             :                                                     const Word16 *cbk_LF, const Word16 *cbk_HF,
     121             : #endif
     122             :                                                     Word16 st1_idx0, Word16 st1_idx1,
     123             : #ifdef ENABLE_HR_MODE
     124             :                                                     Word32 *st1_vector
     125             : #else
     126             :                                                     Word16 *st1_vector
     127             : #endif 
     128             :                                                     )
     129             : {
     130             :     Counter col;
     131             :     Word16 offset0, offset1;
     132             : #ifdef DYNMEM_COUNT
     133             :     Dyn_Mem_In("processDeQuantize_stage1ScfDecStage1_fx", sizeof(struct {
     134             :                    Word16  offset0, offset1;
     135             :                    Counter col;
     136             :                }));
     137             : #endif
     138             : 
     139           0 :     offset0 = shl_pos(st1_idx0, 3); /* mult by M/2 */
     140           0 :     offset1 = shl_pos(st1_idx1, 3);
     141           0 :     FOR (col = 0; col < M / 2; col++)
     142             :     {
     143           0 :         st1_vector[col]     = cbk_LF[offset0++]; move16();
     144           0 :         st1_vector[col + 8] = cbk_HF[offset1++]; move16();
     145             : #ifdef ENABLE_HR_MODE
     146           0 :         move16(); 
     147           0 :         move16();
     148             : #endif
     149             :     }
     150             : #ifdef DYNMEM_COUNT
     151             :     Dyn_Mem_Out();
     152             : #endif
     153           0 : }
     154             : 
     155           0 : void downshift_w32_arr(Word32 *w32_arr, Word16 *w16_arr, Word16 shft_val, Word32 len)
     156             : {
     157             :     Word32 i;
     158           0 :     FOR (i = 0; i < len; i++)
     159             :     {
     160           0 :         w16_arr[i] = extract_l(L_shr_pos(w32_arr[i], shft_val));
     161           0 :         move16();
     162             :     }
     163           0 :     return;
     164             : }
     165             : 
     166           0 : void round_w32tow16_arr(Word32 *w32_arr, Word16 *w16_arr,Word32 len)
     167             : {
     168             :     Word32 i;
     169           0 :     FOR (i = 0; i < len; i++)
     170             :     {
     171           0 :         w16_arr[i] = round_fx(w32_arr[i]);
     172           0 :         move16();
     173             :     }
     174           0 :     return;
     175             : }
     176             : 
     177           0 : static void processQuantize_stage1ScfEncStage1_fx(const Word16 *target_st1,
     178             : #ifdef ENABLE_HR_MODE
     179             :                                                   Word32 *st1_vector,
     180             : #else
     181             :                                                   Word16 *st1_vector,
     182             : #endif
     183             :                                                   Word16 *st1_idx0Ptr, Word16 *st1_idx1Ptr)
     184             : 
     185             : {
     186             : #ifdef WMOPS
     187             :     push_wmops("processQuantize_stage1ScfEncStage1_fx");
     188             : #endif
     189             : 
     190             : #ifdef ENABLE_HR_MODE
     191           0 :     first_stage_split_search(st1SCF0_7_base5_32x8_Q27, st1SCF8_15_base5_32x8_Q27, target_st1, SCF_STAGE1_NBCDKENTRIES, 
     192             :                              st1_idx0Ptr, st1_idx1Ptr);
     193             : 
     194           0 :     processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q27, st1SCF8_15_base5_32x8_Q27, *st1_idx0Ptr,
     195           0 :                                             *st1_idx1Ptr, st1_vector);
     196             : #else
     197             :     first_stage_split_search(st1SCF0_7_base5_32x8_Q11, st1SCF8_15_base5_32x8_Q11, target_st1, SCF_STAGE1_NBCDKENTRIES,
     198             :                              st1_idx0Ptr, st1_idx1Ptr);
     199             : 
     200             :     processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q11, st1SCF8_15_base5_32x8_Q11, *st1_idx0Ptr,
     201             :                                             *st1_idx1Ptr, st1_vector);
     202             : #endif
     203             : 
     204             : #ifdef WMOPS
     205             :     pop_wmops();
     206             : #endif
     207             : 
     208           0 :     return;
     209             : }
     210             : 
     211             : /* gain-shape MSE search in warped SCF-residual domain,  synthesis in SCF resiudal domain allows for easy weighting */
     212             : 
     213           0 : static void pvq_enc_find_best_submode_pre_post_fx(
     214             : #ifdef ENABLE_HR_MODE
     215             :     const Word32 *target_st2, /* this target is in the linearized  warped domain , same as input to PVQ search  */
     216             : #else
     217             :     const Word16 *target_st2, /* this target is in the linearized  warped domain , same as input to PVQ search  */
     218             : #endif
     219             :     const Word16 *enc_pulses_far, Word16 *enc_pulses_near, const Word16 *enc_pulsesA, const Word16 *enc_pulsesB,
     220             :     Word16 *sub_mode_ptr, Word16 *i_gain_ptr,
     221             : #ifdef ENABLE_HR_MODE
     222             :     Word32 *enc_adj_glob_warped_vec, 
     223             : #else
     224             :     Word16 *enc_adj_glob_warped_vec,
     225             : #endif
     226             :     Word8 *scratchBuffer) /* Size = 18 * M */
     227             : {
     228             : 
     229             :     Counter       L_section, idx;
     230             : #ifdef ENABLE_HR_MODE
     231             :     const Word32 *search_en1shape[N_SCF_SHAPES_ST2];
     232             : #else
     233             :     const Word16 *search_en1shape[N_SCF_SHAPES_ST2];
     234             : #endif
     235             :     const Word16 *search_gainTab[N_SCF_SHAPES_ST2];
     236             :     Word16        search_n_gains[N_SCF_SHAPES_ST2];
     237             :     Word32        L_mse, L_mse_min, L_idx;
     238             :     Word16 *      pulses_far, *pulses_near, *pulsesAB, *pulsesA;
     239             : #ifdef ENABLE_HR_MODE
     240             :     Word32 *      target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
     241             : #else
     242             :     Word16 *      target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
     243             : #endif
     244             : #ifdef ENABLE_HR_MODE
     245             :     Word32  tmp, err;
     246             : #else
     247             :     Word16  tmp, err;
     248             : #endif
     249             :     Counter i;
     250             : 
     251             : #ifdef DYNMEM_COUNT
     252             : #ifdef ENABLE_HR_MODE
     253             :     Dyn_Mem_In("pvq_enc_find_best_submode_pre_post_fx", sizeof(struct {
     254             :                    Counter i, L_section, idx;
     255             :                    Word32 *search_en1shape[N_SCF_SHAPES_ST2];
     256             :                    Word16 *search_gainTab[N_SCF_SHAPES_ST2];
     257             :                    Word16  search_n_gains[N_SCF_SHAPES_ST2];
     258             :                    Word32  L_mse, L_mse_min, L_idx;
     259             :                    Word16 *pulses_far, *pulses_near, *pulsesAB, *pulsesA;
     260             :                    Word32 *target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
     261             :                    Word32  tmp, err;
     262             :                }));
     263             : #else
     264             :     Dyn_Mem_In("pvq_enc_find_best_submode_pre_post_fx", sizeof(struct {
     265             :                    Counter i, L_section, idx;
     266             :                    Word16 *search_en1shape[N_SCF_SHAPES_ST2];
     267             :                    Word16 *search_gainTab[N_SCF_SHAPES_ST2];
     268             :                    Word16  search_n_gains[N_SCF_SHAPES_ST2];
     269             :                    Word32  L_mse, L_mse_min, L_idx;
     270             :                    Word16 *pulses_far, *pulses_near, *pulsesAB, *pulsesA;
     271             :                    Word16 *target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
     272             :                    Word16  tmp, err;
     273             :                }));
     274             : #endif /* ENABLE_HR_MODE */
     275             : #endif /* DYNMEM_COUNT */
     276             : 
     277           0 :     pulses_near = (Word16 *)scratchAlign(scratchBuffer, 0); /* Size = 2 * M */
     278             : 
     279           0 :     pulsesAB = (Word16 *)scratchAlign(pulses_near, sizeof(*pulses_near) * M); /* Size = 2 * M */
     280             : 
     281           0 :     pulsesA = (Word16 *)scratchAlign(pulsesAB, sizeof(*pulsesAB) * M); /* Size = 2 * M */
     282             : 
     283             : #ifdef ENABLE_HR_MODE
     284           0 :     target_w = (Word32 *)scratchAlign(pulsesA, sizeof(*pulsesA) * M); /* Size = 2 * M */
     285             : 
     286           0 :     shape_near = (Word32 *)scratchAlign(target_w, sizeof(*target_w) * M); /* Size = 4 * M */
     287             : 
     288           0 :     shapeAB = (Word32 *)scratchAlign(shape_near, sizeof(*shape_near) * M); /* Size = 4 * M */
     289             : 
     290           0 :     shapeA = (Word32 *)scratchAlign(shapeAB, sizeof(*shapeAB) * M); /* Size = 4 * M */
     291             : #else
     292             :     target_w = (Word16 *)scratchAlign(pulsesA, sizeof(*pulsesA) * M); /* Size = 2 * M */
     293             : 
     294             :     shape_near = (Word16 *)scratchAlign(target_w, sizeof(*target_w) * M); /* Size = 2 * M */
     295             : 
     296             :     shapeAB = (Word16 *)scratchAlign(shape_near, sizeof(*shape_near) * M); /* Size = 2 * M */
     297             : 
     298             :     shapeA = (Word16 *)scratchAlign(shapeAB, sizeof(*shapeAB) * M); /* Size = 2 * M */
     299             : #endif
     300             : 
     301           0 :     pulses_far = (Word16 *)scratchAlign(shapeA, sizeof(*shapeA) * M); /* Size = 2 * M */
     302             : 
     303             : #ifdef ENABLE_HR_MODE
     304           0 :     shape_far = (Word32 *)scratchAlign(pulses_far, sizeof(*pulses_far) * M); /* Size = 2 * M */
     305             : #else
     306             :     shape_far = (Word16 *)scratchAlign(pulses_far, sizeof(*pulses_far) * M); /* Size = 2 * M */
     307             : #endif
     308             : 
     309             : #ifdef WMOPS
     310             :     push_wmops("pvq_enc_find_best_submode_pre_post_fx");
     311             : #endif
     312             : 
     313             :     /* construct pulse vectors and en1 normalized shape vectors  */ /* use shape Q in Q14 */
     314           0 :     basop_memmove(pulses_far, enc_pulses_far, M * sizeof(*pulses_far));
     315           0 :     basop_memmove(pulses_near, enc_pulses_near, M * sizeof(*pulses_near));
     316           0 :     basop_memmove(target_w, target_st2, M * sizeof(*target_w));
     317             : 
     318           0 :     pvq_dec_en1_normQ14_fx(shape_near, pulses_near, sns_Kval[2][0], M); /* near outlier mode  */
     319           0 :     pvq_dec_en1_normQ14_fx(shape_far, pulses_far, sns_Kval[3][0], M);   /* far outlier mode  */
     320             : 
     321             :     /* regular mode(with a split),   prepare vectors  of full length M */
     322           0 :     basop_memmove(pulsesAB, enc_pulsesA, N_SETA * sizeof(*pulsesAB));
     323           0 :     basop_memmove(pulsesA, enc_pulsesA, N_SETA * sizeof(*pulsesA));
     324             : 
     325           0 :     FOR (i = N_SETA; i < M; i++)
     326             :     {
     327           0 :         pulsesAB[i] = enc_pulsesB[sub(i, N_SETA)]; move16();
     328             :     }
     329             : 
     330             :     IF (M > N_SETA)
     331             :     {
     332           0 :         basop_memset(&pulsesA[N_SETA], 0, (M - N_SETA) * sizeof(*pulsesA));
     333             :     }
     334             : 
     335           0 :     pvq_dec_en1_normQ14_fx(shapeAB, pulsesAB, sns_Kval[0][0], M);
     336             :     /* regular AB , b_pulses = 1 ;*/ /* OPT: combine  with shapeA */
     337             : 
     338           0 :     pvq_dec_en1_normQ14_fx(shapeA, pulsesA, sns_Kval[1][0], M);
     339             :     /* regular A ,  b_pulses = 0 */ /* OPT:  M-> N_SETA */
     340             : 
     341             :     /* setup search structure */
     342             : 
     343             :     /* now aligned with order of  j  {regular=0, regular_lf=1, outlier_near=2, outlier far=3}  */
     344             : 
     345           0 :     search_en1shape[0] = shapeAB;
     346           0 :     search_gainTab[0]  = sns_gaintabPtr[0];
     347           0 :     search_n_gains[0]  = sns_gainSz[0]; /* assumes whole bits */
     348             : 
     349           0 :     search_en1shape[1] = shapeA;
     350           0 :     search_gainTab[1]  = sns_gaintabPtr[1];
     351           0 :     search_n_gains[1]  = sns_gainSz[1]; /* assumes whole bits */
     352             : 
     353           0 :     search_en1shape[2] = shape_near;
     354           0 :     search_gainTab[2]  = sns_gaintabPtr[2];
     355           0 :     search_n_gains[2]  = sns_gainSz[2]; /*assume whole bits */
     356             : 
     357           0 :     search_en1shape[3] = shape_far;
     358           0 :     search_gainTab[3]  = sns_gaintabPtr[3];
     359           0 :     search_n_gains[3]  = sns_gainSz[3]; /*assume whole bits */
     360             : 
     361             :     /* start actual search loop */
     362             : 
     363             :     /* basic raw MSE loop,   */
     364           0 :     L_mse_min = INT32_MAX;         move32();
     365           0 :     L_idx     = L_deposit_l(-1); /* section in low 2  bits* gain idx above */
     366             : 
     367           0 :     FOR (L_section = 0; L_section < N_SCF_SHAPES_ST2; L_section++)
     368             :     {
     369             :         /* raw MSE  over gain and shape */
     370           0 :         FOR (idx = 0; idx < search_n_gains[L_section]; idx++)
     371             :         {
     372             :             /* MSE ( proc_target_local[i]-adjGain[i]*en1Shape[i] ) */
     373             : 
     374           0 :             L_mse = L_deposit_l(0);
     375           0 :             FOR (i = 0; i < M; i++)
     376             :             {
     377             : #ifdef ENABLE_HR_MODE
     378           0 :                 tmp   = Mpy_32_16_lc3plus(search_en1shape[L_section][i], search_gainTab[L_section][idx]); /* Q30 + 14 - 15 = Q29 */
     379           0 :                 err   = L_sub(target_w[i], tmp);                                                /*  both in  Q29      */
     380           0 :                 L_mse = L_add(L_mse, L_shr_pos(Mpy_32_32_lc3plus(err, err), 1)); /* Q29+29-31 = Q27 */
     381             : #else
     382             :                 tmp   = mult_r(search_gainTab[L_section][idx], search_en1shape[L_section][i]); /* Q15+14+1-16= Q14 */
     383             :                 err   = sub(target_w[i], tmp);                                                 /*  both in  Q14      */
     384             :                 L_mse = L_mac0(L_mse, err, err);                                               /* Q14+14 = Q28 */
     385             : #endif                                           /* Q14+14 = Q28 */
     386             :             }
     387             : 
     388           0 :             IF (L_sub(L_mse, L_mse_min) < 0) /* OPT: always update L_mse_min) */
     389             :             {
     390           0 :                 L_mse_min = L_mse;                          move32();
     391           0 :                 L_idx     = L_mac0(L_section, idx, 1 << 2); /* save both section and gain  idx */
     392             :             }
     393             :         } /* gains */
     394             :     }     /*submodes*/
     395             : 
     396           0 :     L_section = L_and(0x3L, L_idx); /* section was stored in two lowest bits */
     397           0 :     ASSERT(L_section >= 0 && L_section <= 3);
     398           0 :     *i_gain_ptr = extract_l(L_shr_pos(L_idx, 2)); /*1,2,3 bit gain */
     399           0 :     ASSERT(*i_gain_ptr >= 0 && *i_gain_ptr <= 7);
     400             : 
     401             :     /* returns a scaled and transformed vector, ___EXACTLY__ as a decoder would scale it */
     402           0 :     ASSERT(enc_adj_glob_warped_vec != NULL);
     403             :     {
     404             :         /* warp/rotate search result to SCF residual domain */
     405             : #ifdef ENABLE_HR_MODE
     406           0 :         idct32_32_fx(search_en1shape[L_section], target_w);
     407             : #else
     408             :         idct16_fx(search_en1shape[L_section], target_w); /* fwd synthesis  warping */
     409             : #endif
     410             :         /* actual synthesis gain scaling in SCF-residual domain, for easy weighting analysis  */
     411           0 :         pvq_dec_scale_vec_fx(target_w, search_gainTab[L_section][*i_gain_ptr], enc_adj_glob_warped_vec);
     412             :     }
     413             : 
     414           0 :     *sub_mode_ptr = extract_l(L_section);
     415           0 :     move16(); /* 0,1,2,3 */
     416             : 
     417             : #ifdef WMOPS
     418             :     pop_wmops();
     419             : #endif
     420             : #ifdef DYNMEM_COUNT
     421             :     Dyn_Mem_Out();
     422             : #endif
     423           0 :     return;
     424             : }
     425             : 
     426           0 : static void processQuantize_stage2ScfEncStage2_fx(
     427             : #ifdef ENABLE_HR_MODE
     428             :                                                   const Word32 *target_st2, Word32 *st2_vector,
     429             : #else
     430             :                                                   const Word16 *target_st2, Word16 *st2_vector,
     431             : #endif
     432             :                                                   Word32 *L_prm_idx,
     433             :                                                   Word16 submodes, Word8 *scratchBuffer) /* Size = 26 * M + 48 */
     434             : {                                                                                        /*func */
     435             : #ifdef ENABLE_HR_MODE
     436             :     Word32 *proc_target;
     437             : #else
     438             :     Word16 *proc_target;
     439             : #endif
     440             :     
     441             :     Word16 *enc_pulses_far, *enc_pulses_near, *enc_pulsesA, *enc_pulsesB;
     442             : 
     443             :     Word16 *pulses_fin, *pulses_proj;
     444             :     Word32  L_tmp;
     445             : 
     446             :     Word8 *buffer_pvq_enc_find_best_submode_pre_post_fx;
     447             : 
     448             :     PvqEntry_fx enc_PVQ_OA, enc_PVQ_B;
     449             :     Word16      submode, i_gain, submodeMSB, submodeLSB;
     450             :     Word32 *    L_search_corr, *L_search_en;
     451             : #ifdef ENABLE_HR_MODE
     452             :     Word16 *    proc_target_lp;
     453             : #endif
     454             : 
     455             : #ifdef DYNMEM_COUNT
     456             : #ifdef ENABLE_HR_MODE
     457             :     Dyn_Mem_In("processQuantize_stage2ScfEncStage2_fx", sizeof(struct {
     458             :                    Word32 *proc_target;
     459             :                    Word16 *enc_pulses_far, *enc_pulses_near, *enc_pulsesA, *enc_pulsesB;
     460             :                    Word16 *pulses_fin, *pulses_proj;
     461             :                    Word32  L_tmp;
     462             :                    Word8 *buffer_pvq_enc_find_best_submode_pre_post_fx;
     463             :                    PvqEntry_fx enc_PVQ_OA, enc_PVQ_B;
     464             :                    Word16      submode, i_gain, submodeMSB, submodeLSB;
     465             :                    Word32 *    L_search_corr, *L_search_en;
     466             :                    Word16 *    proc_target_lp;
     467             :                }));
     468             : #else
     469             :     Dyn_Mem_In("processQuantize_stage2ScfEncStage2_fx", sizeof(struct {
     470             :                    Word16 *proc_target;
     471             :                    Word16 *enc_pulses_far, *enc_pulses_near, *enc_pulsesA, *enc_pulsesB;
     472             :                    Word16 *pulses_fin, *pulses_proj;
     473             :                    Word32  L_tmp;
     474             :                    Word8 *buffer_pvq_enc_find_best_submode_pre_post_fx;
     475             :                    PvqEntry_fx enc_PVQ_OA, enc_PVQ_B;
     476             :                    Word16      submode, i_gain, submodeMSB, submodeLSB;
     477             :                    Word32 *    L_search_corr, *L_search_en;
     478             :                }));
     479             : #endif /* ENABLE_HR_MODE */
     480             : #endif /* DYNMEM_COUNT */
     481             : 
     482             : #ifdef ENABLE_HR_MODE
     483           0 :     buffer_pvq_enc_find_best_submode_pre_post_fx = (Word8 *) scratchAlign(scratchBuffer, 0);
     484           0 :     proc_target         = (Word32 *) scratchAlign(buffer_pvq_enc_find_best_submode_pre_post_fx, sizeof(*buffer_pvq_enc_find_best_submode_pre_post_fx) * 28 * M);
     485             : #else
     486             :     buffer_pvq_enc_find_best_submode_pre_post_fx = scratchAlign(scratchBuffer, 0); /* Size = 18 * M */
     487             :     proc_target =
     488             :         (Word16 *)scratchAlign(buffer_pvq_enc_find_best_submode_pre_post_fx,
     489             :                                sizeof(*buffer_pvq_enc_find_best_submode_pre_post_fx) * 18 * M); /* Size = 2 * M */
     490             : #endif
     491             : 
     492           0 :     enc_pulses_near = (Word16 *)scratchAlign(proc_target, sizeof(*proc_target) * M);         /* Size = 2 * M */
     493           0 :     enc_pulsesA     = (Word16 *)scratchAlign(enc_pulses_near, sizeof(*enc_pulses_near) * M); /* Size = 2 * N_SETA */
     494           0 :     enc_pulsesB     = (Word16 *)scratchAlign(enc_pulsesA, sizeof(*enc_pulsesA) * N_SETA);    /* Size = 2 * N_SETB */
     495           0 :     pulses_fin = (Word16 *)scratchAlign(enc_pulsesB, sizeof(*enc_pulsesB) * N_SETB); /* Size = 2 * N_SCF_SHAPES_ST2 */
     496           0 :     pulses_proj =
     497           0 :         (Word16 *)scratchAlign(pulses_fin, sizeof(*pulses_fin) * N_SCF_SHAPES_ST2); /* Size = 2 * N_SCF_SHAPES_ST2 */
     498           0 :     L_search_corr =
     499           0 :         (Word32 *)scratchAlign(pulses_proj, sizeof(*pulses_proj) * N_SCF_SHAPES_ST2); /* Size = 4 * N_SCF_SHAPES_ST2 */
     500           0 :     L_search_en    = (Word32 *)scratchAlign(L_search_corr,
     501             :                                          sizeof(*L_search_corr) * N_SCF_SHAPES_ST2); /* Size = 4 * N_SCF_SHAPES_ST2 */
     502           0 :     enc_pulses_far = (Word16 *)scratchAlign(L_search_en, sizeof(*L_search_en) * N_SCF_SHAPES_ST2); /* Size = 2 * M */
     503             : 
     504             : #ifdef ENABLE_HR_MODE
     505           0 :     proc_target_lp      = (Word16 *)buffer_pvq_enc_find_best_submode_pre_post_fx; /* size = 2*M */
     506             : #endif
     507             :     
     508             : #ifdef WMOPS
     509             :     push_wmops("processQuantize_stage2ScfEncStage2_fx");
     510             : #endif
     511             : 
     512             :     /* fixed setup for a given  bitrate of 38 ,  no  moves needed */
     513             :     /* k_far  = sns_Kval[3][0]; */
     514             :     /* k_near = sns_Kval[2][0]; */
     515             :     /* kA     = sns_Kval[1][0]; */ /* regular, regular_lf */
     516             :                                    /* kB is always  1 */
     517             : 
     518             :     /* NB  these search indecese do not correspond exactly to specification shape_index j */
     519             : 
     520           0 :     pulses_fin[0] = sns_Kval[3][0]; /* far   6 */
     521           0 :     pulses_fin[1] = sns_Kval[2][0]; /* near  8 */
     522           0 :     pulses_fin[2] = sns_Kval[1][0]; /* section A     10 */
     523           0 :     pulses_fin[3] = sns_Kval[0][1]; /* section B     1 */
     524             : 
     525           0 :     pulses_proj[0] = sns_Kval[3][0];
     526           0 :     pulses_proj[1] = 0;
     527           0 :     pulses_proj[2] = 0;
     528           0 :     pulses_proj[3] = 0;
     529             : 
     530             :     /*  pre_process  */
     531             : #ifdef ENABLE_HR_MODE
     532           0 :     dct32_fx(target_st2, proc_target); /* enc analysis */
     533           0 :     downshift_w32_arr(proc_target, proc_target_lp, 16, M);
     534             : 
     535             :     /* get the initial four integer shape candidate vectors,  no normalization at this stage  */
     536           0 :     pvq_enc_search_fx(proc_target_lp, enc_pulses_far, enc_pulses_near, enc_pulsesA, enc_pulsesB, L_search_corr,
     537             :                       L_search_en, pulses_fin, pulses_proj, M, N_SETA);
     538             : #else
     539             :     Word32 target_st2_32[M]; Word32 proc_target_32[M]; int i;
     540             :     
     541             :     FOR (i = 0; i < M; i++)
     542             :     {
     543             :         target_st2_32[i] = L_shl_pos(target_st2[i], 16);
     544             :     }
     545             :     
     546             :     dct32_fx(target_st2_32, proc_target_32); /* enc analysis */
     547             :     
     548             :     downshift_w32_arr(proc_target_32, proc_target, 16, M);
     549             : 
     550             :     /* get the initial four integer shape candidate vectors,  no normalization at this stage  */
     551             :     pvq_enc_search_fx(proc_target, enc_pulses_far, enc_pulses_near, enc_pulsesA, enc_pulsesB, L_search_corr,
     552             :                       L_search_en, pulses_fin, pulses_proj, M, N_SETA);
     553             : #endif
     554             : 
     555             :     /* scale with gains a after a  unit energy fwd transform  */
     556             :     /* apply transform to each candidate shape vector priot  to gain-shape search loop */
     557           0 :     submode = submodes; /* used as input solely to debug/unit test a specific shape mode  */
     558             : 
     559             :     /*target should be in a  linearized residual domain target */
     560             :     /* search pre, synthesis  post*/
     561           0 :     pvq_enc_find_best_submode_pre_post_fx(proc_target, enc_pulses_far, enc_pulses_near, enc_pulsesA, enc_pulsesB,
     562             :                                           &submode, &i_gain, st2_vector,
     563             :                                           buffer_pvq_enc_find_best_submode_pre_post_fx); /* Q14 tr out */
     564             : 
     565             :     /* send parameters  to multiplexor as a series/vector  of Long Words */
     566             :     /*    0 :    0..3  submode  */
     567             :     /*    1 :    0..7  gain_ind  */
     568             :     /*    2 :    0..1  LeadSign ind */
     569             :     /*    3 :    25 bit     MPVQ index    outl_near or  A  part  */
     570             :     /*    4 :    3.7 to 21 bits  MPVQ index           B  part  OR   -2  */
     571             : 
     572           0 :     L_prm_idx[0] = L_deposit_l(submode); /*  complete submode fwd'ed  to ari_codec as  0,1,2,3  */
     573             : 
     574           0 :     submodeMSB = shr_pos(submode, 1);                       /* LSB of submode , sent as main submode bit  */
     575           0 :     submodeLSB = s_and(submode, 0x1); /* LSB of submode  */ /*   sent via shape param  */
     576             : 
     577             :     /* gain, shape indicese , incl. calls to  MPVQ indexing */
     578           0 :     IF (submodeMSB == 0)
     579             :     { /* regular modes::   j=0(reg=AB)  or 1(reg_lf  A)  */ /* regular mode, with two or one shape indices  */
     580             : 
     581             :         /* assume regular_lf part ,  shape_j == 1 */
     582             :         enc_PVQ_OA =
     583           0 :             mpvq_index_fx(enc_pulsesA, N_SETA, sns_Kval[submode][0]); /* o : leading_sign_index, index, size, k_val */
     584           0 :         L_prm_idx[2] = L_deposit_l(enc_PVQ_OA.lead_sign_ind);         /*LS set A */
     585             : 
     586           0 :         ASSERT(enc_PVQ_OA.size == (UWord32)sns_MPVQ_Sz[submode][0]);
     587           0 :         L_prm_idx[3] = L_add(0L, (Word32)enc_PVQ_OA.index); /* MPVQ shape index set A fractional   */
     588             : 
     589             :         /* section B always have low indexing dynamics and is  combined into one joint single  index */
     590           0 :         IF (submodeLSB == 0)
     591             :         {                                                                              /* regular   AB  , shape_j == 0*/
     592           0 :             L_prm_idx[1] = L_deposit_l(i_gain); /* full established gain idx fwd'ed */ /*      2  possible values */
     593           0 :             enc_PVQ_B    = mpvq_index_fx(enc_pulsesB, N_SETB, 1);
     594           0 :             ASSERT(((enc_PVQ_B.size << 1)) ==
     595             :                    (sns_MPVQ_Sz[submode][1])); /*  two lowest indeces indicate all_zero B section  */
     596             : 
     597           0 :             L_tmp        = L_shl_pos((Word32)enc_PVQ_B.index, 1);            /* 2*section B  MPVQ index */
     598           0 :             L_prm_idx[4] = L_add(L_tmp, enc_PVQ_B.lead_sign_ind); move32(); /* add joint section B and  LS index */
     599             : 
     600           0 :             ASSERT(L_prm_idx[4] >= 0 && L_prm_idx[4] < (Word32)sns_MPVQ_Sz[submode][0]);
     601             :         }
     602             :         ELSE
     603             :         {
     604           0 :             L_prm_idx[1] = L_deposit_l(i_gain);
     605             :             /* MSBs of established gain idx */ /*  2 or 4   total  possible values */
     606           0 :             L_prm_idx[4] = L_deposit_l(-2);
     607             :         }
     608             :     }
     609             :     ELSE
     610             :     {
     611             :         /* outlier  modes   shape_j= 2(near, LSB=0) or 3(far, LSB=1)  */
     612             : 
     613           0 :         IF (submodeLSB == 0)
     614             :         {
     615           0 :             L_prm_idx[1] = L_deposit_l(i_gain); /* established gain idx  */ /*   4  possible values */
     616           0 :             enc_PVQ_OA   = mpvq_index_fx(enc_pulses_near, M,
     617           0 :                                        sns_Kval[submode][0]); /* o :  leading_sign_index,  index, size, k_val        */
     618           0 :             ASSERT(enc_PVQ_OA.size == sns_MPVQ_Sz[submode][0]);
     619           0 :             L_prm_idx[3] = L_add(0L, enc_PVQ_OA.index); /* MPVQ index  fractional bits */
     620           0 :             L_prm_idx[4] = L_deposit_l(-1);             /* no gain LSBs  */
     621             :         }
     622             :         ELSE
     623             :         {
     624           0 :             L_prm_idx[1] = L_deposit_l(i_gain); /* established gain idx MSBs   */ /*   all 4 or 8   possible values */
     625           0 :             enc_PVQ_OA   = mpvq_index_fx(enc_pulses_far, M,
     626           0 :                                        sns_Kval[submode][0]); /* o :  leading_sign_index,  index, size, k_val        */
     627           0 :             ASSERT(enc_PVQ_OA.size == sns_MPVQ_Sz[submode][0]);
     628           0 :             L_prm_idx[3] = L_add(0L, enc_PVQ_OA.index); /* MPVQ index  fractional bits */
     629           0 :             L_prm_idx[4] = L_deposit_l(-2);             /*  */
     630             :         }
     631           0 :         L_prm_idx[2] = L_deposit_l(enc_PVQ_OA.lead_sign_ind); /* LS shape single bit */
     632             :     }
     633             : 
     634             : #ifdef WMOPS
     635             :     pop_wmops();
     636             : #endif
     637             : #ifdef DYNMEM_COUNT
     638             :     Dyn_Mem_Out();
     639             : #endif
     640           0 :     return;
     641             : }
     642             : 
     643           0 : static Word16 scfdec_stage2_fx(                          /* o: ber flag */
     644             :                                const Word32 *L_prm_idx,  /* set to -1 if not used */
     645             : #ifdef ENABLE_HR_MODE
     646             :                                Word32 *      st2_vector, /*o: Q14 */
     647             : #else
     648             :                                Word16 *      st2_vector, /*o: Q14 */
     649             : #endif
     650             :                                Word8 *       scratchBuffer)
     651             : {
     652             :     /*   MPVQ deindexing, gainscaling transform and transform */
     653             : #ifdef ENABLE_HR_MODE
     654             :     Dyn_Mem_Deluxe_In(
     655             :         Word16  submode;
     656             :         Word16  submodeLSB, submodeMSB;
     657             :         Word16  gValQ13;
     658             :         Word16  idxB;
     659             :         Word16  maxK;
     660             :         Word16  BER_dec;
     661             :         Word16 *dec_pulses;
     662             :         Word32 *dec_en1_vec;
     663             :         Word32 *dec_adj_glob_vec;
     664             :     );
     665             : #else
     666             :     Dyn_Mem_Deluxe_In(
     667             :         Word16  submode;
     668             :         Word16  submodeLSB, submodeMSB;
     669             :         Word16  gValQ13;
     670             :         Word16  idxB;
     671             :         Word16  maxK;
     672             :         Word16  BER_dec;
     673             :         Word16 *dec_pulses;
     674             :         Word16 *dec_en1_vec;
     675             :         Word16 *dec_adj_glob_vec;
     676             :     );
     677             : #endif
     678             : 
     679             : #ifdef WMOPS
     680             :     push_wmops("scfdec_stage2_fx");
     681             : #endif
     682             : 
     683           0 :     dec_pulses       = (Word16 *)scratchAlign(scratchBuffer, 0);                      /* Size = 2 * M = 32 bytes */
     684             : #ifdef ENABLE_HR_MODE
     685           0 :     dec_en1_vec      = (Word32 *)scratchAlign(dec_pulses, sizeof(*dec_pulses) * M);   /* Size = 2 * M = 32 bytes */
     686           0 :     dec_adj_glob_vec = (Word32 *)scratchAlign(dec_en1_vec, sizeof(*dec_en1_vec) * M); /* Size = 2 * M = 32 bytes */
     687             : #else
     688             :     dec_en1_vec      = (Word16 *)scratchAlign(dec_pulses, sizeof(*dec_pulses) * M);   /* Size = 2 * M = 32 bytes */
     689             :     dec_adj_glob_vec = (Word16 *)scratchAlign(dec_en1_vec, sizeof(*dec_en1_vec) * M); /* Size = 2 * M = 32 bytes */
     690             : #endif
     691             : 
     692             :     /* get submode   */
     693           0 :     submode = extract_l(L_prm_idx[0]); /* 0..3 */
     694             : 
     695           0 :     submodeLSB = s_and(submode, 0x1);
     696           0 :     submodeMSB = shr_pos(submode, 1);
     697             : 
     698             :     /* get initial adjustment gain vector for  regular, outl_near   */
     699           0 :     ASSERT(L_prm_idx[1] >= 0 && L_prm_idx[1] < sns_gainSz[submode]);
     700           0 :     gValQ13 = sns_gaintabPtr[submode][L_prm_idx[1]];
     701           0 :     ASSERT(gValQ13 >= 0);
     702             : 
     703             :     /* gain, shape indices,  incl.calls  to MPVQ deindexing */
     704           0 :     IF (submodeMSB != 0)
     705             :     {
     706             :         /* outlier_near or outlier_far  mode decoding */
     707           0 :         maxK    = sns_Kval[submode][0]; move16();
     708           0 :         BER_dec = pvq_dec_deidx_fx(dec_pulses, maxK, M, extract_l(L_prm_idx[2]), (UWord32)L_prm_idx[3]);
     709             :     }
     710             :     ELSE
     711             :     { /* regular mode, with potentially two shape indices  */
     712             : 
     713           0 :         maxK    = sns_Kval[submode][0]; move16();
     714           0 :         BER_dec = pvq_dec_deidx_fx(dec_pulses, maxK, N_SETA, extract_l(L_prm_idx[2]), (UWord32)L_prm_idx[3]);
     715             : 
     716           0 :         IF (submodeLSB == 0)
     717             :         {
     718           0 :             idxB = extract_l(L_prm_idx[4]); /* 0..11 */
     719           0 :             ASSERT(idxB >= 0 && idxB < (Word16)sns_MPVQ_Sz[0][1]);
     720           0 :             BER_dec |= pvq_dec_deidx_fx(&(dec_pulses[N_SETA]), sns_Kval[submode][1], N_SETB, s_and(idxB, 0x1),
     721           0 :                                         (UWord32)L_deposit_l(shr_pos(idxB, 1)));
     722             :             /* maxK does not need to be increased as set B is not stacked  */
     723             :         }
     724             :         ELSE
     725             :         { /* LSB gain bit already parsed */
     726           0 :             ASSERT(L_prm_idx[4] < 0);
     727           0 :             basop_memset(&dec_pulses[N_SETA], 0, (N_SETB) * sizeof(*dec_pulses));
     728             :         }
     729             :     }
     730             : 
     731             :     /* normalize decoded integer vector , exactly as on encoder side !!  */
     732           0 :     pvq_dec_en1_normQ14_fx(dec_en1_vec, dec_pulses, maxK, M);
     733             : 
     734             : #ifdef ENABLE_HR_MODE
     735           0 :     idct32_32_fx(dec_en1_vec, dec_adj_glob_vec);
     736             : #else
     737             :     idct16_fx(dec_en1_vec, dec_adj_glob_vec); /* fwd warping  in unscaled domain */
     738             : #endif
     739             : 
     740             :     /* scaling aligend with encoder search  */
     741           0 :     pvq_dec_scale_vec_fx(dec_adj_glob_vec, gValQ13, st2_vector);
     742             : 
     743             : #ifdef WMOPS
     744             :     pop_wmops();
     745             : #endif
     746             :     Dyn_Mem_Deluxe_Out();
     747           0 :     return BER_dec;
     748             : }
     749             : 
     750           0 : void processSnsQuantizeScfEncoder_fx(Word16  scf[],        /* i: input scf M */
     751             :                                      Word32 *L_prm_idx,    /* o: indeces . negative == unused */
     752             : #ifdef ENABLE_HR_MODE
     753             :                                      Word32 *scf_q,        /* o: quantized scf M */
     754             : #else
     755             :                                      Word16 *scf_q,        /* o: quantized scf M */
     756             : #endif
     757             :                                      Word8 * scratchBuffer) /* Size = 28 * M + 52 */
     758             : {
     759             : #ifdef ENABLE_HR_MODE
     760             :     Dyn_Mem_Deluxe_In(
     761             :         Word32 *target_st2; 
     762             :         Word16 *st1_idx; /* stage 1 indices */
     763             :         Word8 * buffer_processQuantize_stage2ScfEncStage2_fx;
     764             :         Counter col;
     765             :     );
     766             : #else
     767             :     Dyn_Mem_Deluxe_In(
     768             :         Word16 *target_st2;
     769             :         Word16 *st1_idx; /* stage 1 indices */
     770             :         Word8 * buffer_processQuantize_stage2ScfEncStage2_fx;
     771             :         Counter col;
     772             :     );
     773             : #endif
     774             : 
     775             : #ifdef ENABLE_HR_MODE
     776           0 :     target_st2 = (Word32 *)scratchAlign(scratchBuffer, 0);                    /* Size = 2 * M */
     777             : #else
     778             :     target_st2 = (Word16 *)scratchAlign(scratchBuffer, 0);                    /* Size = 2 * M */
     779             : #endif
     780           0 :     st1_idx    = (Word16 *)scratchAlign(target_st2, sizeof(*target_st2) * M); /* Size = 2 * 2 */
     781           0 :     buffer_processQuantize_stage2ScfEncStage2_fx = (Word8 *)scratchAlign(st1_idx, sizeof(*st1_idx) * M);
     782             :     /* Size = 26 * M + 48 */
     783             : 
     784             :     /* TBD needs update  */
     785             : 
     786             :     /* 1st stage trained VQ   */
     787           0 :     processQuantize_stage1ScfEncStage1_fx(scf, scf_q, &st1_idx[0], &st1_idx[1]);
     788           0 :     L_prm_idx[0] = L_deposit_l(st1_idx[0]);
     789           0 :     L_prm_idx[1] = L_deposit_l(st1_idx[1]);
     790             : 
     791             : /* 2nd stage PVQ-based SCF quantizer   */
     792           0 :     FOR (col = 0; col < M; col++)
     793             :     {
     794             : #ifdef ENABLE_HR_MODE
     795           0 :         target_st2[col] = L_sub(L_deposit_h(scf[col]), scf_q[col]);
     796             : #else
     797             :         target_st2[col] = sub(scf[col], scf_q[col]);
     798             : #endif
     799             :     }
     800             : 
     801           0 :     processQuantize_stage2ScfEncStage2_fx(target_st2, scf_q, &L_prm_idx[2], VQMODES26,   /* 0xF means all submodes */
     802             :                                           buffer_processQuantize_stage2ScfEncStage2_fx); /*  PVQ  in stage 2 */
     803             :     Dyn_Mem_Deluxe_Out();
     804           0 : }
     805             : 
     806           0 : Word16 processSnsQuantizeScfDecoder_fx(                                      /* o: BER flag */
     807             :                                        Word32 *L_prm_idx,                    /* i: indeces */
     808             : #ifdef ENABLE_HR_MODE
     809             :                                        Word32 scf_q[],
     810             : #else 
     811             :                                        Word16 scf_q[],
     812             : #endif
     813             :                                        Word8 *scratchBuffer) /* o:  M */
     814             : {
     815             :     Dyn_Mem_Deluxe_In(
     816             :         Word16 BER_flag;
     817             :     );
     818             : 
     819             :     /* Decode First Stage */
     820             : #ifdef ENABLE_HR_MODE
     821           0 :     processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q27, st1SCF8_15_base5_32x8_Q27,
     822           0 :                                             extract_l(L_prm_idx[0]), extract_l(L_prm_idx[1]), scf_q);
     823             : #else
     824             :     processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q11, st1SCF8_15_base5_32x8_Q11,
     825             :                                             extract_l(L_prm_idx[0]), extract_l(L_prm_idx[1]), scf_q);
     826             : #endif
     827             : 
     828             :     /* Decode Second Stage */
     829           0 :     BER_flag = scfdec_stage2_fx(&(L_prm_idx[2]), scf_q, scratchBuffer);
     830             : 
     831             :     Dyn_Mem_Deluxe_Out();
     832           0 :     return BER_flag;
     833             : }
     834             : 

Generated by: LCOV version 1.14