
#include "speech_decoder.h"
#include "copy.h"
#include "speech_mdct.h"
#include "bands.h"
#include "ssc_modes.h"
#include "rc_decode.h"
#include "ssc_quant.h"
#include "ssc_pulsealloc.h"
#include "math_op.h"
#include "comb_filter.h"

#define DECODE_BUFFER_SIZE 312
#ifndef CRC_ON_4BIT
#define SYNCWORD_16K 0xF7
#else
#define SYNCWORD_16K 0xA0
#endif
#define SPREAD_NORMAL (2)


//extern int count;
#ifdef HW_DEBUG_COUNT
int rvp_count;
#endif

#ifdef HW_DEBUG_TABLE_INPUT
unsigned char table_data[30] = {
/*
	0xf7, 0x69, 0xbc, 0xf6, 0x00, 0xae, 0x3b, 0xd6, 0xd2, 0x1c, 
	0x5c, 0x82, 0xb9, 0xd9, 0x55, 0xa5, 0x85, 0x06, 0xd8, 0xfa, 
	0x29, 0x5c, 0x4d, 0xf7, 0x50, 0x3c, 0x19, 0xb9,
*/

	0xf7, 0x3e, 0x62, 0xf0, 0x72, 0xaa, 0xc6, 0xd6, 0xc1, 0x31, 
	0x14, 0x5a, 0x3d, 0x4f, 0x8d, 0x71, 0x0c, 0xbf, 0x7c, 0x7b, 
	0x86, 0xa3, 0x67, 0xf9, 0x77, 0xc9, 0x42, 0x2c, 
};
#endif
/******************************************************
 * Function name: Check CRC
 * Parameters   : BIT_BUF *pBitBuf, FRAME_HEADER *pHdr
 * Return value : 
 * Description  : Check CRC code
 * Last update  : 2013. 01. 04
 ******************************************************/
#ifdef CRC_ON_4BIT
short CheckCRC4(const unsigned char *pBuffer)
{
 static unsigned char tab_crc4[16] = { 0, 3, 6, 5, 12, 15, 10, 9, 11, 8, 13, 14, 7, 4, 1, 2 };
 short  i;
 char crc=0;
 unsigned char crc_check = pBuffer[0] & 0x0F;

 // Generate CRC checksum
 for(i=1 ; i<28 ; i++)
 {
  crc ^= pBuffer[i] >> 4;
  crc  = tab_crc4[crc];
  crc ^= pBuffer[i] & 0xF;
  crc  = tab_crc4[crc];
 }

 // Check CRC
// ASSERT(crc == pHdr->crc_check);
 
 if(crc == crc_check)
 {
	return 0;
 }
 else
 {    
	return 2;
 }
}
#endif







static int sun_custom_decoder_init(SPEECHDecoder *st, const SpeechMode *mode)
{
	if (st==NULL) return SUN_ALLOC_FAIL;
	SUN_CLEAR_uchar((unsigned char*)st, speech_decoder_get_size());
	st->mode = mode;
	st->overlap = mode->overlap;
	st->end = st->mode->nbEBands;


//	printf("before init_burst = %d\n",st->plc_burst_cnt);

//#ifdef HW_PLC_BURST_COUNT
	st->plc_burst_cnt = 0;
//#endif


//	printf("after init_burst = %d\n",st->plc_burst_cnt);


#ifdef HW_DEBUG_COUNT
	rvp_count = 0;
#endif


	return SUN_OK;
}


#ifdef HW_PLC_3

////////////////////////   PLC °ü·Ã ////////////////////////
//#define PLC_CURRENT
//#define PLC_NEW1
// #define PLC_NEW2
 #define PLC_NEW3

#define HW_PLC_BURST_COUNT
#define PLC_COMB_1


#define PLC_NEW3_ADDITIONAL
////////////////////////////////////////////////////////////



// ÇöÀç version 2018_0412 ºê·ÎµåÄÄ release




