LCOV - code coverage report
Current view: top level - lib_com - re8_util_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 114 114 100.0 %
Date: 2025-05-03 01:55:50 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*====================================================================================
       2             :     EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
       3             :   ====================================================================================*/
       4             : 
       5             : #include <stdint.h>
       6             : #include "options.h" /* Compilation switches                   */
       7             : #include "cnst.h"    /* Common constants                       */
       8             : #include "rom_com.h" /* Static table prototypes                */
       9             : #include "prot_fx.h" /* Function prototypes                    */
      10             : 
      11             : 
      12             : /*-------------------------------------------------------------------*
      13             :  * Local function prototypes
      14             :  *-------------------------------------------------------------------*/
      15             : 
      16             : static Word16 re8_identify_absolute_leader_fx( const Word16 y[] );
      17             : static void re8_coord_fx( const Word16 *y, Word16 *k );
      18             : 
      19             : 
      20             : /*----------------------------------------------------------------*
      21             :  * re8_vor_fx()
      22             :  *
      23             :  * MULTI-RATE RE8 INDEXING BY VORONOI EXTENSION
      24             :  *----------------------------------------------------------------*/
      25     1907335 : void re8_vor_fx(
      26             :     const Word16 y[], /* i  : point in RE8 (8-dimensional integer vector)                                               Q0*/
      27             :     Word16 *n,        /* o  : codebook number n=0,2,3,4,... (scalar integer)                                    Q0*/
      28             :     Word16 k[],       /* o  : Voronoi index (integer vector of dimension 8) used only if n>4 Q0*/
      29             :     Word16 c[],       /* o  : codevector in Q0, Q2, Q3, or Q4 if n<=4, y=c                                           Q0*/
      30             :     Word16 *ka        /* o  : identifier of absolute leader (to index c)                                                Q0*/
      31             : )
      32             : {
      33             :     Word16 i, r, iter, ka_tmp, n_tmp, mask;
      34             :     Word16 k_tmp[8], v[8], c_tmp[8], k_mod[8];
      35             :     Word32 Ltmp, Lsphere;
      36             : 
      37             :     /*----------------------------------------------------------------*
      38             :      * verify if y is in Q0, Q2, Q3 or Q4
      39             :      *   (a fast search is used here:
      40             :      *    the codebooks Q0, Q2, Q3 or Q4 are specified in terms of RE8 absolute leaders
      41             :      *    (see FORinstance Xie and Adoul's paper in ICASSP 96)
      42             :      *    - a unique code identifying the absolute leader related to y is computed
      43             :      *      in re8_identify_absolute_leader()
      44             :      *      this code is searched FORin a pre-defined list which specifies Q0, Q2, Q3 or Q4)
      45             :      *      the absolute leader is identified by ka
      46             :      *    - a translation table maps ka to the codebook number n)
      47             :      *----------------------------------------------------------------*/
      48     1907335 :     *ka = re8_identify_absolute_leader_fx( y ); /* Q0 */
      49     1907335 :     move16();
      50             : 
      51             :     /*----------------------------------------------------------------*
      52             :      * compute codebook number n of Qn (by table look-up)
      53             :      *   at this stage, n=0,2,3,4 or out=100
      54             :      *----------------------------------------------------------------*/
      55     1907335 :     *n = Da_nq[*ka]; /* Q0 */
      56     1907335 :     move16();
      57             : 
      58             :     /*----------------------------------------------------------------*
      59             :      * decompose y into :
      60             :      *     (if n<=4:)
      61             :      *     y = c        where c is in Q0, Q2, Q3 or Q4
      62             :      *   or
      63             :      *     (if n>4:)
      64             :      *     y = m c + v  where c is in Q3 or Q4, v is a Voronoi codevector
      65             :      *                        m=2^r (r integer >=2)
      66             :      *
      67             :      *   in the latter case (if n>4), as a side-product, compute the (Voronoi) index k[] of v
      68             :      *   and replace n by n = n' + 2r where n' = 3 or 4 (c is in Qn') and r is defined above
      69             :      *----------------------------------------------------------------*/
      70             : 
      71     1907335 :     IF( LE_16( *n, 4 ) )
      72             :     {
      73     1695007 :         Copy( y, c, 8 ); /* Q0 */
      74             :     }
      75             :     ELSE
      76             :     {
      77             :         /*------------------------------------------------------------*
      78             :          * initialize r and m=2^r based on || y ||^2/8
      79             :          *------------------------------------------------------------*/
      80      212328 :         Ltmp = L_mult( y[0], y[0] ); /* Q1 */
      81     1698624 :         FOR( i = 1; i < 8; i++ )
      82             :         {
      83     1486296 :             Ltmp = L_mac( Ltmp, y[i], y[i] ); /* Q1 */
      84             :         }
      85             : 
      86      212328 :         Lsphere = L_shr( Ltmp, 5 + 1 ); /* *0.125*0.25  / 2 to remove L_mac effect */
      87             : 
      88      212328 :         r = 1;
      89      212328 :         move16();
      90      236365 :         FOR( ; Lsphere > 11; Lsphere >>= 2 )
      91             :         {
      92       24037 :             r = add( r, 1 );
      93             :         }
      94             :         /*------------------------------------------------------------*
      95             :          * compute the coordinates of y in the RE8 basis
      96             :          *------------------------------------------------------------*/
      97      212328 :         re8_coord_fx( y, k_mod );
      98             : 
      99             :         /*------------------------------------------------------------*
     100             :          * compute m and the mask needed for modulo m (for Voronoi coding)
     101             :          *------------------------------------------------------------*/
     102      212328 :         mask = sub( shl( 1, r ), 1 ); /* 0x0..011...1           Q0*/
     103             : 
     104             :         /*------------------------------------------------------------*
     105             :          * find the minimal value of r (or equivalently of m) in 2 iterations
     106             :          *------------------------------------------------------------*/
     107             : 
     108      636984 :         FOR( iter = 0; iter < 2; iter++ )
     109             :         {
     110             :             /*--------------------------------------------------------*
     111             :              * compute v such that y is in m RE_8 +v (by Voronoi coding)
     112             :              *--------------------------------------------------------*/
     113     3821904 :             FOR( i = 0; i < 8; i++ )
     114             :             {
     115     3397248 :                 k_tmp[i] = s_and( k_mod[i], mask ); /* Q0 */
     116     3397248 :                 move16();
     117             :             }
     118             : 
     119      424656 :             re8_k2y_fx( k_tmp, r, v );
     120             : 
     121             :             /*--------------------------------------------------------*
     122             :              * compute c = (y-v)/m
     123             :              * (y is in RE8, c is also in RE8 by definition of v)
     124             :              *--------------------------------------------------------*/
     125             : 
     126     3821904 :             FOR( i = 0; i < 8; i++ )
     127             :             {
     128     3397248 :                 c_tmp[i] = shr( sub( y[i], v[i] ), r ); /* Q0 */
     129     3397248 :                 move16();
     130             :             }
     131             : 
     132             :             /*--------------------------------------------------------*
     133             :              *  verify if c_tmp is in Q2, Q3 or Q4
     134             :              *--------------------------------------------------------*/
     135      424656 :             ka_tmp = re8_identify_absolute_leader_fx( c_tmp ); /* Q0 */
     136             : 
     137             :             /*--------------------------------------------------------*
     138             :              * at this stage, n_tmp=2,3,4 or out = 100 -- n=0 is not possible
     139             :              *--------------------------------------------------------*/
     140      424656 :             n_tmp = Da_nq[ka_tmp]; /* Q0 */
     141      424656 :             move16();
     142             : 
     143      424656 :             IF( GT_16( n_tmp, 4 ) )
     144             :             {
     145             :                 /*--------------------------------------------------------*
     146             :                  * if c is not in Q2, Q3, or Q4 (i.e. n_tmp>4), use m = 2^(r+1) instead of 2^r
     147             :                  *--------------------------------------------------------*/
     148      212327 :                 r = add( r, 1 );                 /* Q0 */
     149      212327 :                 mask = add( shl( mask, 1 ), 1 ); /* mask = m-1 <- this is less complex */
     150             :             }
     151             :             ELSE
     152             :             {
     153             :                 /*--------------------------------------------------------*
     154             :                  * c is in Q2, Q3, or Q4 -> the decomposition of y as y = m c + v is valid
     155             :                  *
     156             :                  * since Q2 is a subset of Q3, indicate n=3 instead of n=2 (this is because
     157             :                  * for n>4, n=n'+2r with n'=3 or 4, so n'=2 is not valid)
     158             :                  *--------------------------------------------------------*/
     159      212329 :                 n_tmp = s_max( n_tmp, 3 ); /* Q0 */
     160             : 
     161             :                 /*--------------------------------------------------------*
     162             :                  * save current values into ka, n, k and c
     163             :                  *--------------------------------------------------------*/
     164      212329 :                 *ka = ka_tmp; /* Q0 */
     165      212329 :                 move16();
     166      212329 :                 *n = add( n_tmp, shl( r, 1 ) ); /* Q0 */
     167      212329 :                 move16();
     168      212329 :                 Copy( k_tmp, k, 8 ); /* Q0 */
     169      212329 :                 Copy( c_tmp, c, 8 ); /* Q0 */
     170             : 
     171             :                 /*--------------------------------------------------------*
     172             :                  * try  m = 2^(r-1) instead of 2^r to be sure that m is minimal
     173             :                  *--------------------------------------------------------*/
     174      212329 :                 r = sub( r, 1 );       /* Q0 */
     175      212329 :                 mask = shr( mask, 1 ); /* Q0 */
     176             :             }
     177             :         }
     178             :     }
     179             : 
     180     1907335 :     return;
     181             : }
     182             : 
     183             : 
     184             : /*-------------------------------------------------------------------------
     185             :  * re8_k2y_fx()
     186             :  *
     187             :  * VORONOI INDEXING (INDEX DECODING) k -> y
     188             :  -------------------------------------------------------------------------*/
     189      504319 : void re8_k2y_fx(
     190             :     const Word16 *k, /* i  : Voronoi index k[0..7]                                                                              Q0*/
     191             :     const Word16 m,  /* i  : Voronoi modulo (m = 2^r = 1<<r, where r is integer >=2)   Q0*/
     192             :     Word16 *y        /* o  : 8-dimensional point y[0..7] in RE8                                                 Q0*/
     193             : )
     194             : {
     195             :     Word16 i, v[8], *ptr1, *ptr2, m_tmp, mm;
     196             :     Word32 ytp[8], z[8], Ltmp, Lsum;
     197             : 
     198             :     /*---------------------------------------------------------------*
     199             :      * compute y = k M and z=(y-a)/m, where
     200             :      *   M = [4        ]
     201             :      *       [2 2      ]
     202             :      *       [|   \    ]
     203             :      *       [2     2  ]
     204             :      *       [1 1 _ 1 1]
     205             :      *   a=(2,0,...,0)
     206             :      *---------------------------------------------------------------*/
     207      504319 :     m_tmp = sub( 15, m ); /* Q0 */
     208             : 
     209      504319 :     Lsum = L_deposit_l( k[7] ); /* Q0 */
     210      504319 :     ytp[7] = Lsum;
     211      504319 :     move32();
     212      504319 :     z[7] = L_shl( Lsum, m_tmp ); /* m_tmp */
     213      504319 :     move32();                    /* (int)(floor(y[7]*QR+0.5))>>m */
     214             : 
     215     3530233 :     FOR( i = 6; i >= 1; i-- )
     216             :     {
     217     3025914 :         Ltmp = L_deposit_l( shl( k[i], 1 ) ); /* Q0 */
     218     3025914 :         Lsum = L_add( Lsum, Ltmp );           /* Q0 */
     219     3025914 :         ytp[i] = L_add( ytp[7], Ltmp );       /* Q0 */
     220     3025914 :         move32();
     221     3025914 :         z[i] = L_shl( ytp[i], m_tmp ); /* m_tmp */
     222     3025914 :         move32();                      /* (int)(floor(y[7]*QR+0.5))>>m */
     223             :     }
     224             : 
     225      504319 :     Lsum = L_add( Lsum, L_deposit_l( shl( k[0], 2 ) ) ); /* Q0 */
     226      504319 :     ytp[0] = Lsum;
     227      504319 :     move32();
     228      504319 :     z[0] = L_shl( L_sub( Lsum, 2 ), m_tmp ); /* m_tmp */
     229      504319 :     move32();                                /* (int)(floor(y[7]*QR+0.5))>>m */
     230             : 
     231             :     /*---------------------------------------------------------------*
     232             :      * find nearest neighbor v of z in infinite RE8
     233             :      *---------------------------------------------------------------*/
     234      504319 :     re8_PPV_fx( z, v );
     235             : 
     236             :     /*---------------------------------------------------------------*
     237             :      * compute y -= m v
     238             :      *---------------------------------------------------------------*/
     239      504319 :     ptr1 = y; /* Q0 */
     240      504319 :     ptr2 = v; /* Q0 */
     241             : 
     242      504319 :     mm = shr( shl( 1, m ), 1 ); /* shr to remove effect of L_mult in L_msu */
     243             : 
     244     4538871 :     FOR( i = 0; i < 8; i++ )
     245             :     {
     246     4034552 :         Ltmp = L_msu( ytp[i], *ptr2++, mm ); /* Q0 */
     247     4034552 :         *ptr1++ = extract_l( Ltmp );         /* Q0 */
     248             :     }
     249             : 
     250      504319 :     return;
     251             : }
     252             : 
     253             : 
     254             : /*-----------------------------------------------------------------------*
     255             :  * re8_identify_absolute_leader:
     256             :  *
     257             :  * IDENTIFY THE ABSOLUTE LEADER RELATED TO y USING A PRE-DEFINED TABLE WHICH
     258             :  * SPECIFIES THE CODEBOOKS Q0, Q2, Q3 and Q4
     259             :  -----------------------------------------------------------------------*/
     260             : 
     261     2331991 : static Word16 re8_identify_absolute_leader_fx(                  /* o : integer indicating if y if in Q0, Q2, Q3 or Q4 (or if y is an outlier)   Q0*/
     262             :                                                const Word16 y[] /* i : point in RE8 (8-dimensional integer vector)                              Q0*/
     263             : )
     264             : {
     265             :     Word16 i, s, id, nb, pos, ka, tmp16;
     266             :     Word32 Ltmp, Ls;
     267             :     Word32 C;
     268             :     const Word16 *ptr;
     269             : 
     270             :     /*-----------------------------------------------------------------------*
     271             :      * compute the RE8 shell number s = (y1^2+...+y8^2)/8 and C=(y1^2, ..., y8^2)
     272             :      *-----------------------------------------------------------------------*/
     273     2331991 :     Ls = L_mult( y[0], y[0] ); /* Q1 */
     274    18655928 :     FOR( i = 1; i < 8; i++ )
     275             :     {
     276    16323937 :         Ls = L_mac( Ls, y[i], y[i] ); /* Q1 */
     277             :     }
     278     2331991 :     s = extract_h( L_shl_sat( Ls, 16 - ( 3 + 1 ) ) ); /* s can saturate here */
     279             :     /*-----------------------------------------------------------------------*
     280             :      * compute the index 0 <= ka <= NB_LEADER+1 which identifies an absolute leader of Q0, Q2, Q3 or Q4
     281             :      *
     282             :      * by default, ka=index of last element of the table (to indicate an outlier)
     283             :      *-----------------------------------------------------------------------*/
     284             :     /*-------------------------------------------------------------------*
     285             :      * if s=0, y=0 i.e. y is in Q0 -> ka=index of element indicating Q0
     286             :      *-------------------------------------------------------------------*/
     287     2331991 :     ka = NB_LEADER;
     288     2331991 :     move16();
     289     2331991 :     IF( s != 0 )
     290             :     {
     291     2131464 :         ka = NB_LEADER + 1;
     292     2131464 :         move16();
     293             :         /*-------------------------------------------------------------------*
     294             :          * the maximal value of s for y in  Q0, Q2, Q3 or Q4 is NB_SPHERE
     295             :          *   if s> NB_SPHERE, y is an outlier (the value of ka is set correctly)
     296             :          *-------------------------------------------------------------------*/
     297     2131464 :         IF( LE_16( s, NB_SPHERE ) )
     298             :         {
     299             :             /*---------------------------------------------------------------*
     300             :              * compute the unique identifier id of the absolute leader related to y:
     301             :              * s = (y1^4 + ... + y8^4)/8
     302             :              *---------------------------------------------------------------*/
     303     2091675 :             C = L_mult( y[0], y[0] );                /* Q1 */
     304     2091675 :             tmp16 = extract_h( L_shl( C, 16 - 1 ) ); /* Q0 */
     305     2091675 :             Ltmp = L_mult( tmp16, tmp16 );           /* Q1 */
     306    16733400 :             FOR( i = 1; i < 8; i++ )
     307             :             {
     308    14641725 :                 C = L_mult( y[i], y[i] );                /* Q1 */
     309    14641725 :                 tmp16 = extract_h( L_shl( C, 16 - 1 ) ); /* Q0 */
     310    14641725 :                 Ltmp = L_mac( Ltmp, tmp16, tmp16 );      /* Q1 */
     311             :             }
     312     2091675 :             id = extract_h( L_shl( Ltmp, 16 - ( 3 + 1 ) ) ); /* id can saturate to 8192 */
     313             : 
     314             :             /*---------------------------------------------------------------*
     315             :              * search for id in table Da_id
     316             :              * (containing all possible values of id if y is in Q2, Q3 or Q4)
     317             :              * this search is focused based on the shell number s so that
     318             :              * only the id's related to the shell of number s are checked
     319             :              *---------------------------------------------------------------*/
     320             : 
     321     2091675 :             nb = Da_nb[s - 1];   /* get the number of absolute leaders used on the shell of number s    Q0*/
     322     2091675 :             pos = Da_pos[s - 1]; /* get the position of the first absolute leader of shell s in Da_id   Q0*/
     323     2091675 :             move16();
     324     2091675 :             move16();
     325             : 
     326     2091675 :             ptr = &Da_id[pos]; /* Q0 */
     327     2091675 :             move16();
     328     3625790 :             FOR( i = 0; i < nb; i++ )
     329             :             {
     330     3240924 :                 IF( EQ_16( id, *ptr ) )
     331             :                 {
     332     1706809 :                     ka = pos;
     333     1706809 :                     move16(); /* get ka */
     334     1706809 :                     BREAK;
     335             :                 }
     336     1534115 :                 ptr++;
     337     1534115 :                 pos = add( pos, 1 ); /* Q0 */
     338             :             }
     339             :         }
     340             :     }
     341             : 
     342     2331991 :     return ( ka );
     343             : }
     344             : 
     345             : 
     346             : /*-------------------------------------------------------------------------
     347             :  * Re8_coord:
     348             :  *
     349             :  * COMPUTATION OF RE8 COORDINATES
     350             :  -----------------------------------------------------------------------*/
     351             : 
     352      212328 : static void re8_coord_fx(
     353             :     const Word16 *y, /* i  : 8-dimensional point y[0..7] in RE8         Q0*/
     354             :     Word16 *k        /* o  : coordinates k[0..7]                                        Q0*/
     355             : )
     356             : {
     357             :     Word16 i, tmp, sum;
     358             : 
     359             :     /*---------------------------------------------------------------*
     360             :      * compute k = y M^-1
     361             :      *   M = 1/4 [ 1          ]
     362             :      *           [-1  2       ]
     363             :      *           [ |    \     ]
     364             :      *           [-1       2  ]
     365             :      *           [ 5 -2 _ -2 4]
     366             :      *
     367             :      *---------------------------------------------------------------*/
     368      212328 :     k[7] = y[7]; /* Q0 */
     369      212328 :     move16();
     370      212328 :     tmp = y[7]; /* Q0 */
     371      212328 :     move16();
     372      212328 :     sum = add( y[7], shl( y[7], 2 ) ); /* Q0 */
     373             : 
     374     1486296 :     FOR( i = 6; i >= 1; i-- )
     375             :     {
     376             :         /* apply factor 2/4 from M^-1 */
     377     1273968 :         k[i] = shr( sub( y[i], tmp ), 1 ); /* Q0 */
     378     1273968 :         move16();
     379     1273968 :         sum = sub( sum, y[i] ); /* Q0 */
     380             :     }
     381             :     /* apply factor 1/4 from M^-1 */
     382      212328 :     k[0] = shr( add( y[0], sum ), 2 ); /* Q0 */
     383      212328 :     move16();
     384             : 
     385      212328 :     return;
     386             : }

Generated by: LCOV version 1.14