

//#ifdef HAVE_CONFIG_H
#include "config.h"
//#endif

#include "ssc_math.h"
#include "vector_quant.h"
#include "ssc_macro.h"

#include "ssc_int32.h"
#include "ssc_pulsealloc.h"

extern short *SSC_restricted_local;


static void rot_exp1(short *X, int len, int st1, short a, short b)
{


   short *pointX;
   int x_one, x_two;
   int i;
   
   pointX = X;
   

   i = 0;
   while(i<len-st1)
   {
	  x_two = pointX[st1];
      x_one = pointX[0];

	  pointX[st1] = (SSC_MULT16x16(a,x_two) + SSC_MULT16x16(b,x_one))>>15;
	  *pointX++      = (SSC_MULT16x16(a,x_one) - SSC_MULT16x16(b,x_two))>>15;
	  i++;
   }
   
    
   pointX = &X[len-1-(st1<<1)]; 

   i=len-1-(st1<<1);
   while (i>-1)
   {
	  x_two = pointX[st1];
      x_one = pointX[0];

	  pointX[st1] = (SSC_MULT16x16(a,x_two) + SSC_MULT16x16(b,x_one)) >>15;
	  *pointX--      = (SSC_MULT16x16(a,x_one) - SSC_MULT16x16(b,x_two))>>15;

	  i--;
   }
}




static void rot_exp(short *X, int width, int first_str, int Cay, int val_sp)
{

   
   short gain, angle;
   int second_str=0;
   int fig;
   int i;
   short a, b;

   if (val_sp==ZERO_SPR || (Cay<<1)>=width)
      return;

   fig = 15-SSC_MULT16x16(5,val_sp-1);

   gain = (int)SSC_MULT16x16(Q15_ONE,width)/(width+fig*Cay);
   angle = SSC_HLF16(SSC_MULT16x16_Q15(gain,gain));


   a = norm_cosine((int)(angle));
   b = norm_cosine((int)(SSC_SUB16(Q15ONE,angle))); /*  sin(angle) */

   if (width>=(first_str<<3))
   {
      second_str = 1;

      while (SSC_MULT16x16((SSC_MULT16x16(second_str, second_str) + second_str), first_str) + (first_str>>2) < width)
         second_str++;
   }

   width /= first_str;


   i = 0;
   while(i<first_str)
   {
	   if (second_str)
		   rot_exp1(X+SSC_MULT16x16(i, width), width, second_str, b, a);
	   rot_exp1(X+SSC_MULT16x16(i, width), width, 1, a, b);

	   i++;
   }
}

static void normalise_residual(short * iy, short * X,
	int N, int Ryy, short gain)
{
   int i;
   int k;

   int t;
   short g;

   k = eclog_minus1(Ryy)>>1;
   t = SSC_VSHR32(Ryy, 2*(k-7));
   g = SSC_MULT16x16_P15(audio_rsqrt_norm(t),gain);

#ifndef HW_OPTI5  
   i=0;
   do
      X[i] = SSC_toSHORT(SSC_PSHR32(SSC_MULT16x16(g, iy[i]), k+1));
   while (++i < N);
#else

   i = N;
   do
   {
	   *X++ = SSC_toSHORT(SSC_PSHR32(SSC_MULT16x16(g, *iy++), k+1));
   }
   while(--i);
   
#endif
}

static unsigned extract_collapse_mask(short *iy, int N, int B)
{
   unsigned collapse_mask;
   int N0;
   int i;

 //  int flag = 0;

   if (B<=1)
      return 1;
   /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
      rot_exp().*/
   N0 = N/B;
   collapse_mask = 0;

#ifndef HW_OPTI5
   i=0; do {
      int j;
      j=0; do {
         collapse_mask |= (iy[i*N0+j]!=0)<<i;
      } while (++j<N0);
   } while (++i<B);
#else

   for(i=0;i<B;i++)
   {
	   unsigned short tmp = 0;
	   int j;
	   j = N0;
	   do{
		   tmp |= *iy++;
	   }while(--j);

	   collapse_mask |= (tmp!=0)<<i;
   }
   

#endif


   return collapse_mask;
}





unsigned alg_unquant(short *X, int N, int K, int spread, int B,
	ec_dec *dec, short gain)

{
	
#ifndef ZH_OPTI_ADD	
   int i;
#endif	
   int Ryy;
   unsigned collapse_mask;

 //  short *iy = (short *)shared_lo2;
////////////////////// 1583 ~ 1728 ///////////////////////////
//   short *iy = &(shared_local[1583]);

   short *iy = &(SSC_restricted_local[1583]);
///////////////////////////////////////////////////////////
#ifndef ZH_OPTI_ADD	
   int *_iy = iy;
#endif	  
   
#ifndef ZH_OPTI_ADD   
   decode_pulses(iy, N, K, dec);
   Ryy = 0;
   
#ifndef HW_OPTI5   
   i=0;
   do {
      Ryy = SSC_MAC16x16(Ryy, iy[i], iy[i]);
   } while (++i < N);
#else
   i=N;
   do
   {
      Ryy = SSC_MAC16x16(Ryy, *_iy, *_iy);
      _iy++;
   } while (--i);   
#endif
   
#else
   Ryy = decode_pulses(iy, N, K, dec);
   
#endif
   normalise_residual(iy, X, N, Ryy, gain);

    rot_exp(X, N, B, K, spread);

   collapse_mask = extract_collapse_mask(iy, N, B);

   return collapse_mask;
}


void renormalise_vector(short *X, int N, short gain)
{
   int i;
   int k;
   //int E;	//hoon_test 1206
   int E = EPSILON;
   short g;
   int t;

//   int *xptr = X;
   short *xptr = X;
#if 1	//hoon_test 1206
   for (i=0;i<N;i++)
   {
#if 1	//hoon_test 1206
       E = SSC_MAC16x16_tmp(E, *xptr, *xptr);
#else
	   SSC_MAC16x16(E_, *xptr, *xptr);
	   E = (int)(long long)E_;
#endif
      xptr++;
   }
#else
   short remainder = (N&3);
   ae_int16x4 *xptr_16x4 = (ae_int16x4 *)(xptr);
   ae_int32x4 E_32x4 = 0;

   for (i=0; i < (N>>2); i++)
   {
	   AE_MULA16X4_vector(E_32x4, *xptr_16x4, *xptr_16x4);
	   xptr_16x4++;
	   /*
	   	   SSC_MAC16x16(E_, *xptr, *xptr);
	   	   E = (int)(long long)E_;
	   	   xptr++;

	   	   SSC_MAC16x16(E_, *xptr, *xptr);
	   	   E = (int)(long long)E_;
	   	   xptr++;

	   	   SSC_MAC16x16(E_, *xptr, *xptr);
	   	   E = (int)(long long)E_;
	   	   xptr++;

	   	   SSC_MAC16x16(E_, *xptr, *xptr);
	   	   E = (int)(long long)E_;
	   	   xptr++;
	   */
   }
   E = AE_INT32X4_RADD(E_32x4);
   E = E+1;
#endif

   k = eclog_minus1(E)>>1;
   t = SSC_VSHR32(E, 2*(k-7));
   g = SSC_MULT16x16_P15(audio_rsqrt_norm(t),gain);

   xptr = X;
   for (i=0;i<N;i++)
   {
      *xptr = SSC_toSHORT(SSC_PSHR32(SSC_MULT16x16(g, *xptr), k+1));
      xptr++;
   }
}