#ifdef PLC_CURRENT  //  ±âÁ¸ original
static void plc_proc(int *freq, short *oldBandE)
{
	short i;
#ifdef HW_HIFI3
	long long tmp_val;
#endif
	for(i=0;i<16;i++)
	{
		oldBandE[i] = SPEECH_MAX(oldBandE[i]-1000, -28672);
	}

   // ÇöÀç version
	for(i=0; i<120; i++)
	{ 
		freq[i] = (freq[i]+freq[i+120])>>1;
	}


	for(i=0; i<120; i++)
	{
#ifndef HW_HIFI3
		freq[i] =  SSC_MULT16x32_Q15(18421,freq[i])   ;
#else
		tmp_val = AE_MUL32X16_H0(freq[i], 18421);
		freq[i] = (int)(tmp_val>>15);
#endif
		freq[i+120] =  freq[i]>>1   ; 
	}

}
#endif



#ifdef PLC_NEW1   // 1 is new-1,  0 is new-2
static void plc_proc(int *freq, short *oldBandE)
{
	short i;
	int *tmp = freq-404;

#ifdef HW_HIFI3
	long long tmp_val;
#endif

	for(i=0;i<16;i++)
	{
		oldBandE[i] = SPEECH_MAX(oldBandE[i]-100, -28672);
	}



	for(i=0; i<120; i++)
	{
		short sign_val =  (freq[i] + tmp[i] + i ) & 1;

		freq[i] = (ABS(freq[i]) + ABS(freq[i+120])) >> 1;
		if(sign_val == 1)
			freq[i] = -freq[i];
	}

	for(i=0; i<120; i++)
	{
#ifndef HW_HIFI3
		freq[i] =  SSC_MULT16x32_Q15(32421,freq[i]);
		freq[i+120] =   SSC_MULT16x32_Q15(32721,freq[i]);
#else
		tmp_val = AE_MUL32X16_H0(freq[i], 32421);
		freq[i] = (int)(tmp_val>>15);

		tmp_val = AE_MUL32X16_H0(freq[i], 32721);
		freq[i+120] = (int)(tmp_val>>15);
#endif
	}

}
#endif

#ifdef PLC_NEW2
static void plc_proc(int *freq, short *oldBandE)
{
	short i;
	int *tmp = freq-404;
#ifdef HW_HIFI3
	long long tmp_val;
#endif

	for(i=0;i<16;i++)
	{
		oldBandE[i] = SPEECH_MAX(oldBandE[i]-100, -28672);
	}

	// ÇöÀç version

	for(i=0; i<120; i++)
	{
		short sign_val =  (freq[i] + tmp[i] + i ) & 1;

	//	freq[i] = ( ABS(freq[i]) + ABS(freq[i+120])) >> 1;

		freq[i] = ABS(SSC_MULT16x32_Q15(22937,freq[i])) + ABS(SSC_MULT16x32_Q15(9831,freq[i+120]));
		freq[i+120] = ABS(SSC_MULT16x32_Q15(9831,freq[i])) + ABS(SSC_MULT16x32_Q15(22937,freq[i+120]));

		if(sign_val == 1)
			freq[i] = -freq[i];
	}

	for(i=0; i<120; i++)
	{
		short sign_val =  (freq[i] + tmp[i] + i ) & 1;
#ifndef HW_HIFI3
		freq[i] =  SSC_MULT16x32_Q15(27421,freq[i]);
		freq[i+120] =   SSC_MULT16x32_Q15(23221,freq[i+120]);
#else
		tmp_val = AE_MUL32X16_H0(freq[i], 27421);
		freq[i] = (int)(tmp_val>>15);

		tmp_val = AE_MUL32X16_H0(freq[i+120], 23221);
		freq[i+120] = (int)(tmp_val>>15);

#endif
	}

}


#endif


#ifdef PLC_NEW3

