/*****************************************
    SeamlessBufferManagement.c
******************************************/
//#include<memory.h>

//#include<stdbool.h>

#include "SeamlessBufferManagement.h"
//#include "audio.h"
#define false 0
#define true 1


#ifdef SB_DRC_ON
#include "SoundBooster_DRC_classic_impl.h"
#endif


#include "ssc_macro.h"
#ifdef KHW_GET_STATUS_MATCH
extern short get_sbm_state_ret;
#endif


#ifdef KHW_DEBUG_COUNT
int error_check_flag;
#endif

#ifdef KHW_SBM_INIT_DEBUG
 int sbm_firstframe = 0;
#endif


#ifdef SSC_MONOSUM
extern short ssc_mono_sum_info;
#endif


#ifdef SB_DRC_ON
extern int DRC_ChNum;
#endif

#ifdef KHW_DEBUG_COUNT
extern int count;
#endif
// KaiserBessel window
#ifdef WIN2048
 int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin2048.dat"
};
#endif
#ifdef WIN4096
 int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin4096.dat"
//#include "KaiserBesselWin4096int.dat"
};
#endif
#ifdef WIN1536
 int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin1536.dat"
};
#endif
#ifdef WIN1280
 int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin1280.dat"
};
#endif
#ifdef WIN1024
 int win[SPEEDPIV_WINLEN / 2 + 1] = {
#include "KaiserBesselWin1024.dat"
};
#endif

#ifdef WIN864
 int win[SPEEDPIV_WINLEN / 2+1] = {

#if 1 //ndef KHW_SBM_TRY
#include "KaiserBesselWin864.dat"
#else
//#include "KaiserBesselWin864_square.dat"
#include "KaiserBesselWin864_modified_1.dat"
#endif

};
#endif

#ifdef WIN512
 int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin512.dat"
};
#endif


#ifdef WIN510
 int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin510.dat"
};
#endif


#ifdef WIN432
 int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin432.dat"
};
#endif






/*Global variables*/
int *sbm_buf_left;
int *sbm_buf_right;


int wridx;
int rdidx0;
int rdidx1;
int winpos;
int r;

#ifndef DISABLETRANSITION
 int transition_flag, trcnt;
 int SpeedPiV_bypass_flag = 1;
 char DJ_SpeedPiV_Init_flag = 1;
 char DJ_SpeedPiV_SetPar_flag = 1;
#endif

int DJ_SpeedPiV_speed_fix;
int Speed_level;


#ifdef KHW_RMS_COMPENSATE
/*
int before_sbm_rms_left[2];
int before_sbm_rms_right[2];

int after_sbm_rms_left[2];
int after_sbm_rms_right[2];


int delay_power_lr[2];
*/
int before_sbm_rms_left[8];
int before_sbm_rms_right[8];

int after_sbm_rms_left[8];
int after_sbm_rms_right[8];


int delay_power_lr[8];
#endif

Speed_Proc_State_T Speed_Proc_State = SPEED_PROC_STATE_NORMAL;
 int gain_crfade = 0, delta_crfade = 0;
int pitch_prot_cnt = PROTECTION_LIMIT;
 FramePitchGain_T Pg_0, Pg_m1;

 int PitchIsStable = false;
 int pitchcnt = 0;
 int pitchstabstate = 100;
 int goFsz, oFsz = 864;
int gout = 0;
 int prev_ch_type = 0;
int flagEnabled_CROSSFADE_Fin = 0;

int DRC_tmp_buffer_right[SBM_MAX_OUTPUT_NUM];
int SBM_NORMAL_OUTPUT_NUM = 864;
int SBM_FAST_OUTPUT_NUM = 840;
int  SBM_SLOW_OUTPUT_NUM = 888;
#ifdef KHW_RMS_COMPENSATE

#ifndef		KHW_ETC
 int prev_in_rms_L[SUBFRAMES_NUM >> 1] = { 1 << (14), };
 int prev_in_rms_R[SUBFRAMES_NUM >> 1] = { 1 << (14), };
#endif

 int prev_gain_L = 1 << (QGAINRMSCMPNS), prev_gain_R = 1 << (QGAINRMSCMPNS);

#ifndef		KHW_ETC
int in_sbm_rms_left[SUBFRAMES_NUM];
int in_sbm_rms_right[SUBFRAMES_NUM];
#endif
int out_sbm_rms_left[SUBFRAMES_NUM];
int out_sbm_rms_right[SUBFRAMES_NUM];





int in_rms_L[SUBFRAMES_NUM]; //, out_rms_L[SUBFRAMES_NUM];
int in_rms_R[SUBFRAMES_NUM]; // , out_rms_R[SUBFRAMES_NUM];

int gain_L[SUBFRAMES_NUM], gain_R[SUBFRAMES_NUM];

/*externs*/
extern int sbm_internal_count;
extern short SSC_shared_mem[1728 + 4 + 48];


#ifndef DISABLETRANSITION

