1165 lines
35 KiB
C++
1165 lines
35 KiB
C++
/*====================================================================================
|
|
EVS Codec 3GPP TS26.443 Nov 13, 2018. Version 12.11.0 / 13.7.0 / 14.3.0 / 15.1.0
|
|
====================================================================================*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include "options.h"
|
|
#include "cnst.h"
|
|
#include "rom_com.h"
|
|
#include "prot.h"
|
|
|
|
namespace evs {
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* LOCAL DEFINITIONS
|
|
*-------------------------------------------------------------------*/
|
|
|
|
#define N_OPT 5 /* complexity setting, direct functional calculation limit */
|
|
#define TABLE_LIM_OPT 96 /* odd divisor table recursion limit setting, due to dim 6 */
|
|
|
|
/* local typedefs for optimized pvq indexing, used only in this c-file to vectorize common function calls for c-code clarity */
|
|
typedef void (*VEC2INDFUNCM) (const short* , short* , unsigned int*, unsigned int*);
|
|
typedef unsigned int (*NFUNCM) (short);
|
|
typedef unsigned int (*H_FUNCM) ( unsigned int );
|
|
typedef void (*IND2VECFUNCM) ( short, short, unsigned int, short* ) ;
|
|
typedef void (*NDIM_FUNCM) ( short, short, unsigned int, short* );
|
|
|
|
typedef unsigned long long ui64; /* Basop Mpy32_32_uu simulation */
|
|
|
|
/* local constants for indexing functions c-code clarity */
|
|
#ifndef ONE_U
|
|
|
|
#define ZERO 0
|
|
#define ONE 1
|
|
#define ONE_U 1u
|
|
#define TWO 2
|
|
#define SIGNBIT 0x80000000u
|
|
|
|
#define MAXBIT 0x40000000L /* if Word32 */
|
|
#define MINNEG 0xffffffffL
|
|
|
|
#define UDIVBY3 2863311531U
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* local_norm_l_opt
|
|
*
|
|
* rewritten version of STL norm_l for "int" fixed point normalization
|
|
* in floating point c-code.
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
short local_norm_l_opt ( /* o : shifts needed for normalization */
|
|
int l32var /* i : signed 32bit input value */
|
|
)
|
|
{
|
|
short l32res;
|
|
|
|
|
|
if (l32var == (int)MINNEG )
|
|
{
|
|
return (32-ONE);
|
|
}
|
|
else
|
|
{
|
|
if (l32var == ZERO)
|
|
{
|
|
return ZERO;
|
|
}
|
|
else
|
|
{
|
|
if (l32var < ZERO)
|
|
{
|
|
l32var = ~l32var;
|
|
}
|
|
|
|
for (l32res = ZERO; l32var < (int)MAXBIT; l32res++)
|
|
{
|
|
l32var <<= ONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (l32res);
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* floor_sqrt_exact()
|
|
* returns x = floor(sqrt(input)); where (x*x) <= input
|
|
*-------------------------------------------------------------------*/
|
|
unsigned int floor_sqrt_exact( /* o : floor(sqrt(input)) */
|
|
unsigned int input /* i : unsigned input [0.. UINT_MAX/4] */
|
|
)
|
|
{
|
|
double _tmp;
|
|
unsigned int x;
|
|
if (input == ZERO)
|
|
{
|
|
return ZERO;
|
|
}
|
|
|
|
_tmp = (double) input ;
|
|
x = (unsigned int)(sqrt( _tmp )); /* floor is a part of the cast */
|
|
return x;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* f_odd_exact_div_opt()
|
|
*
|
|
* find 1/(den1*2+1) * ( num1p*num2p - num3) ,
|
|
* if the result is known a priori to be exactly a 32bit unsigned integer
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
unsigned int f_odd_exact_div_opt( /* o : see Eq. */
|
|
unsigned int num1p, /* i : see Eq. */
|
|
unsigned int num2p, /* i : see Eq. */
|
|
unsigned int num3, /* i : see Eq. */
|
|
unsigned int den1 /* i : see Eq. */
|
|
)
|
|
{
|
|
unsigned int tmp;
|
|
tmp = exactdivodd[den1] * (num1p*num2p - num3);
|
|
|
|
return (tmp);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* f_even_exact_div_opt()
|
|
*
|
|
* returns (num1p*num2p - num3 )/ den1
|
|
* if the result is known a priori to be exactly a 32bit unsigned integer
|
|
*--------------------------------------------------------------------------*/
|
|
static
|
|
unsigned int f_even_exact_div_opt( /* o : see Eq. */
|
|
unsigned int num1p, /* i : see Eq. */
|
|
unsigned int num2p, /* i : see Eq. range should be larger than num1p */
|
|
unsigned int num3, /* i : see Eq. */
|
|
int den1 /* i : see Eq. */
|
|
)
|
|
{
|
|
unsigned int tmp1, oddfactor, UL_tmp;
|
|
int den1_m1;
|
|
short even_sh;
|
|
unsigned int UL_tmp_h;
|
|
ui64 ULL_tmp;
|
|
|
|
den1_m1 = den1 - ONE; /* remove top bit */
|
|
even_sh = (31) - local_norm_l_opt((den1_m1)^den1); /* NB STL operation defined for signed positive 32 bit variable */
|
|
oddfactor = exactdivodd[den1_m1>>even_sh];
|
|
even_sh -= ONE;
|
|
|
|
ULL_tmp = (ui64)num1p*(ui64)num2p; /* use STL Mpy_32_32_uu functionality */
|
|
UL_tmp_h = (unsigned int)(ULL_tmp>>32); /* high output from basicop */
|
|
UL_tmp = (unsigned int) (ULL_tmp); /* low output from basicop */
|
|
|
|
if(num3 > UL_tmp)
|
|
{
|
|
UL_tmp_h = UL_tmp_h - ONE_U;
|
|
}
|
|
UL_tmp = (UL_tmp - num3); /* can and should underflow */
|
|
UL_tmp = (UL_tmp_h<<(32-even_sh))|(UL_tmp>>even_sh); /* bitwise OR */
|
|
|
|
/* use tabled modular multiplicative inverse for the odd part division */
|
|
tmp1 = UL_tmp*oddfactor;
|
|
|
|
|
|
return tmp1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* a_three()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
unsigned int a_three( /* o: offset for dim 3 */
|
|
unsigned int k_val /* i: nb unit pulses */
|
|
) /* k_val may be higher than 16 bit signed */
|
|
{
|
|
if( k_val )
|
|
{
|
|
return (ONE_U + k_val*((k_val - ONE_U) << ONE));
|
|
}
|
|
else
|
|
{
|
|
return ZERO;
|
|
}
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* a_four()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
unsigned int a_four( /* o: offset for dim 4 */
|
|
unsigned int k_val /* i: nb unit pulses */
|
|
)
|
|
{
|
|
if(k_val)
|
|
{
|
|
return UDIVBY3*((k_val<<ONE)*(4 + ((k_val<<ONE) - 3)*k_val) - 3); ;
|
|
}
|
|
return ZERO;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* a_five()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
unsigned int a_five( /* o: offset for dim 5 */
|
|
unsigned int k_val /* i: nb unit pulses */
|
|
)
|
|
{
|
|
unsigned int offset;
|
|
|
|
if(k_val==0)
|
|
{
|
|
offset=0;
|
|
}
|
|
else if(k_val==1)
|
|
{
|
|
offset=1;
|
|
}
|
|
else
|
|
{
|
|
offset = (ONE_U + ((((((k_val - TWO)*k_val + 5)*k_val - 4)*k_val)*(UDIVBY3))<<ONE));
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* direct_msize()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
unsigned int direct_msize(short dim_in, short k_in)
|
|
{
|
|
unsigned int msize,k,ksq;
|
|
|
|
msize = ONE_U; /* k==0 or dim==1 , and base */
|
|
if(k_in)
|
|
{
|
|
k = (unsigned int)k_in;
|
|
ksq=k*k;
|
|
switch (dim_in)
|
|
{
|
|
case (5):
|
|
/* k*k = 238*238 < 2^16 */
|
|
msize += ( ((ksq*(5 + ksq))* UDIVBY3 )<<ONE );
|
|
break;
|
|
case (4 ):
|
|
msize = ((k*(ksq + 2))*UDIVBY3)<<TWO;
|
|
break;
|
|
case ( 3 ):
|
|
msize += ((ksq)<<ONE) ;
|
|
break;
|
|
case ( 2 ):
|
|
msize = k<<ONE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return msize;
|
|
}
|
|
|
|
|
|
/* update h_mem[0.. k_val_in+1] , with starting offsets for A+U recursion */
|
|
static
|
|
void initOffsets( short dim_in, unsigned int* h_mem, short k_val_in)
|
|
{
|
|
unsigned int k_val_curr, k_val_prev;
|
|
short k_val;
|
|
h_mem[0] = ZERO; /* % A(=>0,k=0) */
|
|
h_mem[1] = ONE_U; /* % A(*,k=1) */
|
|
|
|
if(dim_in==2)
|
|
{
|
|
for( k_val = TWO; k_val <= k_val_in; k_val++)
|
|
{
|
|
h_mem[k_val] = (unsigned int)((k_val<<ONE) - ONE); /* A(2, 2 .. k ) */
|
|
}
|
|
h_mem[k_val] = (unsigned int)(k_val_in); /* U(2,k+1) */
|
|
}
|
|
else if(dim_in==3)
|
|
{
|
|
k_val_prev = ONE;
|
|
for(k_val_curr = TWO; k_val_curr <= (unsigned int)k_val_in; k_val_curr++)
|
|
{
|
|
h_mem[k_val_curr]= (ONE_U + k_val_curr*(k_val_prev<<ONE) );
|
|
k_val_prev = k_val_curr;
|
|
}
|
|
h_mem[k_val_curr] = k_val_curr* k_val_prev;
|
|
}
|
|
else if(dim_in==4)
|
|
{
|
|
for(k_val_curr = TWO; k_val_curr <= (unsigned int)k_val_in; k_val_curr++)
|
|
{
|
|
h_mem[k_val_curr] = UDIVBY3*((k_val_curr<<ONE)*(4 + ((k_val_curr<<ONE) - 3)*k_val_curr) - 3);
|
|
}
|
|
h_mem[k_val_curr] = (UDIVBY3*((k_val_curr<<ONE)*(4 + ((k_val_curr<<ONE) - 3)*k_val_curr) - 3))>>1 ;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* a_fwd()
|
|
*
|
|
* create offsets for A(n,k) from lower A(n-1,k)
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void a_fwd(
|
|
unsigned int *a_in, /* i/o: offsets */
|
|
short n_items /* i : items, k's */
|
|
)
|
|
{
|
|
unsigned int a_1;
|
|
short i,i_prev;
|
|
unsigned int a_in0 ; /* i : start column value */
|
|
|
|
a_in0 = ONE_U;
|
|
i_prev=ZERO;
|
|
for(i=ONE; i <= n_items; i++) /*basic A fwd row recursion */
|
|
{
|
|
a_1 = a_in0 + a_in[i_prev] + a_in[i] ; /* a_in addressed in at least two locations */
|
|
a_in[i_prev] = a_in0;
|
|
a_in0 = a_1;
|
|
i_prev = i; /* no real need to count as it is a ptr update */
|
|
}
|
|
a_in[i_prev] = a_in0;
|
|
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* a_bwd()
|
|
*
|
|
* create offsets for A(n,k) from higher A(n+1,k)
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void a_bwd(
|
|
unsigned int *a_in, /* i/o: offsets */
|
|
short n_items /* i: n_items */
|
|
)
|
|
{
|
|
unsigned int a_1;
|
|
unsigned int a_in0;
|
|
short i;
|
|
short i_prev;
|
|
|
|
a_in0 = ZERO;
|
|
i_prev = ZERO;
|
|
for(i=ONE; i<=n_items; i++) /*basic A reverse row recursion */
|
|
{
|
|
a_1 = a_in[i] - a_in0 - a_in[i_prev];
|
|
a_in[i_prev] = a_in0;
|
|
a_in0 = a_1;
|
|
i_prev = i;
|
|
}
|
|
a_in[i_prev] = a_in0;
|
|
return;
|
|
}
|
|
|
|
static
|
|
unsigned int direct_row_A2U_rec_calc(short dim_in , short k_val_in, unsigned int a_km2, unsigned int a_km1)
|
|
{
|
|
|
|
/* U(n,k) = (A(n,k-2)-1)/2 + ((2*n-1)*A(n,k-1) - A(n,k-2) )/2*(k-1) */
|
|
/* U(n,k) = floor(A(n,k-2)/2) + (n*A(n,k-1) - floor(A(n,k-1)/2) - floor(A(n,k-2)/2) +1 )/(k-1) */
|
|
/* U(n,k) = floor(A(n,k-2)/2) + (n*A(n,k-1) - (floor(A(n,k-1)/2) + floor(A(n,k-2)/2) +1) ) /(k-1) */
|
|
|
|
unsigned int divisor, km2_size, result;
|
|
|
|
divisor = (unsigned int)(k_val_in-ONE);
|
|
km2_size = (a_km1>>ONE) + (a_km2>>ONE) + ONE_U ;
|
|
|
|
if(divisor&ONE_U)
|
|
{
|
|
/* odd */
|
|
result = ( (a_km2>>ONE ) + f_odd_exact_div_opt((unsigned int)(dim_in), a_km1, km2_size , divisor>>ONE) );
|
|
}
|
|
else
|
|
{
|
|
/* even divisor */
|
|
result = ( (a_km2>>ONE) + f_even_exact_div_opt((unsigned int)dim_in,a_km1, km2_size, divisor ) );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static
|
|
void a_u_fwd(
|
|
unsigned int *a_u_in,
|
|
short k_val_in,
|
|
short mem_size_m1
|
|
)
|
|
{
|
|
unsigned int u_kp1_prev;
|
|
unsigned int a_k_prev ;
|
|
|
|
/* mem_size_m1 = 1 + k_val_in */
|
|
u_kp1_prev = a_u_in[mem_size_m1]; /* previous n U (n,k+1) value*/
|
|
a_k_prev = a_u_in[k_val_in]; /* previous n A(n,k) value*/
|
|
|
|
a_fwd(&a_u_in[ONE], k_val_in); /* a_u_in[k==ZERO] = zero if n>0 */
|
|
|
|
/* low dynamic last offset entry mixed recursion */
|
|
/* used for size calculation */
|
|
/* U(n,k+1) = 1 + U(n-1,k+1) + U(n-1,k) + U(n,k) */
|
|
/* U(n,k+1) = 1 + U(n-1,k+1) + (A(n-1,k)-1)/2 + (A(n,k)-1)/2 */
|
|
/* Note, A(n,k) always odd for k>0 , subtracted one always shifted out */
|
|
/* assert(a_k_prev>0, a_k-curr>0) */
|
|
|
|
a_u_in[mem_size_m1] = ONE_U + u_kp1_prev + (a_k_prev>>ONE) + (a_u_in[k_val_in] >>ONE);
|
|
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* nm_h_prep_opt()
|
|
*
|
|
* find and return N_MPVQ(n,k) and also offsets A(n, 0 to k ) and U(n,k+1).
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
unsigned int nm_h_prep_opt( /* o: msize for dim */
|
|
short dim_in, /* i: dimension */
|
|
short k_val_in, /* i: nb unit pulses */
|
|
unsigned int *h /* o: A/U offsets array */
|
|
)
|
|
{
|
|
short mem_size_m1, k_val ;
|
|
short dim_tmp, d_start;
|
|
unsigned int h_saveA, h_saveB; /* registers for alternating A(n,k-1), A(n,k-2)*/
|
|
unsigned int numDsub1; /* k_val_curr, k_val_prev*/;
|
|
|
|
mem_size_m1 = k_val_in + ONE;
|
|
|
|
if( k_val_in > TABLE_LIM_OPT )
|
|
{
|
|
if( dim_in >= 3 )
|
|
{
|
|
d_start = 3;
|
|
}
|
|
else
|
|
{
|
|
d_start = 2;
|
|
}
|
|
initOffsets(d_start, h, k_val_in);
|
|
|
|
for(dim_tmp = d_start; dim_tmp < dim_in; dim_tmp++)
|
|
{
|
|
a_u_fwd(h, k_val_in, mem_size_m1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
h[ZERO] = ZERO;
|
|
h[ONE] = ONE_U;
|
|
numDsub1=(unsigned int) ((dim_in << ONE) - ONE);
|
|
h[TWO] = numDsub1;
|
|
|
|
/* interleaved odd even calls */
|
|
h_saveA = numDsub1 ;
|
|
h_saveB = ONE_U;
|
|
for (k_val = 3; k_val < (mem_size_m1); k_val++ )
|
|
{
|
|
/* A(n,k) = A(n,k-2) + ((2*n-1)*A(n,k-1)-A(n,k-2)) /(k-1) */
|
|
/* first odd k, even divisor */
|
|
h_saveB += f_even_exact_div_opt(numDsub1, h_saveA, h_saveB, k_val - ONE);
|
|
h[k_val] = h_saveB;
|
|
|
|
k_val++; /* next even k, odd divisor */
|
|
if( k_val >= (mem_size_m1))
|
|
{
|
|
break;
|
|
}
|
|
h_saveA += f_odd_exact_div_opt(numDsub1, h_saveB, h_saveA, (k_val - ONE)>>ONE);
|
|
h[k_val] = h_saveA;
|
|
}
|
|
/* always do the last (k+1) recursion based on U(n,k+1) = func( A(n-2,k+1), A(n-1,k+1) ) */
|
|
h[mem_size_m1] = direct_row_A2U_rec_calc(dim_in, mem_size_m1 , h[mem_size_m1-2], h[k_val_in]);
|
|
}
|
|
|
|
/* N_MPVQ(n,k) = 1 + U(n,k+1) + U(n,k) = 1 + U(n,k+1) + (A(n,k)-1)/2 ; */ /* A(n,k) always odd */
|
|
return ( ONE + h[mem_size_m1] + (h[k_val_in]>>ONE) );
|
|
}
|
|
|
|
|
|
/*
|
|
find_amp_split_offset_func_mem()
|
|
find first offset in range 0..k_val_in that is less than ind_in
|
|
using a tree search with direct function calls or memory iteration
|
|
*/
|
|
static
|
|
short find_amp_split_offset_func_mem(
|
|
unsigned int ind_in,
|
|
short k_val_in,
|
|
H_FUNCM h_func_ptr, /* i: offset function pointer */
|
|
unsigned int *h_mem ,
|
|
short k_test, /* o: k_value */
|
|
unsigned int *tmp_offset /* o: offset found */
|
|
)
|
|
{
|
|
short not_ready, low,high ;
|
|
|
|
low = 0;
|
|
high = k_val_in;
|
|
/* split over A(n,k)= h_mem(k), or use direct function */
|
|
not_ready = ONE ;
|
|
while(not_ready)
|
|
{
|
|
k_test = (low+high)>>ONE; /*% split range in half */
|
|
|
|
if(h_mem)
|
|
{
|
|
*tmp_offset = h_mem[k_test]; /* memory search */
|
|
}
|
|
else
|
|
{
|
|
*tmp_offset = (*h_func_ptr)((unsigned int)k_test); /* function search. NB only line difference to the memory search*/
|
|
}
|
|
|
|
if(ind_in > *tmp_offset )
|
|
{
|
|
if(k_test < high)
|
|
{
|
|
low = 1 + k_test ;
|
|
}
|
|
else
|
|
{
|
|
not_ready=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (*tmp_offset == ind_in )
|
|
{
|
|
not_ready=0;
|
|
}
|
|
else
|
|
{
|
|
high = k_test - 1;
|
|
}
|
|
}
|
|
}
|
|
return k_test;
|
|
}
|
|
|
|
|
|
/*
|
|
get_lead_sign()
|
|
update index and return leading sign
|
|
*/
|
|
static
|
|
short get_lead_sign(unsigned int *ind)
|
|
{
|
|
short leading_sign;
|
|
|
|
if( (*ind)&ONE_U) /* leading sign stored in LSB */
|
|
{
|
|
leading_sign = -1;
|
|
}
|
|
else
|
|
{
|
|
leading_sign = 1;
|
|
}
|
|
(*ind) = (*ind)>>ONE;
|
|
|
|
return leading_sign;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mind2vec_one()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void mind2vec_one(
|
|
short k_val_in, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind, /* i: index */
|
|
short *vec_out /* o: pulse train */
|
|
)
|
|
{
|
|
ind = 0; /* to avoid compiler warings */
|
|
|
|
vec_out[ind] = (leading_sign*k_val_in); /* NB input k_val_in can be zero */
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mind2vec_two()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void mind2vec_two(
|
|
short k_val_in, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind_in, /* i: index */
|
|
short *vec_out /* o: pulse train */
|
|
)
|
|
{
|
|
unsigned int ind_tmp;
|
|
short val1;
|
|
|
|
if(k_val_in > 0) /* k_val_in check */
|
|
{
|
|
if (ind_in==0)
|
|
{
|
|
vec_out[0] = (leading_sign*k_val_in);
|
|
vec_out[1] = 0;
|
|
}
|
|
else if (ind_in == ( (unsigned int)(k_val_in<<ONE) - ONE_U) )
|
|
{
|
|
vec_out[0] = 0;
|
|
vec_out[1] = (leading_sign*k_val_in);
|
|
}
|
|
else
|
|
{
|
|
ind_tmp = ind_in - ONE_U;
|
|
val1 = (short)(ONE_U + (ind_tmp>>ONE));
|
|
vec_out[0] = leading_sign*(k_val_in - val1) ;
|
|
|
|
if(ind_tmp&ONE_U)
|
|
{
|
|
vec_out[1] = -val1 ;
|
|
}
|
|
else
|
|
{
|
|
vec_out[1] = val1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static
|
|
short setval_update_sign(
|
|
short k_delta,
|
|
short k_max_local,
|
|
short *leading_sign,
|
|
unsigned int *ind_in,
|
|
short *vec_out
|
|
)
|
|
{
|
|
if(k_delta != 0 )
|
|
{
|
|
*vec_out = (*leading_sign)*k_delta;
|
|
*leading_sign = get_lead_sign(ind_in);
|
|
k_max_local = k_max_local-k_delta ;
|
|
}
|
|
return k_max_local;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mind2vec_three()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void mind2vec_three(
|
|
short k_max_local, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind_in, /* i: index */
|
|
short *vec_out /* o: pulse train */
|
|
)
|
|
{
|
|
short k_delta ;
|
|
unsigned int acc_val;
|
|
|
|
/*
|
|
use direct calculation of first amplitude
|
|
(to find amplitudes faster than using split or linear iteration)
|
|
*/
|
|
if(ind_in==0)
|
|
{
|
|
vec_out[0] = leading_sign*k_max_local;
|
|
}
|
|
else
|
|
{
|
|
acc_val = ((ONE_U + floor_sqrt_exact((ind_in<<ONE) - ONE_U))>>ONE ); /* in BASOP use approximation + search for exact sqrt )*/
|
|
|
|
k_delta = k_max_local - (short)acc_val;
|
|
ind_in -= a_three(acc_val); /* remove amplitude offset A(n,k_acc) */
|
|
|
|
k_max_local = setval_update_sign( k_delta, k_max_local, &leading_sign,&ind_in,vec_out);
|
|
|
|
mind2vec_two( k_max_local, leading_sign, ind_in ,&vec_out[1] );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mind2vec_direct ,
|
|
general function for direct decoding using direct functions
|
|
(no memory recursion)
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void mind2vec_direct(
|
|
short k_max_local, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind, /* i: index */
|
|
H_FUNCM h_func_ptr, /* i : offset function */
|
|
NDIM_FUNCM nd_func_ptr, /* i : next dimension function */
|
|
short *vec_out /* o: pulse train */
|
|
)
|
|
{
|
|
short k_delta, k_test=0;
|
|
unsigned int tmp_offset;
|
|
|
|
if(ind==0)
|
|
{
|
|
vec_out[0] = leading_sign*k_max_local;
|
|
}
|
|
else
|
|
{
|
|
k_test = find_amp_split_offset_func_mem(ind,k_max_local, h_func_ptr , NULL, k_test, &tmp_offset);
|
|
|
|
k_delta = k_max_local - k_test;
|
|
ind = ind - tmp_offset; /* % remove amplitude offset A(n,k_acc) */
|
|
k_max_local = setval_update_sign( k_delta, k_max_local, &leading_sign, &ind,vec_out);
|
|
(*nd_func_ptr)( k_max_local, leading_sign, ind , &vec_out[1] );
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mind2vec_four()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void mind2vec_four(
|
|
short k_val_in, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind_in, /* i: index */
|
|
short *vec_out /* o: pulse train */
|
|
)
|
|
{
|
|
mind2vec_direct(k_val_in,leading_sign, ind_in, a_four, mind2vec_three, vec_out);
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mind2vec_five()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void mind2vec_five(
|
|
short k_val_in , /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind_in, /* i: index */
|
|
short *vec_out /* o: pulse train */
|
|
)
|
|
{
|
|
mind2vec_direct(k_val_in,leading_sign, ind_in, a_five, mind2vec_four, vec_out);
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mind2vec()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void mind2vec(
|
|
short dim_in, /* i: dimension */
|
|
short k_max_local, /* i: nb unit pulses */
|
|
short leading_sign, /* i: leading sign */
|
|
unsigned int ind, /* i: index */
|
|
short *vec_out, /* o: pulse train */
|
|
unsigned int *h_in /* i: offset vector A=1+2U */
|
|
)
|
|
{
|
|
short pos;
|
|
short k_acc, k_delta;
|
|
unsigned int tmp_offset;
|
|
|
|
k_acc = k_max_local;
|
|
|
|
pos = ZERO;
|
|
while (pos < dim_in) /* first to last position decoding */
|
|
{
|
|
if(ind == 0)
|
|
{
|
|
vec_out[pos] = leading_sign*k_max_local;
|
|
break; /* "fast" recursion exit */
|
|
}
|
|
else
|
|
{
|
|
{
|
|
/* linear magnitude search */
|
|
k_acc = k_max_local;
|
|
tmp_offset = h_in[k_acc];
|
|
while(tmp_offset > ind)
|
|
{
|
|
k_acc = k_acc - 1;
|
|
tmp_offset = h_in[k_acc];
|
|
}
|
|
}
|
|
k_delta = k_max_local - k_acc; /* amplitude decoding */
|
|
}
|
|
ind = ind - tmp_offset; /* remove amplitude index offset A(n,k_acc) */
|
|
|
|
k_max_local = setval_update_sign( k_delta, k_max_local, &leading_sign, &ind, &vec_out[pos]);
|
|
|
|
/* move from A(n,kmax) to A(n-1, k_max_local), */
|
|
a_bwd( h_in,k_max_local + 1 ); /* [0..k_max_local], no need to calculate U(n,k_max_local+1) in index decoding */
|
|
pos = pos + 1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* vec2mind_one()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void vec2mind_one(
|
|
const short *vec_in, /* i : PVQ abs pulse train */
|
|
short *k_val_out_ptr , /* o : number of unit pulses */
|
|
unsigned int *next_sign_ind, /* i/o: next sign ind */
|
|
unsigned int *ind /* o : MPVQ index */
|
|
)
|
|
{
|
|
*k_val_out_ptr = -1; /* just to avoid compiler warnings */
|
|
|
|
*ind = ZERO;
|
|
/* *k_val_out_ptr = (short)abs(*vec_in); */ /* dim==1, function not called recursively */
|
|
*next_sign_ind = (unsigned int)(*vec_in < ZERO); /* single sign always pushed out of MPVQ */
|
|
return;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* vec2mind_two()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void vec2mind_two(
|
|
const short *vec_in, /* i : PVQ pulse train */
|
|
short *k_val_out_ptr, /* o : number of unit pulses */
|
|
unsigned int *next_sign_ind, /* i/o: next sign ind */
|
|
unsigned int *ind /* o: MPVQ index */
|
|
)
|
|
{
|
|
unsigned int lead_sign_ind;
|
|
short abs0,abs1,abs01;
|
|
|
|
abs0 = (short) abs(vec_in[0]);
|
|
abs1 = (short) abs(vec_in[1]);
|
|
|
|
abs01 = abs0+abs1;
|
|
*k_val_out_ptr = abs01;
|
|
|
|
if(abs01==0) /* zeroes can happen in a recursive encoding call */
|
|
{
|
|
*next_sign_ind = SIGNBIT;
|
|
*ind = ZERO;
|
|
}
|
|
else
|
|
{
|
|
*next_sign_ind=0;
|
|
if(abs1 == 0)
|
|
{
|
|
*ind = ZERO;
|
|
}
|
|
else if(abs0 == 0)
|
|
{
|
|
*ind = (unsigned int)(abs1<<ONE) - ONE_U;
|
|
*next_sign_ind = 1;
|
|
}
|
|
else
|
|
{
|
|
lead_sign_ind = (unsigned int)(vec_in[1]<0); /*% sign always shifted to first pos */
|
|
*ind = ONE_U + ((unsigned int)(abs1-1)<<ONE) + lead_sign_ind;
|
|
|
|
}
|
|
*next_sign_ind= (unsigned int)(vec_in[*next_sign_ind]<0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* vec2mind_gen345( vec_in kval, next_dim_func , offset_func,....)
|
|
* generic call saves PROM ,
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void vec2mind_gen345(
|
|
const short *vec_in, /* i : PVQ abs pulse train */
|
|
short *k_val_out_ptr, /* o : number of unit pulses */
|
|
unsigned int *next_sign_ind , /* i/o: next sign ind */
|
|
unsigned int *index , /* o: MPVQ index */
|
|
VEC2INDFUNCM vec2indfunc_ptr, /* i: */
|
|
H_FUNCM a_func_ptr /*i: pffset function */
|
|
)
|
|
{
|
|
short tmp_val;
|
|
|
|
tmp_val = vec_in[ZERO];
|
|
(*vec2indfunc_ptr)(&vec_in[ONE], k_val_out_ptr, next_sign_ind, index);
|
|
|
|
if( ((*next_sign_ind&SIGNBIT)==0 && tmp_val!=0)!= ZERO )
|
|
{
|
|
*index = (*index<<ONE) + *next_sign_ind;
|
|
}
|
|
|
|
if(tmp_val != 0) /* push sign */
|
|
{
|
|
*next_sign_ind = (unsigned int)(tmp_val<0);
|
|
}
|
|
|
|
*index += (*a_func_ptr)((unsigned int)*k_val_out_ptr);
|
|
if( tmp_val > 0 )
|
|
{
|
|
*k_val_out_ptr += tmp_val;
|
|
}
|
|
else
|
|
{
|
|
*k_val_out_ptr -= tmp_val;
|
|
}
|
|
return ;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* vec2mind_three()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void vec2mind_three(
|
|
const short *vec_in, /* i : PVQ pulse train */
|
|
short *k_val_out_ptr, /* o : number of unit pulses */
|
|
unsigned int *next_sign_ind, /* i/o: next sign ind */
|
|
unsigned int *index /* o: MPVQ index */
|
|
)
|
|
{
|
|
|
|
|
|
vec2mind_gen345(vec_in,k_val_out_ptr, next_sign_ind, index, vec2mind_two, a_three);
|
|
|
|
return ;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* vec2mind_four()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void vec2mind_four(
|
|
const short *vec_in, /* i : PVQ pulse train */
|
|
short *k_val_out_ptr, /* o : number of unit pulses */
|
|
unsigned int *next_sign_ind, /* i/o: next sign ind */
|
|
unsigned int *index /* o: MPVQ index */
|
|
)
|
|
{
|
|
|
|
vec2mind_gen345(vec_in,k_val_out_ptr, next_sign_ind, index, vec2mind_three, a_four);
|
|
|
|
return ;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* vec2mind_five()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void vec2mind_five(
|
|
const short *vec_in, /* i : PVQ abs pulse train */
|
|
short *k_val_out_ptr, /* o : number of unit pulses */
|
|
unsigned int *next_sign_ind, /* i/o: next sign ind */
|
|
unsigned int *index /* o: MPVQ index */
|
|
)
|
|
{
|
|
|
|
vec2mind_gen345(vec_in,k_val_out_ptr, next_sign_ind, index, vec2mind_four, a_five);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* vec2mind()
|
|
*-------------------------------------------------------------------*/
|
|
static
|
|
void vec2mind(
|
|
short dim_in, /* i : dim */
|
|
short k_val_in, /* i : number of unit pulses */
|
|
const short *vec_in, /* i : PVQ pulse train */
|
|
unsigned int *next_sign_ind, /* o : pushed leading sign */
|
|
unsigned int *index , /* o : MPVQ index */
|
|
unsigned int *N_MPVQ_ptr, /* o : size(N_MPVQ(dim,K_val_in))*/
|
|
unsigned int *h_mem /* o : offsets */
|
|
)
|
|
{
|
|
short pos, mem_size_m1 ;
|
|
short k_val_acc ;
|
|
short tmp_val;
|
|
|
|
|
|
mem_size_m1 = k_val_in + ONE;
|
|
|
|
*next_sign_ind = SIGNBIT; /* % should always be 0 or 1 out, highest bit set signals no sign found yet*/
|
|
|
|
|
|
pos = dim_in - 2; /* % address 2nd last sample */
|
|
vec2mind_two(&vec_in[pos],&k_val_acc,next_sign_ind ,index);
|
|
initOffsets( 3, h_mem, k_val_in) ;
|
|
|
|
|
|
for (pos--; pos>=0; pos--)
|
|
{
|
|
/*
|
|
% Check if the leading sign 'bit' is to be added
|
|
*/
|
|
tmp_val = vec_in[pos];
|
|
if( ((*next_sign_ind&SIGNBIT)==0 && (tmp_val != 0)) )
|
|
{
|
|
*index = (*index<<ONE) + (*next_sign_ind);
|
|
}
|
|
|
|
/* % push sign fwd, for encoding in the next non_zero position */
|
|
if(tmp_val != 0)
|
|
{
|
|
*next_sign_ind = (unsigned int)(tmp_val<0);
|
|
}
|
|
|
|
/*% add indexing offset up to this reverse (r_l) accumulated amplitude point */
|
|
*index += h_mem[k_val_acc]; /* % k_val_acc==0 ==>0 */
|
|
|
|
k_val_acc += (short)abs(tmp_val);/*% now increase acc k value for next N */
|
|
|
|
|
|
if(pos)
|
|
{
|
|
a_u_fwd(h_mem, k_val_in ,mem_size_m1);
|
|
/*% update A(n,k=1:k_val_in) and U(n,k_val_in+1) , NB here (k_val_in + 2 elements always has to be updated */
|
|
}
|
|
}
|
|
|
|
/* size is needed for the subseqent arithmetic encoding/transmission of the index. */
|
|
/* use relation N_MPVQ(n,K) = 1 + (A(n, K)-1)/2 + U(n, 1 + K) */
|
|
/* = N_MPVQ(n,K) = 1 + (A(n, K)>>1) + U(n, 1 + K) , as A(n,K) is odd) */
|
|
|
|
*N_MPVQ_ptr = ONE_U + (h_mem[k_val_acc]>>ONE) + h_mem[ mem_size_m1 ] ; /* total size size */
|
|
|
|
return;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*
|
|
* mpvq_encode_vec()
|
|
*
|
|
* returns struct with leading sign index, MPVQ-index , dim and N_MPVQ
|
|
*-------------------------------------------------------------------------*/
|
|
|
|
PvqEntry mpvq_encode_vec( /* o : leading_sign_index, index, size, k_val */
|
|
const short *vec_in, /* i : signed pulse train */
|
|
short dim_in, /* i : dimension */
|
|
short k_val_local /* i : nb unit pulses */
|
|
)
|
|
{
|
|
PvqEntry result;
|
|
unsigned int h_mem[1+KMAX_NON_DIRECT+1]; /* allocate max offset memory for dim 6 */
|
|
/* OPT: actually only 1+k_val_in+1 needed ) */
|
|
unsigned int lead_sign_ind;
|
|
|
|
VEC2INDFUNCM vec2mind_f[1+N_OPT] = { (VEC2INDFUNCM)NULL, vec2mind_one, vec2mind_two, vec2mind_three, vec2mind_four, vec2mind_five };
|
|
/* VEC2INDFUNCM can be a static global */
|
|
|
|
|
|
result.k_val = k_val_local;
|
|
result.dim = dim_in;
|
|
|
|
/* NB, k_val_local may be changed in some sub encoding routines */
|
|
if( dim_in > N_OPT) /* use the generic dimension function */
|
|
{
|
|
vec2mind(dim_in, k_val_local, vec_in, &lead_sign_ind, &result.index, &result.size, h_mem);
|
|
}
|
|
else /* if (dim_in<=N_OPT) */
|
|
{
|
|
(vec2mind_f[dim_in])(vec_in, &k_val_local, &lead_sign_ind, &result.index);
|
|
result.size = direct_msize(dim_in, k_val_local); /* k_val_local not used for dim==1 */
|
|
}
|
|
result.lead_sign_ind=(short)lead_sign_ind;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* get_size_mpvq_calc_offset()
|
|
*
|
|
* unsigned int h_mem[1 + KMAX +1 ];
|
|
* example using fixed size of offset vector input help variable
|
|
*-------------------------------------------------------------------*/
|
|
|
|
PvqEntry get_size_mpvq_calc_offset( /* o : size, dim, k_val */
|
|
short dim_in, /* i : dimension */
|
|
short k_val_in, /* i : nb unit pulses */
|
|
unsigned int* h_mem /* o : offsets */
|
|
)
|
|
{
|
|
PvqEntry entry;
|
|
|
|
entry.dim = dim_in;
|
|
entry.k_val = k_val_in;
|
|
entry.index = 0U; /* avoid gcc warning in struct passing */
|
|
entry.lead_sign_ind = 0; /* avoid gcc warning in struct passing */
|
|
if(dim_in > N_OPT ) /* non-direct solutions, use A+U relation */
|
|
{
|
|
entry.size = nm_h_prep_opt(entry.dim, entry.k_val, h_mem);
|
|
}
|
|
else
|
|
{
|
|
entry.size = direct_msize(dim_in, entry.k_val); /* ues equations, h_mem is not used */
|
|
}
|
|
|
|
|
|
return entry;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------*
|
|
* mpvq_decode_vec()
|
|
*-------------------------------------------------------------------*/
|
|
|
|
void mpvq_decode_vec( /* o : void */
|
|
const PvqEntry *entry, /* i : sign_ind, index, dim, k_val */
|
|
unsigned int *h_mem, /* i : A/U offsets */
|
|
short *vec_out /* o : pulse train */
|
|
)
|
|
{
|
|
short i, leading_sign;
|
|
IND2VECFUNCM mind2vec_f[N_OPT+1] = { (IND2VECFUNCM)NULL, mind2vec_one, mind2vec_two, mind2vec_three, mind2vec_four, mind2vec_five };
|
|
/*IND2VECFUNCM vector can be static global */
|
|
|
|
|
|
for(i=0; i<entry->dim; i++)
|
|
{
|
|
vec_out[i]=ZERO; /* set all of short output vector to zero */
|
|
}
|
|
|
|
leading_sign = 1;
|
|
if(entry->lead_sign_ind)
|
|
{
|
|
leading_sign = -1;
|
|
}
|
|
|
|
if(entry->k_val != 0)
|
|
{
|
|
if(entry->dim > N_OPT ) /* N_OPT */
|
|
{
|
|
/* generic */
|
|
mind2vec(entry->dim, entry->k_val, leading_sign, entry->index, vec_out, h_mem);
|
|
}
|
|
else
|
|
{
|
|
/* specialized functions */
|
|
(mind2vec_f[entry->dim])(entry->k_val, leading_sign, entry->index, vec_out);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
#ifdef ONE_U
|
|
#undef ZERO
|
|
#undef ONE
|
|
#undef ONE_U
|
|
#undef TWO
|
|
#undef MAXBIT
|
|
#undef MINNEG
|
|
#undef SIGNBIT
|
|
#undef UDIVBY3
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
} // end of namespace
|