static void plc_proc(int *freq, short *oldBandE, SPEECHDecoder *st)
{
	short i;
	int *tmp = freq-404;

	short t_gain1, t_gain2;

	short var_comb_gain;
	short burst_gain = (st->plc_burst_cnt<<10);


#ifdef BUD_ISSUE
	int sum_oldband = 0;
#endif


	if(st->plc_burst_cnt == 0)
	{
		st->plc_base_gain = (st->postfilter_gain>>11) + (st->postfilter_gain_old>>11);
	}
	var_comb_gain = st->plc_base_gain<<7;


	t_gain1 =  SPEECH_MAX(4096, SPEECH_MIN(var_comb_gain - burst_gain + 27421,32767 ));
	t_gain2 =  SPEECH_MAX(4096, SPEECH_MIN(var_comb_gain - burst_gain + 29221,32767 ));


#ifdef HW_DEBUG_COUNT
	if(rvp_count == 60)
	{
		printf("t_gain1 = %d\n",t_gain1);
		printf("t_gain2 = %d\n",t_gain2);
	}
#endif




	for(i=0;i<16;i++)
	{

#ifdef BUD_ISSUE
		sum_oldband = sum_oldband + (int)(oldBandE[i]);
#endif
		oldBandE[i] = SPEECH_MAX(oldBandE[i]-100, -28672);


#ifdef HW_DEBUG_COUNT
	if(rvp_count == 60)
	{
		printf("oldBandE[i] = %d\n",oldBandE[i]);
	}
#endif

	}


#ifdef BUD_ISSUE
	if(sum_oldband == -458752)
	{
		for(i=0; i<120; i++)
		{
			freq[i] = 0;
		}
		return;
	}
#endif


	// ÇöÀç version
	for(i=0; i<120; i++)
	{
		short sign_val =  (freq[i] + tmp[i] + i ) & 1;

		//	freq[i] = ( ABS(freq[i]) + ABS(freq[i+120])) >> 1;
		freq[i] = ABS(SSC_MULT16x32_Q15(22937,freq[i])) + ABS(SSC_MULT16x32_Q15(9831,freq[i+120]));
		freq[i+120] = ABS(SSC_MULT16x32_Q15(9831,freq[i])) + ABS(SSC_MULT16x32_Q15(22937,freq[i+120]));

		if(sign_val == 1)
			freq[i] = -freq[i];
	}
#ifdef HW_DEBUG_COUNT
	if(rvp_count == 60)
	{
		for(i=0; i<240; i++)
		{
			printf("freq[%d] = %d\n",i,freq[i]);
		}
	}
#endif
	for(i=0; i<120; i++)
	{
	//	short sign_val =  (freq[i] + tmp[i] + i ) & 1;
	//	short t_sign_val = (freq[i+60] + tmp[i+60] + i ) & 1;
		short t_sign_val = (freq[i+60] + tmp[i+60] + i ) & 1;
		t_sign_val = (t_sign_val<<1) - 1;
		freq[i] =  SSC_MULT16x32_Q15(t_gain1, freq[i]);
		freq[i+120] =   SSC_MULT16x32_Q15(t_gain2, freq[i+120]) + ((t_sign_val)*(  SPEECH_MIN(6,st->plc_burst_cnt)  ));
	}


#ifdef HW_DEBUG_COUNTx
	if(rvp_count == 60)
	{
		for(i=0; i<240; i++)
		{
			printf("freq[%d] = %d\n",i,freq[i]);
		}
	}
#endif

}

#endif




#endif