void deemphasis_mono_in_sbm(int *in_out, int N)
{
	N=N>>2;

#ifdef VC_PROJ
	do
	{
		*in_out++ = SSC_SHR32((*in_out) + (1 << (SIG_SHIFT - 1)), SIG_SHIFT);
		*in_out++ = SSC_SHR32((*in_out) + (1 << (SIG_SHIFT - 1)), SIG_SHIFT);
		*in_out++ = SSC_SHR32((*in_out) + (1 << (SIG_SHIFT - 1)), SIG_SHIFT);
		*in_out++ = SSC_SHR32((*in_out) + (1 << (SIG_SHIFT - 1)), SIG_SHIFT);
	} while (--N);
#else
	ae_int32x4 *p_tmp1_32x4 = (ae_int32x4 *)(in_out);
	ae_int32x4 tmp1_32x4 = (1 << (SIG_SHIFT - 1));
	do
	{
		*p_tmp1_32x4 = AE_INT32X4_ADD(*p_tmp1_32x4, tmp1_32x4);
		*p_tmp1_32x4 = AE_INT32X4_SRAI32(*p_tmp1_32x4, SIG_SHIFT);
		p_tmp1_32x4++;
	} while (--N);
#endif


}


#ifndef KHW_HIFI_VECTOR_COPY
 void memfill32 (int* a, int b, int n)
{ do{ *a++=b; }
#ifndef KHW_OPTI_C
    while(--n>0);
#else
    while(--n);
#endif
}

 void memfill16Alt(short* a, short b, int n)
{
    do{ *a++ = 0; a++; }
#ifndef KHW_OPTI_C
        while (--n > 0);
#else
        while (--n);
#endif
}
#endif

#ifndef KHW_HIFI_VECTOR_COPY
 void memcopy32 (int* a, int* b, int n)
{
    do{ *a++=*b++; }
#ifndef KHW_OPTI_C
    while(--n>0);
#else
    while(--n);
#endif
}
#endif


#endif

void SBM_SetPar(int speed)
{
	DJ_SpeedPiV_SetPar_flag = 1;
	DJ_SpeedPiV_speed_fix = speed;
}

 int Start_PitchCrossFade(int pitch, int r)
{
    if (pitch_prot_cnt < PROTECTION_LIMIT)
    {
        pitch_prot_cnt++;
        return false;
    }

    if (pitch>(SPEEDPIV_BUFLEN/2)+DIST_THR_1) return false;     // protect against jump out of frame

    if (2*pitch<=(SPEEDPIV_BUFLEN/2)+DIST_THR_1) pitch <<= 1;   // double pitch is safer - codec sometimes set pitch as number of "halfperiods"

    int signed_pitch = (r > (1<<16)) ? pitch : -pitch;        // if speed > 0, must jump forward and wise versa

    rdidx1 = rdidx0;
	int irdidx1 = rdidx1;
	int irdidx0 = rdidx0;
    while (ABS(rdidx1 - rdidx0)<(SPEEDPIV_BUFLEN / 2))
    {
        rdidx1 += signed_pitch;
        if (rdidx1>(winpos >> 16)) rdidx1 -= SPEEDPIV_BUFLEN;     if ((rdidx1<(winpos >> 16) - SPEEDPIV_BUFLEN)) rdidx1 += SPEEDPIV_BUFLEN;
		if (irdidx1 == rdidx1 && irdidx0 == rdidx0)
			break;
    }

    gain_crfade=(1<<26);
    delta_crfade = gain_crfade / (SPEEDPIV_BUFLEN/2);

    return true;
}
 void Stop_PitchCrossFade(void)
{
    rdidx0=rdidx1;
}
 void Start_UnconstrainedCrossfade(int r)
{
    int jump=(SPEEDPIV_BUFLEN/2)+DIST_THR_2;
    int signed_jump=(r>(1<<16)) ? jump:-jump;
    rdidx1=rdidx0+signed_jump;
}
 void Stop_UnconstrainedCrossFade(void)
{
    rdidx0=rdidx1;
}




void SBM_SetPitch(int p0, int g0, int pm1, int gm1)
{
    Pg_0.Pitch=p0; Pg_m1.Pitch=pm1;
    Pg_0.Gain=g0; Pg_m1.Gain=gm1;
}

extern int offsetsConfig;
 void ComputePitchStability(void)
{
    pitchstabstate=(((INT64)pitchstabstate*ALPHAPITCHSTATE)+((INT64)Pg_0.Pitch*((1<<QALPHAPITCH)-ALPHAPITCHSTATE)))>>QALPHAPITCH;
    int dv=ABS(Pg_0.Pitch-pitchstabstate);
    // hysteresis
	int maxpitchcnt = PITCHCNTMAX;
	if (offsetsConfig == 7)
		maxpitchcnt += 9; //PITCHCNTMAX 23
    if (dv<PITCH_DV_THR)
    {
        pitchcnt++;
        if (pitchcnt>= maxpitchcnt)
        {
            PitchIsStable=true;
            pitchcnt= maxpitchcnt;
        }
        else
            PitchIsStable=false;
    }
    else
    {
        pitchcnt=0;
        PitchIsStable=false;
    }

}




