

//#ifdef HAVE_CONFIG_H
#include "config.h"
//#endif

#include "ssc_quant.h"
#include "ssc_lap.h"

#include "ssc_macro.h"
#include "ssc_math.h"
#include "ssc_pulsealloc.h"

#include "util.h"






const signed char eMeans[22] = {
	103,100, 92, 85, 81,
	77, 72, 70, 78, 75,
	73, 71, 78, 74, 69,
	72, 70, 74, 76, 71,
	60, 60,
};


static const unsigned char e_prob_model[2][42] = {

	{
		42, 121,  96,  66, 108,  43, 111,  40, 117,  44, 123,  32, 120,  36,
		119,  33, 127,  33, 134,  34, 139,  21, 147,  23, 152,  20, 158,  25,
		154,  26, 166,  21, 173,  16, 184,  13, 184,  10, 150,  13, 139,  15,
	},
	/*Intra*/
	{
		22, 178,  63, 114,  74,  82,  84,  83,  92,  82, 103,  62,  96,  72,
		96,  67, 101,  73, 107,  72, 113,  55, 118,  52, 125,  52, 118,  52,
		117,  55, 135,  49, 137,  39, 157,  32, 145,  29,  97,  33,  77,  40,
	}

};



static const unsigned char small_energy_icdf[3]={2,1,0};



void unquant_coarse_energy(const AUDIOMode *m, short end, short *oldEBands, int intra, ec_dec *dec)
{

   const unsigned char *prob_model = e_prob_model[intra];

   int i, c;
   int prev[2] = {0, 0};
   short coef;
   short beta;
   int budget;
   int tell;


   if (intra)
   {
	   coef = 0;
	   beta = 4915;
   } else {

	   beta = 6554;
	   coef = 16384;
   }
   budget = dec->storage*8;

   /* Decode at a fixed coarse resolution */

   for (i=0;i<end;i++)
   {
      c=0;
      do {
         int qi;
         int q;
         int tmp;
         int step;

         /* It would be better to express this invariant as a
            test on C at function entry, but that isn't enough
            to make the static analyzer happy. */
         audio_assert(c<2);
         tell = ec_tell(dec);
         if(budget-tell>=15)
         {
            int pi;
            pi = 2*IMIN(i,20);
            qi = ec_laplace_decode(dec,
                  prob_model[pi]<<7, prob_model[pi+1]<<6);
         }
         else if(budget-tell>=2)
         {
            qi = rc_decode_cdf(dec, small_energy_icdf, 2);
            qi = (qi>>1)^-(qi&1);
         }
         else if(budget-tell>=1)
         {
            qi = -rc_decode_logp_bit(dec, 1);
         }
         else
            qi = -1;
         q = (int)SSC_SHL32(SSC_toINT(qi),SHIFT_10);

		step = c*m->nbEBands;
		oldEBands[i+step] = MAX16(-9216, oldEBands[i+step]);
		tmp = SSC_PSHR32(SSC_MULT16x16(coef,oldEBands[i+step]),8) + prev[c] + SSC_SHL32(q,7);

		tmp = MAX32(-3670016, tmp);
		
         oldEBands[i+step] = SSC_PSHR32(tmp, 7);
         prev[c] = prev[c] + SSC_SHL32(q,7) - SSC_MULT16x16(beta,SSC_PSHR32(q,8));
      } 
	  while (++c < 2);
   }
}

void unquant_fine_energy(const AUDIOMode *m, short end, short *oldEBands, short *fine_quant, ec_dec *dec)
{

   int i;

   /* Decode finer resolution */

   for (i=0;i<end;i++)
   {

	   int q2;
	   short offset;

      if (fine_quant[i] <= 0)
         continue;


         q2 = ec_dec_bits(dec, fine_quant[i]);
		 offset = SSC_SUB16(SSC_SHR32(SSC_SHL32(SSC_toINT(q2),SHIFT_10)+512,fine_quant[i]),512);


		oldEBands[i] += offset;
		q2 = ec_dec_bits(dec, fine_quant[i]);
		offset = SSC_SUB16(SSC_SHR32(SSC_SHL32(SSC_toINT(q2),SHIFT_10)+512,fine_quant[i]),512);
		oldEBands[i+m->nbEBands] += offset;

   }
}

void unquant_energy_finalise(const AUDIOMode *m, short end, short *oldEBands, short *fine_quant,  short *fine_priority, int bits_left, ec_dec *dec)
{
   int i, prio;
   
   int q2;
   short offset;

   /* Use up the remaining bits */
   for (prio=0;prio<2;prio++)
   {
	  for (i=0;i<end && bits_left>=2 ;i++)
	  {
         if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
            continue;
            
         q2 = ec_dec_bits(dec, 1);
		 offset = SSC_SHR16(SSC_SHL16(q2,SHIFT_10)-512,fine_quant[i]+1);
		 oldEBands[i] += offset;

		 q2 = ec_dec_bits(dec, 1);
		 offset = SSC_SHR16(SSC_SHL16(q2,SHIFT_10)-512,fine_quant[i]+1);
		 oldEBands[i+m->nbEBands] += offset;

		 bits_left = bits_left-2;
      }
   }
}