#ifndef HW_30BYTE
short speech_decode_inside(void *_st, unsigned char *data, short len, short *pcm, short frame_size)
#else
short speech_decode(void *_st, unsigned char *data, short len, short *pcm, short frame_size,short plc_enable)
#endif
{
	short i, N, bits;
	short speech_ptr; 
	int *freq;
	short *X;
	short *fine_quant;
	short *pulses;
	const short *cap;
	short *fine_priority;
	int *decode_mem;
	int *out_syn;
	short *oldBandE;
//	short intra_ener;
	short effEnd;
	short codedBands;
	short alloc_trim;
	short total_bits; 
	short tell;
	short nbEBands;
	short overlap;
	short silence;
	short balance;
	const SpeechMode *mode;
	short postfilter_pitch;
	short postfilter_gain;

#ifndef OPT_DATASIZE2
	short offsets[16];
#else
	short *offsets;
#endif

	short *norm;
#ifdef HW_PLC_UPDATE3
	short *burst_count;
#endif
#ifdef CRC_ON_4BIT
	short crc_flag;
#endif
#ifdef CRC_ON_8BIT
	short crc_flag_8bit = 0;
	unsigned char crc;
#endif

	ec_dec _dec;
	ec_dec *dec;

	SPEECHDecoder *st = (SPEECHDecoder *)_st;

	unsigned char syncword;
	int tmpval;

#ifdef HW_PLC_3
	int *plc_freq;
#endif

#ifdef HW_HIFI3_VECTOR
	ae_int32x4 *p_tmp1_32x4;
	ae_int32x4 tmp1_32x4 = 8;
	ae_int32x4 tmp2_32x4;
	ae_int16x4 *p_tmp1_16x4;
	ae_int16x4 tmp1_16x4;
#endif



	mode = st->mode;
	nbEBands = mode->nbEBands;
	overlap = mode->overlap;
#ifndef OPT_DATASIZE2
	decode_mem = (int *)st->_decode_mem;
	oldBandE = (short*)(decode_mem+(DECODE_BUFFER_SIZE+overlap));
	speech_ptr = ((DECODE_BUFFER_SIZE+overlap)<<2)+(nbEBands<<1);
#else
	decode_mem = (int *)st->_decode_mem;
	speech_ptr = (DECODE_BUFFER_SIZE<<2)+(overlap<<1);
	oldBandE = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+(nbEBands<<1);
#endif


	pulses = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+((st->end)<<1);

#ifndef OPT_DATASIZE2
	cap = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+((nbEBands)<<1);
#endif
	fine_priority = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+((st->end)<<1);
	fine_quant = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+((st->end)<<1);

	freq = (int *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+((frame_size)<<2);

#ifndef HW_PLC_3
	norm = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+(frame_size<<1);
	X = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+((frame_size)<<1);
#else
	plc_freq = (int *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+(frame_size<<1);
	norm = (short *)(st->_decode_mem + speech_ptr);
	speech_ptr = speech_ptr+(frame_size<<1);
	X = (short *)(st->_decode_mem + speech_ptr);

#ifdef OPT_DATASIZE2
	cap = (short *)(st->_decode_mem + speech_ptr);                   // calculate_bitalloc(),
	offsets = cap+((nbEBands)<<1);
#endif
	speech_ptr = speech_ptr+((frame_size)<<1);
#endif


#ifdef HW_PLC_UPDATE3
	burst_count = (short *)(st->_decode_mem + speech_ptr);
#endif

	N = frame_size;
	effEnd = st->end;



#ifdef HW_PLC_3
	if(plc_enable == 1)
	{
//		short fake_pitch;

#ifndef HW_PLC_UPDATE3X
		postfilter_gain = 0;
		postfilter_pitch = 0;

#else
		if((*burst_count)>0)
		{
			postfilter_gain = 0;
			postfilter_pitch = 0;
		}
		else
		{
			postfilter_gain = SSC_MULT16x16_Q15(st->postfilter_gain,24576);  // ÀÌÀü gainÀÇ 75% ¼öÁØ
			postfilter_pitch = st->postfilter_period;
		}
#endif
		




/////////////////////////////////////////////////////////
		rc_dec_init(&_dec,(unsigned char*)data,len);
		dec = &_dec;
////////////////////////////////////////////////////////




////////////////////////////////////////////////////////



	//	fake_pitch = postfilter_gain>0;


#ifndef PLC_NEW3
		plc_proc(freq,oldBandE);
#else
		plc_proc(freq,oldBandE,st);
#endif

#ifdef HW_PLC_BURST_COUNT
		st->plc_burst_cnt++;
#endif

		goto HW_PLC_LOC;
	}
#ifdef HW_PLC_UPDATE3
	else
	{
		*burst_count = 0;
	}
#endif
#endif


#ifdef HW_DEBUG_TABLE_INPUT
	for(i = 0; i<28; i++)
	{
		data[i] = table_data[i];
	}
#endif


	//Í¬²½×Ö·û
	syncword = data[0];


#ifndef CRC_ON_4BIT
	if(!(syncword==SYNCWORD_16K)) return 0;
#else
	syncword = syncword & 0xf0;
	if(!(syncword==SYNCWORD_16K)) return 0;


	crc_flag = CheckCRC4(data);
	if (crc_flag != 0)
	{
		return -4;
	}
#endif


#ifdef CRC_ON_8BIT


#ifndef HW_CODESIZE
	crc_flag_8bit = CheckCRC8(data+1);
#else
	crc = UpdateCRC8(data+1);
	if(crc != data[1])
	{
		crc_flag_8bit = 2;
	}
#endif


	if (crc_flag_8bit != 0)
	{
////////////// CRC ErrorÀÏ¶§ PLC working À¯¹«¿¡ ´ëÇÑ Á¤Ã¥À» °áÁ¤ÇØ¾ß ÇÔ.
		
#ifndef HW_PLC_3x		
		return -4;
#else

#ifndef HW_PLC_UPDATE
		short fake_pitch;
		postfilter_gain = 0;
		postfilter_pitch = 0;
#else
		postfilter_gain = SSC_MULT16x16_Q15(st->postfilter_gain,24576);  // ÀÌÀü gainÀÇ 75% ¼öÁØ
		postfilter_pitch = st->postfilter_period;
#endif
		rc_dec_init(&_dec,(unsigned char*)data,len);
		dec = &_dec;

		fake_pitch = postfilter_gain>0;
		plc_proc(freq,oldBandE,fake_pitch);

		goto HW_PLC_LOC;
#endif
//////////////////////////////////////////////////////////////////////////
	}

	data = data+2;
	len = len - 2;
#else
	data++;
	len = len-1;
#endif

	rc_dec_init(&_dec,(unsigned char*)data,len);
	dec = &_dec;

//	ec_dec_normalize(dec);


	total_bits = len<<3;
	tell = ec_tell(dec);
	if (tell >= total_bits) silence = 1;
	else if (tell==1) silence = rc_dec_bit_logp(dec, 15);
	else silence = 0;
	if(silence)
	{
		tell = len<<3;
		dec->nbits_total+=tell-ec_tell(dec);
#ifdef HW_SILENCE_DEC
		postfilter_pitch = 0;
		postfilter_gain = 0;
		goto HW_SILENCE_1;
#endif
	}

	postfilter_gain = 0;
	postfilter_pitch = 0;
	if (tell+16 <= total_bits)
	{
		if(rc_dec_bit_logp(dec, 1))
		{
			int qg, octave;

			octave = rc_dec_uint(dec, 6);
			postfilter_pitch = (16<<octave)+rc_dec_bits(dec, 4+octave)-1;
			qg = rc_dec_bits(dec, 3);
#ifndef HW_HIFI3
			postfilter_gain = 3072*(qg+1);
#else
			postfilter_gain = SSC_MULT16x16(3072,(qg+1));
#endif
		}
		tell = ec_tell(dec);
	}

	/* Decode the global flags (first symbols in the stream) */
//	intra_ener = tell+3<=total_bits ? rc_dec_bit_logp(dec, 3) : 0;  // ==> ENCODER¿Í ÇÔ²² ÃßÈÄ¿¡ »©ÀÚ.  BIT¸¸ ³¶ºñÇÏ°í ¾È¾²ÀÓ.

//	tell+3<=total_bits ? rc_dec_bit_logp(dec, 3) : 0;  // ==> ENCODER¿Í ÇÔ²² ÃßÈÄ¿¡ »©ÀÚ.  BIT¸¸ ³¶ºñÇÏ°í ¾È¾²ÀÓ.
	if(tell+3 <= total_bits)
    {
        rc_dec_bit_logp(dec, 3);
    }

	/* Get band energies */

#ifdef HW_DEBUG_TABLE_INPUT
		for (i=0;i<nbEBands;i++)
			oldBandE[i]=0;
#endif


#ifndef HW_CODESIZE
	unquant_coarse_energy(mode, st->end, oldBandE, intra_ener, dec);
#else
	unquant_coarse_energy(mode, st->end, oldBandE, dec);
#endif


	cap = _cap;
	total_bits<<=BITRES;
	tell = ec_tell_frac(dec);
	alloc_trim = (tell+48) <= total_bits ? rc_dec_icdf(dec, trim_icdf, 7) : 5;
	bits = ((int)len<<6) - ec_tell_frac(dec) - 1;



	compute_offset(oldBandE,offsets);

	codedBands = calculate_bitalloc(mode, st->end, offsets,  cap,
		alloc_trim, bits, &balance, pulses,
		fine_quant, fine_priority, dec,-10000   );


#ifdef HW_PLC_BURST_COUNT
	st->plc_burst_cnt = 0;
#endif
	
	unquant_fine_energy(mode, st->end, oldBandE, fine_quant, dec);

//&st->rng

	quant_all_bands_dec(mode, st->end, X, norm, pulses,
		len<<6, balance, dec,  codedBands, &st->rng,oldBandE);





#ifndef HW_HIFI3
	unquant_energy_finalise(mode, st->end, oldBandE,
			fine_quant, fine_priority, len*8-ec_tell(dec), dec);
#else
	unquant_energy_finalise(mode, st->end, oldBandE,
			fine_quant, fine_priority, (len<<3)-ec_tell(dec), dec);
#endif

#ifdef HW_SILENCE_DEC
HW_SILENCE_1:
#endif


#ifdef HW_PLC_3	
	SUN_COPY_32(plc_freq, freq, N);
#endif


	if (silence)
	{
		for (i=nbEBands;i--;)
			oldBandE[i] = -28672;
		freq[0] = 0;
		for (i=N-1;i ;i--)
			freq[i] = 0;
	} else {
		/* Synthesis */
		denormalise_bands(mode, X, freq, oldBandE, effEnd); 
	}




HW_PLC_LOC: 

    out_syn = decode_mem+DECODE_BUFFER_SIZE-N;  
	SUN_COPY_32(decode_mem, decode_mem+N, DECODE_BUFFER_SIZE-N+(overlap>>1));


	clt_mdct_backward(mode->trig, freq, out_syn);

#ifdef HW_DEBUG_COUNTx
	if(rvp_count == 59)
	{
		for(i=0; i<120; i++)
		{
			printf("freq[%d] = %d\n",i,freq[i]);
		}
		printf("\n\n");
		for(i=0; i<240; i++)
		{
			printf("out_syn[%d] = %d\n",i,out_syn[i]);
		}

	}
#endif



	if(st->postfilter_gain_old!=0 || st->postfilter_gain!=0)
		comb_filter(out_syn, out_syn, st->postfilter_period_old, st->postfilter_period, overlap,
		st->postfilter_gain_old, st->postfilter_gain, overlap);
#ifdef HW_PLC_UPDATEx
	else if(plc_enable == 1)  // PLC´Â ¹«Á¶°Ç combfilter Åë°úÇÏ°Ô ÇÏÀÚ...  #
	{
	//	if (plc_pitch_info[2] != 0) // ÇÑ¹øµµ update ¾ÈµÅ¾î, ÃÊ¹Ý¿¡ 0ÀÌ ¿Ã¼öµµ ÀÖÀ¸¹Ç·Î...
			comb_filter(out_syn, out_syn, 172, 122, overlap, 12378, 9821, overlap);
	}
#endif



#ifndef PLC_COMB_1
	st->postfilter_period_old = st->postfilter_period;
	st->postfilter_gain_old = st->postfilter_gain;


	st->postfilter_period = postfilter_pitch;
	st->postfilter_gain = postfilter_gain;
#else


#ifndef AFTER_190327_OPTI
	if(plc_enable)
	{
		if(st->postfilter_period_old == st->postfilter_period && st->postfilter_period != 0)
		{
			postfilter_gain = SSC_MULT16x32_Q15(24960,SPEECH_MIN(st->postfilter_gain,st->postfilter_gain_old));
			st->postfilter_gain_old = st->postfilter_gain;
			st->postfilter_gain = postfilter_gain;
		}
		else
		{
			st->postfilter_period_old = st->postfilter_period;
			st->postfilter_gain_old = st->postfilter_gain;

			st->postfilter_period = postfilter_pitch;
			st->postfilter_gain = postfilter_gain;
		}
	}
	else
	{
		st->postfilter_period_old = st->postfilter_period;
		st->postfilter_gain_old = st->postfilter_gain;

		st->postfilter_period = postfilter_pitch;
		st->postfilter_gain = postfilter_gain;
	}
#else
#ifndef PLC_NEW3_ADDITIONAL
	if(plc_enable && (st->postfilter_period_old == st->postfilter_period && st->postfilter_period != 0))   // ABS(st->postfilter_period_old - st->postfilter_period) < 5, 10
	{
		postfilter_gain = SSC_MULT16x32_Q15(24960,SPEECH_MIN(st->postfilter_gain,st->postfilter_gain_old));
		st->postfilter_gain_old = st->postfilter_gain;
		st->postfilter_gain = postfilter_gain;
	}
#else
	if(plc_enable && (  ABS(st->postfilter_period_old - st->postfilter_period)<12 && (st->postfilter_period != 0)   )) 
	{
		postfilter_gain = SSC_MULT16x32_Q15(30320,SPEECH_MIN(st->postfilter_gain,st->postfilter_gain_old));
		st->postfilter_gain_old = st->postfilter_gain;
		st->postfilter_gain = postfilter_gain;
		postfilter_pitch = (st->postfilter_period_old + st->postfilter_period)>>1;
		st->postfilter_period_old = st->postfilter_period;
		st->postfilter_period = postfilter_pitch;
	}
#endif
	else
	{
		st->postfilter_period_old = st->postfilter_period;
		st->postfilter_gain_old = st->postfilter_gain;

		st->postfilter_period = postfilter_pitch;
		st->postfilter_gain = postfilter_gain;
	}


#endif






#endif




#ifdef HW_PLC_UPDATEx
	if(postfilter_gain>0)
	{
	//	plc_pitch_info[1] = plc_pitch_info[0];   // T0
	//	plc_pitch_info[0] = postfilter_pitch;    // T1

		plc_pitch_info[2] = SSC_MULT16x16_Q15(postfilter_gain,29492);

	}
#endif

	st->rng = dec->rng;

	/* We reuse freq[] as scratch space for the de-emphasis */





#ifndef HW_HIFI3_VECTOR
	i=N-1;

	do{
	//	ae_int32x4 tmp;
		tmpval = SSC_PSHR(out_syn[i],4);
#ifndef VC_PROJ
		pcm[i--] = AE_SAT16X4_scalar(tmpval);
#else
		tmpval = SPEECH_MAX(tmpval,-32768);
		pcm[i--] = SPEECH_MIN(tmpval,32767); 
#endif
		tmpval = SSC_PSHR(out_syn[i],4);

#ifndef VC_PROJ
		pcm[i--] = AE_SAT16X4_scalar(tmpval);
#else
		tmpval = SPEECH_MAX(tmpval,-32768);
		pcm[i--] = SPEECH_MIN(tmpval,32767); 
#endif
		tmpval = SSC_PSHR(out_syn[i],4);
#ifndef VC_PROJ
		pcm[i--] = AE_SAT16X4_scalar(tmpval);
#else
		tmpval = SPEECH_MAX(tmpval,-32768);
		pcm[i--] = SPEECH_MIN(tmpval,32767); 
#endif
		tmpval = SSC_PSHR(out_syn[i],4);
#ifndef VC_PROJ
		pcm[i--] = AE_SAT16X4_scalar(tmpval);
#else
		tmpval = SPEECH_MAX(tmpval,-32768);
		pcm[i--] = SPEECH_MIN(tmpval,32767); 
#endif
	}
	while(i>-1);
#else

	p_tmp1_32x4 = (ae_int32x4 *)(out_syn);
//	p_tmp1_16x4 = (ae_int16x4 *)(&pcm[N-1]);   // ¿ä°É·Î ÇÏ¸é Á×À½.....


	for(i=0;i<N;i=i+4)
	{
		ae_int16x4 *p_tmp2_local_16x4 = (ae_int16x4 *)(&pcm[i]);
		tmp2_32x4 = AE_INT32X4_ADD(*p_tmp1_32x4, tmp1_32x4);
		tmp2_32x4 =	AE_INT32X4_SRAI32(tmp2_32x4, 4);
		*p_tmp2_local_16x4 =  AE_SAT16X4_vector(tmp2_32x4);
		p_tmp1_32x4++;
	}
#endif


/*
#ifdef HW_DEBUG_COUNT
	if(rvp_count == 61)
	{
		for(i=0; i<120; i++)
		{
			printf("pcm[%d] = %d\n",i,pcm[i]);
		}
	}
#endif
*/




#ifdef HW_DEBUG_COUNT
	rvp_count++;
#endif



#ifndef HW_HIFI3
	if (ec_tell(dec) > 8*len) 
		return SUN_INTERNAL_ERROR;
#else
	if (ec_tell(dec) > (len<<3))
		return SUN_INTERNAL_ERROR;
#endif
	if(ec_get_error(dec)) st->error = 1;
	return frame_size; //    /st->downsample;
}

#ifndef HW_30BYTE
short speech_decode(void *_st, const unsigned char *data, short len, short *pcm, short frame_size)
{
	short ret1, ret2;
	ret1 = speech_decode_inside(_st, data, len>>1, pcm, frame_size>>1);
	if(ret1>0)
	{
		ret2 = speech_decode_inside(_st, data+(len>>1), len>>1, pcm+(frame_size>>1), frame_size>>1);
		if(ret2>0)
		{
			ret1 = ret1+ret2;
		}
	}
	return ret1;
}
#endif


short speech_decoder_get_size()
{
#ifndef HW_PLC_3
	return (sizeof(SPEECHDecoder)+2848); 
#else
#ifndef HW_PLC_UPDATE3
#ifndef OPT_DATASIZE2
	return (sizeof(SPEECHDecoder)+3088);
#else
	return (sizeof(SPEECHDecoder)+2816);
//	return (sizeof(SPEECHDecoder)+2820);
#endif
#else
	return (sizeof(SPEECHDecoder)+3092);
#endif


#endif
}

void speech_decoder_init(void *dec, short Fs)
{
    SPEECHDecoder* speech_dec = (SPEECHDecoder *)dec;
#ifndef HW_DATA_SIZE_STATIC_MODES
	sun_custom_decoder_init(speech_dec, &mode16000_160_40);
#else
	sun_custom_decoder_init(speech_dec, ssc_custom_mode_create());
#endif
    speech_dec->Fs = Fs;

}