int SBM_Exe_Frame_Bypass(int *out1,int *out2, int n)  //vector_copy
{

#ifndef KHW_HIFI_VECTOR_COPY
    int nout = n;
#endif

//    int prevwridx = wridx - (SPEEDPIV_BUFLEN >> 1);
    int prevwridx = wridx + rdidx0;

    if (ssc_mono_sum_info == 2)
    {
#ifndef KHW_HIFI_VECTOR_COPY
        do{
            *out1++ = sbm_buf_left[prevwridx];
            *out2++ = sbm_buf_right[prevwridx++];
        } while (--n > 0);
#else
        memcopy32(out1, &sbm_buf_left[prevwridx], n);
        memcopy32(out2, &sbm_buf_right[prevwridx], n);
#endif
    }
    else {

        int *sbm_buf_ptr = sbm_buf_left;

        //int prevwridx;
        if (ssc_mono_sum_info == 1)
        {
            sbm_buf_ptr = sbm_buf_right;
        }

        //prevwridx = wridx - (SPEEDPIV_BUFLEN >> 1);
#ifndef KHW_HIFI_VECTOR_COPY
        do {
            *out1++ = sbm_buf_ptr[prevwridx++];
        } while (--n > 0);
#else
        memcopy32(out1, &sbm_buf_ptr[prevwridx], n);
#endif
    }
#ifndef KHW_HIFI_VECTOR_COPY
    return nout;
#else
    return n;
#endif
}


//int SBM_Exe_Frame(int *out1,int *out2, const short *in, int n)
int SBM_Exe_Frame(int *out1, int *out2, int n)
{
    int nout = 0;
    int bwridx = wridx;
    int brdidx0 = rdidx0;
    int brdidx1 = rdidx1;
    int bwinpos = winpos;   // right corner of triangle window
	int bSpeed_Proc_State = Speed_Proc_State;
	int bflagEnabled_CROSSFADE_Fin = flagEnabled_CROSSFADE_Fin;
	int bpitch_prot_cnt = pitch_prot_cnt;

    // pitch stability compute

    ComputePitchStability();
    
	// </pitch stability compute>
	//SpeedPiV_bypass_flag = 1;
    if (SpeedPiV_bypass_flag)
    {
        nout = SBM_Exe_Frame_Bypass(out1, out2, n);
    }
    else if (ssc_mono_sum_info == 2)
    {
        nout = SBM_Exe_Frame_Ch(out1, out2, 2, n);
		
		/*
			if (count == 30 && r == 67408)
			{
				int k;

				printf("out1\n");
				for (k = 0; k < 840; k++)
				{
					printf("out1[%d] = %d\n", k, out1[k]);
				}

				printf("out2\n");
				for (k = 0; k < 840; k++)
				{
					printf("out2[%d] = %d\n", k, out2[k]);
				}

			}
			*/


        /////////////////////////////////////////////////////////////////////////////////////
        if (nout < oFsz)
        {

            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
			pitch_prot_cnt = bpitch_prot_cnt;
			Speed_Proc_State = bSpeed_Proc_State;
			flagEnabled_CROSSFADE_Fin = bflagEnabled_CROSSFADE_Fin;
            r -= 10;

            nout = SBM_Exe_Frame_Ch(out1, out2, 2, n);

            if (nout < oFsz)/*Tested this never happens but just for protection*/
            {
                out1[oFsz - 1] = 0; // (int)(in[n - 2]);
                out2[oFsz - 1] = 0; // (int)(in[n - 1]);
            }

            r += 10;
        }
        else if (nout > oFsz)
        {
            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
			pitch_prot_cnt = bpitch_prot_cnt;
			Speed_Proc_State = bSpeed_Proc_State;
			flagEnabled_CROSSFADE_Fin = bflagEnabled_CROSSFADE_Fin;
            r += 10;

            nout = SBM_Exe_Frame_Ch(out1, out2, 2, n);

            r -= 10;
        }
    }
    else
    {
        nout = SBM_Exe_Frame_Ch(out1, out2, ssc_mono_sum_info, n);

        /////////////////////////////////////////////////////////////////////////////////////

        if (nout < oFsz)
        {

            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
			pitch_prot_cnt = bpitch_prot_cnt;
			Speed_Proc_State = bSpeed_Proc_State;
			flagEnabled_CROSSFADE_Fin = bflagEnabled_CROSSFADE_Fin;
            r -= 10;

            nout = SBM_Exe_Frame_Ch(out1, out2, ssc_mono_sum_info, n);

            if (nout < oFsz) //Tested this never happens but just for protection
            {
                out1[oFsz - 2] = 0; // (int)(in[n - 2]);
                out1[oFsz - 1] = 0;//  (int)(in[n - 1]);
            }

            r += 10;
        }
        else if (nout > oFsz)
        {

            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
			pitch_prot_cnt = bpitch_prot_cnt;
			Speed_Proc_State = bSpeed_Proc_State;
			flagEnabled_CROSSFADE_Fin = bflagEnabled_CROSSFADE_Fin;
            r += 10;

			nout = SBM_Exe_Frame_Ch(out1, out2, 1, n);

            r -= 10;
        }
    }
    nout = oFsz;

    return nout;
}


