LCOV - code coverage report
Current view: top level - lib_lc3plus - pvq_index_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 0 152 0.0 %
Date: 2025-08-23 01:22:27 Functions: 0 14 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             : #define SIGNBIT_FX 0x80000000u
      13             : #define SIGNBIT_SHRT_FX 0x8000
      14             : 
      15           0 : static void initOffsets_fx(Word16 dim_in, UWord32 *h_mem,
      16             :                            Word16 k_val_in) /* may be removed with tables for N=16,10,6  */
      17             : {
      18             :     UWord32 k_val_prev, k_val_curr;
      19             :     UWord32 k_val, UL_k_val_in;
      20             : #ifdef DYNMEM_COUNT
      21             :     Dyn_Mem_In("initOffsets_fx", sizeof(struct {
      22             :                    UWord32 k_val_prev, k_val_curr;
      23             :                    UWord32 k_val, UL_k_val_in;
      24             :                }));
      25             : #endif
      26             : 
      27           0 :     h_mem[0] = UL_deposit_l(0);
      28           0 :     h_mem[1] = UL_deposit_l(1);
      29             : 
      30           0 :     UL_k_val_in = UL_deposit_l(k_val_in);
      31           0 :     IF (sub(dim_in, 2) == 0)
      32             :     {
      33           0 :         FOR (k_val = 2; k_val <= UL_k_val_in; k_val++)
      34             :         {
      35           0 :             h_mem[k_val] = UL_subNsD(UL_lshl(k_val, 1), 1U); move32();
      36             :         }
      37           0 :         h_mem[k_val] = UL_k_val_in; move32();
      38             :     }
      39             :     ELSE
      40             :     {
      41           0 :         k_val_prev = UL_deposit_l(1U);
      42           0 :         FOR (k_val_curr = 2; k_val_curr <= UL_k_val_in; k_val_curr++)
      43             :         {
      44           0 :             h_mem[k_val_curr] = UL_addNsD(1U, UL_Mpy_32_32(k_val_curr, UL_lshl(k_val_prev, 1))); move32();
      45           0 :             k_val_prev        = UL_addNsD(k_val_curr, 0U);
      46             :         }
      47           0 :         h_mem[k_val_curr] = UL_Mpy_32_32(k_val_curr, k_val_prev); move32();
      48             :     }
      49             : 
      50             : #ifdef DYNMEM_COUNT
      51             :     Dyn_Mem_Out();
      52             : #endif
      53           0 : }
      54             : 
      55           0 : static void a_fwd_fx(UWord32 *a_in,   /* i/o: offsets   */
      56             :                      Word16   n_items /* i  :  items, k's  */
      57             : )
      58             : {
      59             :     UWord32  a_1, a_in0;
      60             :     Counter  i;
      61             :     UWord32 *a_in_prev_ptr;
      62             : 
      63             : #ifdef DYNMEM_COUNT
      64             :     Dyn_Mem_In("a_fwd_fx", sizeof(struct {
      65             :                    UWord32  a_1, a_in0;
      66             :                    Counter  i;
      67             :                    UWord32 *a_in_prev_ptr;
      68             :                }));
      69             : #endif
      70             : 
      71           0 :     a_in0 = UL_deposit_l(1);
      72             : 
      73           0 :     a_in_prev_ptr = &(a_in[-1]);
      74           0 :     FOR (i = 1; i <= n_items; i++)
      75             :     {
      76           0 :         a_1              = UL_addNsD(a_in0, UL_addNsD(a_in_prev_ptr[i], a_in[i]));
      77           0 :         a_in_prev_ptr[i] = a_in0; move32();
      78           0 :         a_in0            = UL_addNsD(a_1, 0U);
      79             :     }
      80           0 :     a_in_prev_ptr[i] = a_in0; move32();
      81             : 
      82             : #ifdef DYNMEM_COUNT
      83             :     Dyn_Mem_Out();
      84             : #endif
      85           0 : }
      86             : 
      87           0 : static void a_bwd_fx(UWord32 *a_in,   /* i/o: offsets   */
      88             :                      Word16   n_items /* i:  n_items  */
      89             : )
      90             : {
      91             :     UWord32  a_1, a_in0;
      92             :     Counter  i;
      93             :     UWord32 *a_in_prev_ptr;
      94             : 
      95             : #ifdef DYNMEM_COUNT
      96             :     Dyn_Mem_In("a_bwd_fx", sizeof(struct {
      97             :                    UWord32  a_1, a_in0;
      98             :                    Counter  i;
      99             :                    UWord32 *a_in_prev_ptr;
     100             :                }));
     101             : #endif
     102             : 
     103           0 :     a_in0         = UL_deposit_l(0);
     104           0 :     a_in_prev_ptr = &(a_in[-1]);
     105             : 
     106           0 :     FOR (i = 1; i <= n_items; i++)
     107             :     {
     108           0 :         a_1              = UL_subNsD(UL_subNsD(a_in[i], a_in0), a_in_prev_ptr[i]);
     109           0 :         a_in_prev_ptr[i] = a_in0; move32();
     110           0 :         a_in0            = UL_addNsD(a_1, 0U);
     111             :     }
     112           0 :     a_in_prev_ptr[i] = a_in0; move32();
     113             : 
     114             : #ifdef DYNMEM_COUNT
     115             :     Dyn_Mem_Out();
     116             : #endif
     117           0 : }
     118             : 
     119           0 : static void a_u_fwd_fx(UWord32 *a_u_in, Word16 k_val_in, Word16 mem_size_m1)
     120             : {
     121             :     UWord32 u_kp1_prev, u_kp1;
     122             :     UWord32 u_k_prev;
     123             : 
     124             : #ifdef DYNMEM_COUNT
     125             :     Dyn_Mem_In("a_u_fwd_fx", sizeof(struct {
     126             :                    UWord32 u_kp1_prev, u_kp1;
     127             :                    UWord32 u_k_prev;
     128             :                }));
     129             : #endif
     130             : 
     131           0 :     u_kp1_prev = a_u_in[mem_size_m1]; move32();
     132           0 :     u_k_prev   = UL_lshr(a_u_in[k_val_in], 1);
     133             : 
     134           0 :     a_fwd_fx(&a_u_in[1], k_val_in);
     135             : 
     136           0 :     u_kp1               = UL_lshr(a_u_in[k_val_in], 1);
     137           0 :     a_u_in[mem_size_m1] = UL_addNsD(1U, UL_addNsD(u_kp1_prev, UL_addNsD(u_k_prev, u_kp1)));
     138             : 
     139             : #ifdef DYNMEM_COUNT
     140             :     Dyn_Mem_Out();
     141             : #endif
     142           0 : }
     143             : 
     144           0 : static Word16 get_lead_sign_fx(UWord32 *ind)
     145             : {
     146             :     Word16 leading_sign;
     147             : 
     148             : #ifdef DYNMEM_COUNT
     149             :     Dyn_Mem_In("get_lead_sign_fx", sizeof(struct { Word16 leading_sign; }));
     150             : #endif
     151             : 
     152           0 :     leading_sign = 1; move16();
     153           0 :     if (UL_and(*ind, 1) != 0)
     154             :     {
     155           0 :         leading_sign = -1; move16();
     156             :     }
     157           0 :     (*ind) = UL_lshr(*ind, 1);
     158             : 
     159             : #ifdef DYNMEM_COUNT
     160             :     Dyn_Mem_Out();
     161             : #endif
     162             : 
     163           0 :     return leading_sign;
     164             : }
     165             : 
     166             : /*-------------------------------------------------------------------*
     167             :  * mind2vec_one_fx()
     168             :  *-------------------------------------------------------------------*/
     169           0 : static void mind2vec_one_fx(Word16  k_val_in,                           /* i:  nb unit pulses    , [ 0...K_MAX ]   */
     170             :                             Word16  leading_sign,                       /* i: leading sign  -1, 0, 1*/
     171             :                             UWord32 ind, /* i:  index                */ /* parameter could  be omitted */
     172             :                             Word16 *vec_out                             /* o:  pulse train          */
     173             : )
     174             : {
     175           0 :     *vec_out = (Word16)ind; /* dummy assignment to handle the common ind parameter warning  */
     176             : 
     177           0 :     if (leading_sign < 0)
     178             :     {
     179           0 :         k_val_in = negate(k_val_in);
     180             :     }
     181           0 :     *vec_out = k_val_in; move16();
     182           0 : }
     183             : 
     184           0 : static Word16 setval_update_sign_fx(Word16 k_delta, Word16 k_max_local, Word16 *leading_sign, UWord32 *ind_in,
     185             :                                     Word16 *vec_out)
     186             : {
     187           0 :     IF (k_delta != 0)
     188             :     {
     189           0 :         mind2vec_one_fx(k_delta, *leading_sign, *ind_in, vec_out);
     190           0 :         *leading_sign = get_lead_sign_fx(ind_in);
     191           0 :         k_max_local   = sub(k_max_local, k_delta);
     192             :     }
     193           0 :     return k_max_local;
     194             : }
     195             : 
     196             : /*-------------------------------------------------------------------*
     197             :  * mind2vec_fx()
     198             :  *-------------------------------------------------------------------*/
     199           0 : static void mind2vec_fx(Word16   dim_in,       /* i:  dimension        */
     200             :                         Word16   k_max_local,  /* i:  nb unit pulses   */
     201             :                         Word16   leading_sign, /* i: leading sign  */
     202             :                         UWord32  ind,          /* i:  index            */
     203             :                         Word16 * vec_out,      /* o:  pulse train      */
     204             :                         UWord32 *h_in          /* i:  offset vector   A=1+2U  */
     205             : )
     206             : {
     207             :     Counter pos;
     208             :     Word16  k_acc, k_delta;
     209             :     UWord32 UL_tmp_offset, UL_diff;
     210             :     UWord16 sgn;
     211             : 
     212             : #ifdef DYNMEM_COUNT
     213             :     Dyn_Mem_In("mind2vec_fx", sizeof(struct {
     214             :                    Counter pos;
     215             :                    Word16  k_acc, k_delta;
     216             :                    UWord32 UL_tmp_offset, UL_diff;
     217             :                    UWord16 sgn;
     218             :                }));
     219             : #endif
     220             : 
     221           0 :     k_acc = k_max_local; move16();
     222           0 :     FOR (pos = 0; pos < dim_in; pos++)
     223             :     {
     224             : 
     225           0 :         IF (ind != 0)
     226             :         {
     227             : 
     228           0 :             k_acc = k_max_local; move16();
     229             : 
     230           0 :             UL_tmp_offset = UL_addNsD(h_in[k_acc], 0U);
     231             : 
     232           0 :             UL_diff = UL_subNs(ind, UL_tmp_offset, &sgn);
     233             : 
     234           0 :             WHILE (sgn)
     235             :             {
     236           0 :                 UL_diff = UL_subNs(ind, h_in[--k_acc], &sgn);
     237             :             }
     238             : 
     239           0 :             ind = UL_addNsD(UL_diff, 0U);
     240             : 
     241           0 :             k_delta = sub(k_max_local, k_acc);
     242             :         }
     243             :         ELSE
     244             :         {
     245           0 :             mind2vec_one_fx(k_max_local, leading_sign, ind, &vec_out[pos]);
     246           0 :             BREAK;
     247             :         }
     248             : 
     249           0 :         k_max_local = setval_update_sign_fx(k_delta, k_max_local, &leading_sign, &ind, &vec_out[pos]);
     250             : 
     251           0 :         a_bwd_fx(h_in, add(k_max_local, 1));
     252             :     }
     253             : 
     254             : #ifdef DYNMEM_COUNT
     255             :     Dyn_Mem_Out();
     256             : #endif
     257           0 : }
     258             : 
     259           0 : PvqEntry_fx get_size_mpvq_calc_offset_fx(                   /* o : size, dim, k_val        */
     260             :                                          Word16   dim_in,   /* i : dimension                */
     261             :                                          Word16   k_val_in, /* i : nb unit pulses           */
     262             :                                          UWord32 *h_mem     /* o : offsets                  */
     263             : )
     264             : {
     265             :     Counter     i;
     266             :     PvqEntry_fx entry;
     267             :     Word16      kp1;
     268             : 
     269             : #ifdef DYNMEM_COUNT
     270             :     Dyn_Mem_In("get_size_mpvq_calc_offset_fx", sizeof(struct {
     271             :                    Counter     i;
     272             :                    PvqEntry_fx entry;
     273             :                    Word16      kp1;
     274             :                }));
     275             : #endif
     276             : 
     277           0 :     entry.dim   = dim_in;   move16();
     278           0 :     entry.k_val = k_val_in; move16();
     279             : 
     280           0 :     entry.index         = L_deposit_l(0);
     281           0 :     entry.lead_sign_ind = 0; move16();
     282             : 
     283           0 :     ASSERT(dim_in <= M);
     284           0 :     ASSERT(tabledKMAX[dim_in] != 0);
     285             : 
     286             :     /* tabled values for worst case K */ /* made into table lookup for N=16, 10, 6  */
     287           0 :     kp1 = add(k_val_in, 1);
     288           0 :     FOR (i = 0; i <= kp1; i++) /* A+U copying */
     289             :     {
     290           0 :         h_mem[i] =
     291           0 :             UL_addNsD(MPVQ_offs_ptr[dim_in][i], 0U); /* a vector  copying is needed as MPVQ recursion is in place */
     292             :     }
     293             :     /* special handling of last  U offset   in k+1 column  */
     294           0 :     if (sub(k_val_in, tabledKMAX[dim_in]) != 0)
     295             :     {
     296           0 :         h_mem[kp1] = UL_lshr(h_mem[kp1], 1); /* (A+1)/2 , convert from  A(K+1) to  U(K+1)  domain */
     297             :     }
     298           0 :     entry.size =
     299           0 :         UL_addNsD(1U, UL_addNsD(h_mem[kp1], UL_lshr(h_mem[k_val_in], 1))); /* MPVQ size calc. 1 + H(K+1) + (A(K)>>1) */
     300             : 
     301             : #ifdef DYNMEM_COUNT
     302             :     Dyn_Mem_Out();
     303             : #endif
     304             : 
     305           0 :     return entry;
     306             : }
     307             : 
     308             : /*-------------------------------------------------------------------*
     309             :  * mpvq_deindex_fx()
     310             :  *-------------------------------------------------------------------*/
     311           0 : void mpvq_deindex_fx(                           /* o :  void                        */
     312             :                      const PvqEntry_fx *entry,  /* i :  sign_ind, index, dim, k_val */
     313             :                      UWord32 *          h_mem,  /* i :  A/U offsets                 */
     314             :                      Word16 *           vec_out /* o :  pulse train                 */
     315             : )
     316             : {
     317             :     Word16 leading_sign;
     318             : #ifdef DYNMEM_COUNT
     319             :     Dyn_Mem_In("mpvq_deindex_fx", sizeof(struct { Word16 leading_sign; }));
     320             : #endif
     321             : #ifdef WMOPS
     322             :     push_wmops("mpvq_deindex_fx");
     323             : #endif
     324             : 
     325           0 :     basop_memset(vec_out, 0, (entry->dim) * sizeof(Word16));
     326             : 
     327           0 :     leading_sign = 1; move16();
     328           0 :     if (entry->lead_sign_ind != 0)
     329             :     {
     330           0 :         leading_sign = -1; move16();
     331             :     }
     332             : 
     333           0 :     IF (entry->k_val != 0)
     334             :     {
     335           0 :         mind2vec_fx(entry->dim, entry->k_val, leading_sign, entry->index, vec_out, h_mem);
     336             :     }
     337             : #ifdef DYNMEM_COUNT
     338             :     Dyn_Mem_Out();
     339             : #endif
     340             : #ifdef WMOPS
     341             :     pop_wmops();
     342             : #endif
     343           0 : }
     344             : 
     345             : /*-------------------------------------------------------------------*
     346             :  * vec2mind_two_fx()
     347             :  *-------------------------------------------------------------------*/
     348           0 : static void vec2mind_two_fx(const Word16 *vec_in,        /* i : PVQ  pulse train        */
     349             :                             Word16 *      k_val_out_ptr, /* o : number of unit pulses    */
     350             :                             UWord32 *     next_sign_ind, /* i/o: next sign ind           */
     351             :                             UWord32 *     ind            /* o: MPVQ index                */
     352             : )
     353             : {
     354             :     UWord32 lead_sign_ind_add;
     355             :     Word16  abs0, abs1, abs01, sptr;
     356             : 
     357             : #ifdef DYNMEM_COUNT
     358             :     Dyn_Mem_In("vec2mind_two_fx", sizeof(struct {
     359             :                    UWord32 lead_sign_ind_add;
     360             :                    Word16  abs0, abs1, abs01, sptr;
     361             :                }));
     362             : #endif
     363             : 
     364           0 :     abs0           = abs_s(vec_in[0]);
     365           0 :     abs1           = abs_s(vec_in[1]);
     366           0 :     abs01          = add(abs0, abs1);
     367           0 :     *k_val_out_ptr = abs01; move16();
     368           0 :     *ind           = UL_deposit_l(0);
     369             : 
     370           0 :     *next_sign_ind = UL_deposit_h(SIGNBIT_SHRT_FX);
     371             : 
     372           0 :     IF (abs01 != 0)
     373             :     {
     374           0 :         sptr           = 0; move16();
     375           0 :         *next_sign_ind = UL_deposit_l(sptr);
     376             : 
     377           0 :         test();
     378           0 :         IF (abs0 != 0 && abs1 != 0)
     379             :         {
     380           0 :             lead_sign_ind_add = UL_deposit_l(1);
     381           0 :             if (vec_in[1] < 0)
     382             :             {
     383           0 :                 lead_sign_ind_add = UL_deposit_l(2);
     384             :             }
     385           0 :             *ind = UL_addNsD(UL_deposit_l((UWord16)lshl(sub(abs1, 1), 1)), lead_sign_ind_add);
     386             :         }
     387             :         ELSE
     388             :         {
     389           0 :             IF (abs0 == 0)
     390             :             {
     391           0 :                 *ind = UL_deposit_l((UWord16)sub(lshl(abs1, 1), 1));
     392           0 :                 sptr = 1; move16();
     393             :             }
     394             :         }
     395             : 
     396           0 :         if (vec_in[sptr] < 0)
     397             :         {
     398           0 :             *next_sign_ind = UL_deposit_l(1);
     399             :         }
     400             :     }
     401             : 
     402             : #ifdef DYNMEM_COUNT
     403             :     Dyn_Mem_Out();
     404             : #endif
     405           0 : }
     406             : 
     407           0 : static void enc_push_sign(Word16 val, UWord32 *next_sign_ind, UWord32 *index)
     408             : {
     409           0 :     test();
     410           0 :     IF ((UL_and(*next_sign_ind, SIGNBIT_FX) == 0) && (val != 0))
     411             :     {
     412           0 :         *index = UL_addNsD(UL_lshl(*index, 1), *next_sign_ind);
     413             :     }
     414           0 :     if (val < 0)
     415             :     {
     416           0 :         *next_sign_ind = UL_deposit_l(1);
     417             :     }
     418           0 :     if (val > 0)
     419             :     {
     420           0 :         *next_sign_ind = UL_deposit_l(0);
     421             :     }
     422           0 : }
     423             : 
     424           0 : static void vec2mind_fx(Word16        dim_in,        /* i :  dim                       */
     425             :                         Word16        k_val_in,      /* i :  number of unit pulses     */
     426             :                         const Word16 *vec_in,        /* i :  PVQ pulse train           */
     427             :                         UWord32 *     next_sign_ind, /* o :  pushed leading sign       */
     428             :                         UWord32 *     index,         /* o :  MPVQ index                */
     429             :                         UWord32 *     N_MPVQ_ptr,    /* o :  size(N_MPVQ(dim,K_val_in))*/
     430             :                         UWord32 *     h_mem)              /* o :  offsets                   */
     431             : {
     432             :     Counter pos;
     433             :     Word16  mem_size_m1, k_val_acc, tmp_val;
     434             :     UWord32 tmp_h;
     435             : 
     436             : #ifdef DYNMEM_COUNT
     437             :     Dyn_Mem_In("vec2mind_fx", sizeof(struct {
     438             :                    Counter pos;
     439             :                    Word16  mem_size_m1, k_val_acc, tmp_val;
     440             :                    UWord32 tmp_h;
     441             :                }));
     442             : #endif
     443             : 
     444           0 :     mem_size_m1    = add(k_val_in, 1);
     445           0 :     *next_sign_ind = UL_deposit_h(SIGNBIT_SHRT_FX);
     446             : 
     447           0 :     pos = sub(dim_in, 2);
     448           0 :     vec2mind_two_fx(&vec_in[pos], &k_val_acc, next_sign_ind, index);
     449           0 :     initOffsets_fx(3, h_mem, k_val_in);
     450             : 
     451           0 :     tmp_h = h_mem[k_val_acc]; move32();
     452           0 :     FOR (pos--; pos >= 0; pos--)
     453             :     {
     454           0 :         tmp_val = vec_in[pos]; move16();
     455           0 :         enc_push_sign(tmp_val, next_sign_ind, index);
     456             : 
     457           0 :         *index = UL_addNsD(*index, tmp_h);
     458             : 
     459           0 :         k_val_acc = add(k_val_acc, abs_s(tmp_val));
     460             : 
     461           0 :         IF (pos != 0)
     462             :         {
     463           0 :             a_u_fwd_fx(h_mem, k_val_in, mem_size_m1);
     464             :         }
     465           0 :         tmp_h = UL_addNsD(h_mem[k_val_acc], 0U);
     466             :     }
     467           0 :     *N_MPVQ_ptr = UL_addNsD(1U, UL_addNsD(UL_lshr(tmp_h, 1), h_mem[mem_size_m1])); move32();
     468             : 
     469             : #ifdef DYNMEM_COUNT
     470             :     Dyn_Mem_Out();
     471             : #endif
     472           0 : }
     473             : 
     474           0 : PvqEntry_fx mpvq_index_fx(                          /* o : leading_sign_index, index, size, k_val        */
     475             :                           const Word16 *vec_in,     /* i : signed pulse train        */
     476             :                           Word16        dim_in,     /* i : dimension                 */
     477             :                           Word16        k_val_local /* i : nb unit pulses            */
     478             : )
     479             : {
     480             :     PvqEntry_fx result;
     481             :     UWord32     h_mem[1 + KMAX_FX + 1];
     482             :     UWord32     lead_sign_ind;
     483             : 
     484             : #ifdef DYNMEM_COUNT
     485             :     Dyn_Mem_In("mpvq_index_fx", sizeof(struct {
     486             :                    PvqEntry_fx result;
     487             :                    UWord32     h_mem[1 + KMAX_FX + 1];
     488             :                    UWord32     lead_sign_ind;
     489             :                }));
     490             : #endif
     491             : #ifdef WMOPS
     492             :     push_wmops("mpvq_index_fx");
     493             : #endif
     494             : 
     495           0 :     ASSERT(k_val_local <= KMAX_FX);
     496             : 
     497           0 :     result.k_val = k_val_local; move16();
     498           0 :     result.dim   = dim_in;      move16();
     499             : 
     500           0 :     vec2mind_fx(dim_in, k_val_local, vec_in, &lead_sign_ind, &result.index, &result.size, h_mem);
     501             : 
     502           0 :     result.lead_sign_ind = u_extract_l(lead_sign_ind);
     503             : 
     504             : #ifdef DYNMEM_COUNT
     505             :     Dyn_Mem_Out();
     506             : #endif
     507             : #ifdef WMOPS
     508             :     pop_wmops();
     509             : #endif
     510             : 
     511           0 :     return result;
     512             : }
     513             : 

Generated by: LCOV version 1.14