#ifndef DISABLETRANSITION

 void SBM_Effect_tr_stereo(int *out1, int *out2, const int *new_buf_left, const int *new_buf_right, int n, int trcnt)
{

    int *old_buf1 = out1;
    int *old_buf2 = out2;

    do{
        int new_data, old_data;

#ifdef KHW_OPTI_HIFI
        ae_int64 tmp_val;
#endif

        int gain = trcnt; if (gain>TRMAXLEVEL) gain = TRMAXLEVEL;

        // left
        old_data = (*old_buf1++);

        new_data = (*new_buf_left++);

        // saturation need?
#ifndef KHW_OPTI_HIFI
        *out1++ = ((((INT64)(old_data - new_data)*gain) >> QTR) + new_data);
#else
        tmp_val = AE_MUL32_HH((old_data - new_data), gain);
        *out1++ = ((int)((long long)AE_SRAI64(tmp_val, QTR))) + new_data;
#endif



        // right

        old_data = *old_buf2++;
        new_data = *new_buf_right++;

        // saturation need?
#ifndef KHW_OPTI_HIFI
        *out2++ = (int)((((INT64)(old_data - new_data)*gain) >> QTR) + new_data);
#else
        tmp_val = AE_MUL32_HH((old_data - new_data), gain);
        *out2++ = ((int)((long long)AE_SRAI64(tmp_val, QTR))) + new_data;
#endif


        trcnt -= TRDECR; if (trcnt<0) trcnt = 0;
    } while (--n>0);
}

 void SBM_Effect_tr_mono(int *out, const int *new_buf, const int *old_buf, int n, int trcnt)
{
    do{
        int new_data, old_data;
#ifdef KHW_OPTI_HIFI
        ae_int64 tmp_val;
#endif
        int gain = trcnt; if (gain>TRMAXLEVEL) gain = TRMAXLEVEL;


        old_data = (*old_buf++);
        new_data = (*new_buf++);



#ifndef KHW_OPTI_HIFI
        *out++ = ((((INT64)(old_data - new_data)*gain) >> QTR) + new_data);
#else
        tmp_val = AE_MUL32_HH((old_data - new_data), gain);
        *out++ = ((int)((long long)AE_SRAI64(tmp_val, QTR))) + new_data;
#endif


        trcnt -= TRDECR; if (trcnt<0) trcnt = 0;
    } while (--n>0);
}


 void SBM_Effect_tr(int *out1, int *out2, const int *new_buf_left, const int *new_buf_right,  int n, int trcnt)
{
    if (ssc_mono_sum_info == 2)
        SBM_Effect_tr_stereo(out1, out2, new_buf_left, new_buf_right, n, trcnt);
    else if (ssc_mono_sum_info == 0)
        SBM_Effect_tr_mono(out1, new_buf_left, out1, n, trcnt);
    else
        SBM_Effect_tr_mono(out1, new_buf_right, out1, n, trcnt);

#endif
}




 void SBM_SetPar_Apply(int speed, int n)
{

    goFsz = (int)((n << 16) / speed);
    Speed_level = ((n << 17) / goFsz + 1) >> 1;

    SpeedPiV_bypass_flag = 0;
    // default values
    transition_flag = NO_TRANSITION;
    // check transition case
    if ((Speed_level != ONE_Q16) && (r != ONE_Q16))
    {
        r = Speed_level;
    }
    else if ((Speed_level == ONE_Q16) && (r != ONE_Q16))
    {
        transition_flag = EFFECT_TO_NORMAL;
        trcnt = TRMAXLEVEL;
//        r = Speed_level;
    }
    else if ((Speed_level != ONE_Q16) && (r == ONE_Q16))
    {
        transition_flag = NORMAL_TO_EFFECT;
        ////////////////////////////////////////////////////////
        trcnt = TRMAXLEVEL<<2/*+ (r)*/;/*TODO: Change shift value by 2 if required, because for first time it wil be all zeroes in half buffer of output*/
        ////////////////////////////////////////////////////////
        Speed_Proc_State = SPEED_PROC_STATE_NORMAL;
    }
    else // ((Speed_level==ONE_Q16) && (Win.winstep==ONE_Q16))
        SpeedPiV_bypass_flag = 1;


}

 void SBM_InitSetPar_EXE(int n)
{
    if (DJ_SpeedPiV_Init_flag)
    {
        SBM_Init();
        DJ_SpeedPiV_Init_flag = 0;
    }
    if (DJ_SpeedPiV_SetPar_flag)
    {
        SBM_SetPar_Apply(DJ_SpeedPiV_speed_fix,n);

        DJ_SpeedPiV_SetPar_flag = 0;
    }
}


// gain smoothing

// int gain_state_L=1<<QGAINRMSCMPNS, gain_state_R=1<<QGAINRMSCMPNS;

 void ApplyGain(int* out, int* in, int start_gain, int stop_gain, int n)
{
	int rcp_n = (1 << QGAINRMSCMPNS_LONG) / n;
	int y0 = start_gain;            
	int y1 = stop_gain;
	int a = (y0 - y1)<<1;
	int b = -3 * (y0 - y1);
	int c = 0;
	int d = y0;
	int x_long = 0;

#ifndef VC_PROJ
	ae_int64 tmp_val;
#endif
	do {
		int x = x_long >> (QGAINRMSCMPNS_LONG - QGAINRMSCMPNS);
		
#ifdef VC_PROJ		
		int y = (((INT64)a*x) >> QGAINRMSCMPNS) + b;
		y = (((INT64)y*x) >> QGAINRMSCMPNS) + c;
		int gain = (((INT64)y*x) >> QGAINRMSCMPNS) + d;

		int data = (((INT64)(*in++)*gain)) >> QGAINRMSCMPNS;
#else
		int y, gain, data;
		tmp_val = AE_MUL32_HH(a, x);
		y = (int)((long long)AE_SRAI64(tmp_val, QGAINRMSCMPNS)) ;

		tmp_val = AE_MUL32_HH(y+b, x);
		y = (int)((long long)AE_SRAI64(tmp_val, QGAINRMSCMPNS));

		tmp_val = AE_MUL32_HH(y+c, x);
		gain = (int)((long long)AE_SRAI64(tmp_val, QGAINRMSCMPNS));

		tmp_val = AE_MUL32_HH((*in++) , gain+d);
		data = (int)((long long)AE_SRAI64(tmp_val, QGAINRMSCMPNS));
#endif


		*out++ = data;

		x_long += rcp_n;
	} while (--n > 0);
}


#endif



void SBM_gain_control(int *gain, int *in_rms, int *out_sbm_rms, int prev_gain)
{
	int gain_tmp;
	int subMAXGAIN, subMINGAIN;
	int tmp_val;
	int i;

	gain_tmp = (((INT64)in_rms[0]) << QGAINRMSCMPNS) / (MAX(1, out_sbm_rms[0]));

#ifdef KHW_RMS_GAIN_SMOOTHE
	tmp_val = (prev_gain - (1 << QGAINRMSCMPNS))*(gain_tmp - (1 << QGAINRMSCMPNS));
	if (tmp_val >= 0)
	{
		subMAXGAIN = prev_gain + MAX_GAIN_DIFF;
		subMINGAIN = prev_gain - MAX_GAIN_DIFF;

		if (gain_tmp > subMAXGAIN)
			gain_tmp = subMAXGAIN;
		if (gain_tmp < subMINGAIN)
			gain_tmp = subMINGAIN;
	}
	else  // input ??? output ??? ??? ??
	{
		subMAXGAIN = (1 << QGAINRMSCMPNS) + MAX_GAIN_DIFF;
		subMINGAIN = (1 << QGAINRMSCMPNS) - MAX_GAIN_DIFF;

		if (gain_tmp > subMAXGAIN)
			gain_tmp = subMAXGAIN;
		if (gain_tmp < subMINGAIN)
			gain_tmp = subMINGAIN;
	}
#endif

	if (gain_tmp > MAXGAIN)
		gain_tmp = MAXGAIN;
	if (gain_tmp < MINGAIN)
		gain_tmp = MINGAIN;
	gain[0] = gain_tmp;

	for (i = 1; i < SUBFRAMES_NUM; i++)
	{
		gain_tmp = (((INT64)in_rms[i]) << QGAINRMSCMPNS) / (MAX(1, out_sbm_rms[i]));

#ifdef KHW_RMS_GAIN_SMOOTHE
		tmp_val = (gain[i - 1] - (1 << QGAINRMSCMPNS))*(gain_tmp - (1 << QGAINRMSCMPNS));
		if (tmp_val >= 0)
		{
			subMAXGAIN = gain[i - 1] + MAX_GAIN_DIFF;
			subMINGAIN = gain[i - 1] - MAX_GAIN_DIFF;

			if (gain_tmp > subMAXGAIN)
				gain_tmp = subMAXGAIN;
			if (gain_tmp < subMINGAIN)
				gain_tmp = subMINGAIN;
		}
		else  // input ??? output ??? ??? ??
		{
			subMAXGAIN = (1 << QGAINRMSCMPNS) + MAX_GAIN_DIFF;
			subMINGAIN = (1 << QGAINRMSCMPNS) - MAX_GAIN_DIFF;

			if (gain_tmp > subMAXGAIN)
				gain_tmp = subMAXGAIN;
			if (gain_tmp < subMINGAIN)
				gain_tmp = subMINGAIN;
		}
#endif
		if (gain_tmp > MAXGAIN)
			gain_tmp = MAXGAIN;
		if (gain_tmp < MINGAIN)
			gain_tmp = MINGAIN;
		gain[i] = gain_tmp;
	}

}


int SBM_Exe(short *out, int n, int *DRC_tmp_buf[])
{
    int i;
    int outnum;
    int bupssc_mono_sum_info;


#ifdef	HW_INIT_CLEAN

#ifdef VC_PROJ
	for (i = 0; i < (1728 + 4 + 48); i++)
	{
		SSC_shared_mem[i] = 0;
	}
#else
	__vec_memset(((char *)SSC_shared_mem), 0, (1728 + 4 + 48)<<1);
#endif

#endif


    int *drc_tmp_buf_left = (int *)SSC_shared_mem;
    int *drc_tmp_buf_right = DRC_tmp_buffer_right;


    sbm_buf_left = DRC_tmp_buf[0]+1024; //-(1024 + 54 - 160);
    sbm_buf_right = DRC_tmp_buf[1]+1024; //-(1024 + 54 - 160);

    // Init and SetPar apply
    SBM_InitSetPar_EXE(n);
    bupssc_mono_sum_info = ssc_mono_sum_info;

    switch (transition_flag)
    {

        case NORMAL_TO_EFFECT:
        {
            r = Speed_level; oFsz = goFsz;
            wridx = 0;

			//printf("1\n");

//            rdidx0 = -(SPEEDPIV_WINLEN >> 1);

            rdidx1 = 0;
            winpos = 0;   // right corner of triangle window
            outnum = SBM_Exe_Frame(drc_tmp_buf_left,drc_tmp_buf_right, n);
/*
			if (count == 30)
			{
				int k;
  
				printf("drc_tmp_buf_left\n");
				for (k = 0; k < 840; k++)
				{
					printf("drc_tmp_buf_left[%d] = %d\n", k, drc_tmp_buf_left[k]);
				}

				printf("drc_tmp_buf_right\n");
				for (k = 0; k < 840; k++)
				{
					printf("drc_tmp_buf_right[%d] = %d\n", k, drc_tmp_buf_right[k]);
				}

			}
*/
            transition_flag = NO_TRANSITION;
        }
        break;

//        case EFFECT_TO_NORMAL:
//        {
//            oFsz = goFsz;
//            outnum = SBM_Exe_Frame(drc_tmp_buf_left,drc_tmp_buf_right,  n);
//            outnum = n;
//
//            SBM_Effect_tr(drc_tmp_buf_left, drc_tmp_buf_right, (sbm_buf_left- (SPEEDPIV_WINLEN >> 1)), (sbm_buf_right - (SPEEDPIV_WINLEN >> 1)),  n, trcnt);
//            trcnt -= n; if (trcnt <= 0) { trcnt = 0; transition_flag = NO_TRANSITION; SpeedPiV_bypass_flag = 1;}
//        }
//        break;

        case EFFECT_TO_NORMAL:
            if (Speed_Proc_State!=SPEED_PROC_STATE_NORMAL /*&& (flagEnabled_CROSSFADE_Fin && (Speed_Proc_State == SPEED_PROC_STATE_PROC_CROSSFADE))*/)
            {
                //oFsz = goFsz;
                outnum = SBM_Exe_Frame(drc_tmp_buf_left, drc_tmp_buf_right, n);
                if (Speed_Proc_State==SPEED_PROC_STATE_NORMAL) {transition_flag = NO_TRANSITION; r=Speed_level; oFsz = goFsz;                }
            }
            else
            {
                oFsz = goFsz;
				if (ssc_mono_sum_info == 2)
				{
					memcopy32(drc_tmp_buf_left, sbm_buf_left + rdidx0, n);
					memcopy32(drc_tmp_buf_right, sbm_buf_right + rdidx0, n);
				}
				else if(ssc_mono_sum_info == 0)
					memcopy32(drc_tmp_buf_left, sbm_buf_left + rdidx0, n);
				else
					memcopy32(drc_tmp_buf_left, sbm_buf_right + rdidx0, n);
                outnum=n;
                transition_flag = NO_TRANSITION; r=Speed_level;
            }
            break;

        default:
            outnum = SBM_Exe_Frame(drc_tmp_buf_left,drc_tmp_buf_right, n);
            break;
    }



#ifdef KHW_RMS_COMPENSATE
	int in_n2 = n / SUBFRAMES_NUM;
	int out_n2 = outnum / SUBFRAMES_NUM;

/*
	if (out_n2>108)
	{

		printf("sadf");
	}
*/
//	printf("before ssc_mono_sum_info == 0 ");
	if (ssc_mono_sum_info == 0)
	{
		if (get_sbm_state_ret != 0)
		{

			for (i = 0; i < SUBFRAMES_NUM; i++)
			{
				in_rms_L[i] = SoundBooster_DRC_classic_rms_mono32(sbm_buf_left- (SPEEDPIV_WINLEN >> 1) + (in_n2*i), in_n2);
				out_sbm_rms_left[i] = SoundBooster_DRC_classic_rms_mono32(drc_tmp_buf_left + out_n2 * i, out_n2);
			}

			SBM_gain_control(gain_L, in_rms_L, out_sbm_rms_left, prev_gain_L);

			for (i = 0; i < SUBFRAMES_NUM; i++)
			{   			
				// left
				int start_gain = prev_gain_L; 
				int stop_gain = gain_L[i];
				ApplyGain(drc_tmp_buf_left + out_n2 * i, drc_tmp_buf_left + out_n2 * i, start_gain, stop_gain, out_n2);
				prev_gain_L = gain_L[i];

				prev_gain_R = (1 << QGAINRMSCMPNS);
				gain_R[i] = prev_gain_R;
			}
		}
		else
		{
			ApplyGain(drc_tmp_buf_left, drc_tmp_buf_left, prev_gain_L, (1 << QGAINRMSCMPNS), out_n2);

			for (i = 0; i < SUBFRAMES_NUM; i++)
			{
				gain_L[i] = (1 << QGAINRMSCMPNS);
			}
			prev_gain_L = (1 << QGAINRMSCMPNS);
		}  // if (get_sbm_state_ret != 0)
		
	}   // if (ssc_mono_sum_info == 0)
	else if(ssc_mono_sum_info == 1)
	{


		if (get_sbm_state_ret != 0)
		{
			for (i = 0; i < SUBFRAMES_NUM; i++)
			{
				in_rms_R[i] = SoundBooster_DRC_classic_rms_mono32(sbm_buf_right- (SPEEDPIV_WINLEN >> 1) + (in_n2*i), in_n2);
				out_sbm_rms_right[i] = SoundBooster_DRC_classic_rms_mono32(drc_tmp_buf_left + out_n2 * i, out_n2);   // right channel??? mono???? drc_tmp_buf_left ?.
			}

			SBM_gain_control(gain_R, in_rms_R, out_sbm_rms_right, prev_gain_R);


			for (i = 0; i < SUBFRAMES_NUM; i++)
			{   // left
				int start_gain, stop_gain;
				
				prev_gain_L = (1 << QGAINRMSCMPNS);
				gain_L[i] = prev_gain_L;
				// right
				start_gain = prev_gain_R; stop_gain = gain_R[i];
				ApplyGain(drc_tmp_buf_left + out_n2 * i, drc_tmp_buf_left + out_n2 * i, start_gain, stop_gain, out_n2);
				prev_gain_R = gain_R[i];
			}
		}
		else
		{
			ApplyGain(drc_tmp_buf_left, drc_tmp_buf_left, prev_gain_R, (1 << QGAINRMSCMPNS), out_n2);

			for (i = 0; i < SUBFRAMES_NUM; i++)
			{
				gain_R[i] = (1 << QGAINRMSCMPNS);
			}
			prev_gain_R = (1 << QGAINRMSCMPNS);
		}
	}
	else
	{
	/*
		if (count == 78)
		{
			printf("sadf");
		}
*/

//		printf("afeter else ");
		if (get_sbm_state_ret != 0)
		{

			for (i = 0; i < SUBFRAMES_NUM; i++)
			{
				in_rms_L[i] = SoundBooster_DRC_classic_rms_mono32((sbm_buf_left- (SPEEDPIV_WINLEN >> 1)) + (in_n2*i), in_n2);
				in_rms_R[i] = SoundBooster_DRC_classic_rms_mono32((sbm_buf_right- (SPEEDPIV_WINLEN >> 1)) + (in_n2*i), in_n2);
				out_sbm_rms_left[i] = SoundBooster_DRC_classic_rms_mono32(drc_tmp_buf_left + out_n2 * i, out_n2);
				out_sbm_rms_right[i] = SoundBooster_DRC_classic_rms_mono32(drc_tmp_buf_right + out_n2 * i, out_n2);
			}


			SBM_gain_control(gain_L, in_rms_L, out_sbm_rms_left, prev_gain_L);
			SBM_gain_control(gain_R, in_rms_R, out_sbm_rms_right, prev_gain_R);

			for (i = 0; i < SUBFRAMES_NUM; i++)
			{   // left
				int start_gain = prev_gain_L; int stop_gain = gain_L[i];
				ApplyGain(drc_tmp_buf_left + out_n2 * i, drc_tmp_buf_left + out_n2 * i, start_gain, stop_gain, out_n2);
				prev_gain_L = gain_L[i];

				// right
				start_gain = prev_gain_R; stop_gain = gain_R[i];
				ApplyGain(drc_tmp_buf_right + out_n2 * i, drc_tmp_buf_right + out_n2 * i, start_gain, stop_gain, out_n2);
				prev_gain_R = gain_R[i];
			}

		}
		else
		{
			ApplyGain(drc_tmp_buf_left, drc_tmp_buf_left, prev_gain_L, (1 << QGAINRMSCMPNS), out_n2);
			ApplyGain(drc_tmp_buf_right, drc_tmp_buf_right, prev_gain_R, (1 << QGAINRMSCMPNS), out_n2);

			for (i = 0; i < SUBFRAMES_NUM; i++)
			{
				gain_L[i] = (1 << QGAINRMSCMPNS);
				gain_R[i] = (1 << QGAINRMSCMPNS);
			}
			prev_gain_L = (1 << QGAINRMSCMPNS);
			prev_gain_R = (1 << QGAINRMSCMPNS);
		}
	}
#endif



#ifdef KHW_RMS_COMPENSATE_debug
	int out_sbm_rms_left_debug[SUBFRAMES_NUM];
	int out_sbm_rms_right_debug[SUBFRAMES_NUM];

	for (i = 0; i < SUBFRAMES_NUM; i++)
	{
		out_sbm_rms_left_debug[i] = SoundBooster_DRC_classic_rms_mono32(drc_tmp_buf_left + out_n2 * i, out_n2);
		//	out_sbm_rms_left[i] = out_sbm_rms_left[i] >> 6;

		out_sbm_rms_right_debug[i] = SoundBooster_DRC_classic_rms_mono32(drc_tmp_buf_right + out_n2 * i, out_n2);
		//	out_sbm_rms_right[i] = out_sbm_rms_right[i] >> 6;


		if (out_sbm_rms_left[i] > in_rms_L[i])
		{
			if (out_sbm_rms_left_debug[i] > out_sbm_rms_left[i])
			{
				printf("strange case 1\n");
			}
			else if (out_sbm_rms_left_debug[i] < in_rms_L[i])
			{
				printf("strange case 2\n");
			}
		}



		if (out_sbm_rms_right[i] > in_rms_R[i])
		{
			if (out_sbm_rms_right_debug[i] > out_sbm_rms_right[i])
			{
				printf("strange case 3\n");
			}
			else if (out_sbm_rms_right_debug[i] < in_rms_R[i])
			{
				printf("strange case 4\n");
			}
		}

	}

#endif

    if (ssc_mono_sum_info < 2)
    {
        deemphasis_mono_in_sbm(drc_tmp_buf_left, outnum);
    }
    else
    {
        deemphasis_mono_in_sbm(drc_tmp_buf_left, outnum);
        deemphasis_mono_in_sbm(drc_tmp_buf_right, outnum);
    }

////////////////////////////////////////////////////////////////
    // ref_sbm_rms_left base,   after_sbm_rms_right adjust


/////////////////////////////////////////////////////////////////
/*
    if (count > 29)
    {
        printf("sadf\n");
    }
*/


#ifdef SB_DRC_ON_REAL
	DRC_ChNum = (ssc_mono_sum_info>1)+1;

    for(i=0;i<8;i++)
    {
        SoundBooster_DRC_Exe(&drc_tmp_buf_left[(outnum>>3)*i],&drc_tmp_buf_right[(outnum>>3)*i], (outnum>>3) );
    }

#endif  //SB_DRC_ON


    if (ssc_mono_sum_info == 2)
    {
        for(i=0;i<outnum;i++)
        {
#ifndef KHW_OPTI_HIFI
            if (*drc_tmp_buf_left < -32768)
                *out++ = -32768;
            else if (*drc_tmp_buf_left > 32767)
                *out++ = 32767;
            else
                *out++ = (short)(*drc_tmp_buf_left);


            if (*drc_tmp_buf_right < -32768)
                *out++ = -32768;
            else if (*drc_tmp_buf_right > 32767)
                *out++ = 32767;
            else
                *out++ = (short)(*drc_tmp_buf_right);

            drc_tmp_buf_left++;
            drc_tmp_buf_right++;
#else
            *out++ = AE_SAT16X4_scalar(*drc_tmp_buf_left);
            *out++ = AE_SAT16X4_scalar(*drc_tmp_buf_right);
            drc_tmp_buf_left++;
            drc_tmp_buf_right++;
#endif
        }
    }
    else
    {

        for(i=0;i<outnum;i++)
        {
#ifndef KHW_OPTI_HIFI
            if (*drc_tmp_buf_left < -32768)
                *out++ = -32768;
            else if (*drc_tmp_buf_left > 32767)
                *out++ = 32767;
            else
                *out++ = (short)(*drc_tmp_buf_left);

            drc_tmp_buf_left++;
#else
            *out++ = AE_SAT16X4_scalar(*drc_tmp_buf_left);
            drc_tmp_buf_left++;
#endif
        }

    }

    prev_ch_type = bupssc_mono_sum_info;
    return(outnum);
}


void SBM_Init(void)
{

    short i;
    pitch_prot_cnt = PROTECTION_LIMIT;
#ifdef    KHW_RMS_COMPENSATE
    delay_power_lr[0] = 0;
    delay_power_lr[1] = 0;
    delay_power_lr[2] = 0;
    delay_power_lr[3] = 0;
    delay_power_lr[4] = 0;
    delay_power_lr[5] = 0;
    delay_power_lr[6] = 0;
    delay_power_lr[7] = 0;
#endif
    // default values
#ifndef DISABLETRANSITION
    transition_flag = NO_TRANSITION;
    SpeedPiV_bypass_flag = 0;
#endif
    wridx = 0;


#ifndef KHW_DELAY_CONTROL
	rdidx0 = -(SPEEDPIV_WINLEN >> 1);
#else
	rdidx0 = SBM_DELAY_CONTROL;

#endif
    rdidx1 = 0;

    winpos = 0;   // right corner of triangle window

    // For Pitch Sync
    Speed_Proc_State = SPEED_PROC_STATE_NORMAL;
    PitchIsStable=false;
    pitchcnt=0;
    pitchstabstate = 100;

#ifndef    KHW_SBM_INIT_DEBUG
    r = 1 << 16;    // default speed 1.0x
#else
    if(sbm_firstframe == 0)
    {
        r = 1 << 16;    // default speed 1.0x
        sbm_firstframe = 1;
    }
#endif



#ifdef	HW_INIT_CLEAN

	for (i = 0; i < 888 ; i++)
	{
		DRC_tmp_buffer_right[i] = 0;
	}

#endif

}
