/*****************************************
    SeamlessBufferManagement.c
******************************************/
//#include<memory.h>

#include "SeamlessBufferManagement.h"
#include "config.h"

#ifndef VC_PROJ
#include <xtensa/tie/xt_hifi2.h>
#endif

typedef long long INT64;


#ifdef SSC_MONOSUM
extern short ssc_mono_sum_info;
#endif

// KaiserBessel window
#ifdef WIN2048
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin2048.dat"
};
#endif
#ifdef WIN4096
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin4096.dat"
//#include "KaiserBesselWin4096int.dat"
};
#endif
#ifdef WIN1536
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin1536.dat"
};
#endif
#ifdef WIN1280
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin1280.dat"
};
#endif
#ifdef WIN1024
static int win[SPEEDPIV_WINLEN / 2 + 1] = {
#include "KaiserBesselWin1024.dat"
};
#endif

#ifdef WIN864
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin864.dat"
};
#endif

#ifdef WIN512
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin512.dat"
};
#endif


#ifdef WIN510
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin510.dat"
};
#endif


#ifdef WIN432
static int win[SPEEDPIV_WINLEN / 2+1] = {
#include "KaiserBesselWin432.dat"
};
#endif


#define ABS(x) (((x)>0) ? (x):-(x))
#define MIN(a,b) (((a)<(b)) ? (a):(b))

short sbm_buf[SPEEDPIV_BUFLEN*2];
short bsbm_buf[SPEEDPIV_BUFLEN * 2];
//short sbm_buf[SPEEDPIV_BUFLEN*2];

//short sbm_bufIn[(SPEEDPIV_BUFLEN/2)+864][2];
short sbm_bufIn[((SPEEDPIV_BUFLEN >>1) + SPEEDPIV_BUFLEN)<<1];
short *sbm_bufIn0;
short *sbm_bufIn0d;
short *sbm_bufIn1;
short *sbm_bufIn1d;

int wridx;
int rdidx0;
int rdidx1;
int winpos;
int r;
int n_prefit;
#define ONE_Q16     (1<<16)
#define ONE_Q32     ((INT64)1<<32)
//#define DISABLETRANSITION
#ifndef DISABLETRANSITION
static int transition_flag, trcnt;
static int SpeedPiV_bypass_flag = 1;
static char DJ_SpeedPiV_Init_flag = 1;
static char DJ_SpeedPiV_SetPar_flag = 1;


#ifndef SBM_FIXED_HIFI_2
float DJ_SpeedPiV_speed;
#else
int DJ_SpeedPiV_speed_fix;
#endif


int Speed_level;
//#define QTR         9
#define QTR         10
#define TRMAXLEVEL  (1<<(10))
//#define TRMAXLEVEL  (1<<(9))
#define TRDECR      1
enum{
    NO_TRANSITION = 0,
    NORMAL_TO_EFFECT,
    EFFECT_TO_NORMAL
};

static void memfill32 (int* a, int b, int n)
{ do{ *a++=b; }
#ifndef KHW_OPTI_C
	while(--n>0); 
#else
	while(--n); 
#endif
}

static void memfill16Alt(short* a, short b, int n)
{
    do{ *a++ = 0; a++; } 
#ifndef KHW_OPTI_C
		while (--n > 0);
#else
		while (--n);
#endif
}

static void memcopy32 (int* a, int* b, int n)
{ 
    do{ *a++=*b++; }
#ifndef KHW_OPTI_C
    while(--n>0);
#else
	while(--n);
#endif
}
static void memcopy16Alt(short* a, short* b, int n)
{
    do{ *a++ = *b++; a++; } while (--n > 0);
}
#endif
int goFsz, oFsz=864;
int gout = 0;
int prev_ch_type = 0;
int SBM_Exe_Frame_Stereo(short *out, const short *in, int n)
{
    int nout = 0;
#ifdef KHW_OPTI_HIFI
    ae_int64 tmp_val;
#endif


        do {
            int d;
            // write next sample

            int in1 = *in++;
            int in2 = *in++;
            sbm_buf[wridx] = in1;
            sbm_buf[SPEEDPIV_BUFLEN + wridx] = in2;
            if (++wridx >= SPEEDPIV_BUFLEN) wridx = 0;
            d = wridx - (winpos >> 16);
            d = ((d + SPEEDPIV_BUFLEN + SPEEDPIV_BUFLEN / 2) % SPEEDPIV_BUFLEN) - SPEEDPIV_BUFLEN / 2;


            while (d > 0)
            {
                // position of window center
                int wincntr = winpos - ((SPEEDPIV_WINLEN << 16) / 2);
                int alpha;
                int idx_alpha;
                int gamma;
                int gamma_m1;
                int idx_beta;
                int beta;
                int dl;
                int dr;



                if (wincntr < 0) wincntr += (SPEEDPIV_BUFLEN << 16);

                // weight of first tap
                alpha = (rdidx0 << 16) - wincntr;
                if (alpha < 0) alpha = -alpha;      // weight in Q27 (16+10)
                if (alpha >(SPEEDPIV_WINLEN << 16) / 2) alpha = (SPEEDPIV_WINLEN << 16) - alpha;


                idx_alpha = alpha >> (16 + 0);			// integer part
                gamma = alpha - (idx_alpha << (16 + 0));		// fractional part (Q(16+0))
                gamma_m1 = (1 << (16 + 0)) - gamma;

#ifndef KHW_OPTI_HIFI
                alpha = (int)((((INT64)win[idx_alpha] * gamma_m1 + (INT64)win[idx_alpha + 1] * gamma)) >> (16 + 0));
#else
                tmp_val = AE_MUL32_HH(win[idx_alpha], gamma_m1);
                AE_MULA32_HH(tmp_val, win[idx_alpha + 1], gamma);
                alpha = (int)((long long)AE_SRAI64(tmp_val, 16));
#endif
                idx_beta = (SPEEDPIV_WINLEN / 2) - 1 - idx_alpha;

#ifndef KHW_OPTI_HIFI
                beta = (int)((((INT64)win[idx_beta] * gamma + (INT64)win[idx_beta + 1] * gamma_m1)) >> (16 + 0));
#else
                tmp_val = AE_MUL32_HH(win[idx_beta], gamma);
                AE_MULA32_HH(tmp_val, win[idx_beta + 1], gamma_m1);
                beta = (int)((long long)AE_SRAI64(tmp_val, 16));
#endif
                /*if (nout >= oFsz)
                    break;*/

#ifndef KHW_OPTI_HIFI
                dl = (int)(((INT64)sbm_buf[rdidx0] * beta + (INT64)sbm_buf[rdidx1] * alpha + (1 << (26 - 1))) >> 26);
                dr = (int)(((INT64)sbm_buf[rdidx0 + SPEEDPIV_BUFLEN] * beta + (INT64)sbm_buf[rdidx1 + SPEEDPIV_BUFLEN] * alpha + (1 << (26 - 1))) >> 26);
#else
                //		tmp_val = (1<<25);
                tmp_val = AE_MUL32_HH(sbm_buf[rdidx0], beta);
                AE_MULA32_HH(tmp_val, sbm_buf[rdidx1], alpha);
                tmp_val = AE_ADD64(tmp_val, (1 << 25));
                dl = (int)((long long)AE_SRAI64(tmp_val, 26));

                //		tmp_val = (1<<25);
                tmp_val = AE_MUL32_HH(sbm_buf[rdidx0 + SPEEDPIV_BUFLEN], beta);
                AE_MULA32_HH(tmp_val, sbm_buf[rdidx1 + SPEEDPIV_BUFLEN], alpha);
                tmp_val = AE_ADD64(tmp_val, (1 << 25));
                dr = (int)((long long)AE_SRAI64(tmp_val, 26));
#endif

#ifndef KHW_OPTI_HIFI
                if (dl < -32768) dl = -32768; if (dl > 32767) dl = 32767;
                if (dr < -32768) dr = -32768; if (dr > 32767) dr = 32767;
#else
                dl = AE_SAT16X4_scalar(dl);
                dr = AE_SAT16X4_scalar(dr);
#endif

                *out++ = dl;
                *out++ = dr;

                nout++;     // increment output sample number

                // increment window pointer
                winpos += r;
                if (winpos >= (SPEEDPIV_BUFLEN << 16)) winpos -= (SPEEDPIV_BUFLEN << 16);

                // increment tap pointers
                if (++rdidx0 >= SPEEDPIV_BUFLEN) rdidx0 = 0;
                if (++rdidx1 >= SPEEDPIV_BUFLEN) rdidx1 = 0;

                d = wridx - (winpos >> 16);
                d = ((d + SPEEDPIV_BUFLEN + SPEEDPIV_BUFLEN / 2) % SPEEDPIV_BUFLEN) - SPEEDPIV_BUFLEN / 2;

            }

        } while (--n > 0);
        return nout;
}
int SBM_Exe_Frame_Mono(short *out, const short *in, int n)
{
    int nout = 0;
	int prevwridx;


#ifdef KHW_OPTI_HIFI
    ae_int64 tmp_val;
#endif
 //   int opcorrec_done = 0;
    short *sbm_buf_ptr = sbm_buf;
    short * in_ptr = (short *)in;
    if (ssc_mono_sum_info == 1)
    {
        if (prev_ch_type == 2)
            memfill32((int *)sbm_buf, 0, SPEEDPIV_BUFLEN >> 1);
        sbm_buf_ptr = &sbm_buf[SPEEDPIV_BUFLEN];
    }
    else if (prev_ch_type == 2)
        memfill32((int *)(&sbm_buf[SPEEDPIV_BUFLEN]), 0, SPEEDPIV_BUFLEN >> 1);

    prevwridx = wridx + (SPEEDPIV_BUFLEN >> 1);
    do {
        int d;
        // write next sample

        int in1 = (*in_ptr++);
        sbm_buf_ptr[wridx] = in1;
        if (++wridx >= SPEEDPIV_BUFLEN) wridx = 0;
        d = wridx - (winpos >> 16);
        d = ((d + SPEEDPIV_BUFLEN + SPEEDPIV_BUFLEN / 2) % SPEEDPIV_BUFLEN) - SPEEDPIV_BUFLEN / 2;

        while (d > 0)
        {
            // position of window center
            int wincntr = winpos - ((SPEEDPIV_WINLEN << 16) / 2);
            int alpha;
            int idx_alpha;
            int gamma;
            int gamma_m1;
            int idx_beta;
            int beta;
            int dl;
            if (wincntr < 0) wincntr += (SPEEDPIV_BUFLEN << 16);

            // weight of first tap
            alpha = (rdidx0 << 16) - wincntr;
            if (alpha < 0) alpha = -alpha;      // weight in Q27 (16+10)
            if (alpha >(SPEEDPIV_WINLEN << 16) / 2) alpha = (SPEEDPIV_WINLEN << 16) - alpha;


            idx_alpha = alpha >> (16 + 0);			// integer part
            gamma = alpha - (idx_alpha << (16 + 0));		// fractional part (Q(16+0))
            gamma_m1 = (1 << (16 + 0)) - gamma;
#ifndef KHW_OPTI_HIFI
            alpha = (int)((((INT64)win[idx_alpha] * gamma_m1 + (INT64)win[idx_alpha + 1] * gamma)) >> (16 + 0));
#else
            tmp_val = AE_MUL32_HH(win[idx_alpha], gamma_m1);
            AE_MULA32_HH(tmp_val, win[idx_alpha + 1], gamma);
            alpha = (int)((long long)AE_SRAI64(tmp_val, 16));
#endif		

            idx_beta = (SPEEDPIV_WINLEN / 2) - 1 - idx_alpha;

#ifndef KHW_OPTI_HIFI
            beta = (int)((((INT64)win[idx_beta] * gamma + (INT64)win[idx_beta + 1] * gamma_m1)) >> (16 + 0));
#else
            tmp_val = AE_MUL32_HH(win[idx_beta], gamma);
            AE_MULA32_HH(tmp_val, win[idx_beta + 1], gamma_m1);
            beta = (int)((long long)AE_SRAI64(tmp_val, 16));
#endif

#ifndef KHW_OPTI_HIFI
            dl = (int)(((INT64)sbm_buf_ptr[rdidx0] * beta + (INT64)sbm_buf_ptr[rdidx1] * alpha + (1 << (26 - 1))) >> 26);
#else
            tmp_val = AE_MUL32_HH(sbm_buf_ptr[rdidx0], beta);
            AE_MULA32_HH(tmp_val, sbm_buf_ptr[rdidx1], alpha);
            tmp_val = AE_ADD64(tmp_val, (1 << 25));
            dl = (int)((long long)AE_SRAI64(tmp_val, 26));
#endif

#ifndef KHW_OPTI_HIFI
            if (dl < -32768) dl = -32768; if (dl > 32767) dl = 32767;
#else
            dl = AE_SAT16X4_scalar(dl);
#endif
            *out++ = dl;

            nout++;     // increment output sample number

            // increment window pointer
            winpos += r;
            if (winpos >= (SPEEDPIV_BUFLEN << 16)) winpos -= (SPEEDPIV_BUFLEN << 16);

            // increment tap pointers
            if (++rdidx0 >= SPEEDPIV_BUFLEN)
                rdidx0 = 0;
            if (++rdidx1 >= SPEEDPIV_BUFLEN)
                rdidx1 = 0;

            d = wridx - (winpos >> 16);
            d = ((d + SPEEDPIV_BUFLEN + SPEEDPIV_BUFLEN / 2) % SPEEDPIV_BUFLEN) - SPEEDPIV_BUFLEN / 2;

        }

    } while (--n > 0);
    return nout;

}
int SBM_Exe_Frame_Bypass(short *out, const short *in, int n)
{
    int nout = n;
    //SpeedPiV_bypass_flag = 1;

#ifdef KHW_OPTI_HIFI
    ae_int64 tmp_val;
#endif
    int opcorrec_done = 0;
    int prevwridx = wridx + (SPEEDPIV_BUFLEN >> 1);
    if (ssc_mono_sum_info == 2)
    {
        do{
            int in1 = *in++;
            int in2 = *in++;
            sbm_buf[wridx] = in1;
            sbm_buf[SPEEDPIV_BUFLEN + wridx] = in2;
            if (++wridx >= SPEEDPIV_BUFLEN) wridx = 0;
            if (prevwridx >= SPEEDPIV_BUFLEN) prevwridx = 0;

            *out++ = sbm_buf[prevwridx];
            *out++ = sbm_buf[prevwridx++ + SPEEDPIV_BUFLEN];
        } while (--n > 0);
    }
    else {
        short *sbm_buf_ptr = sbm_buf;
        short * in_ptr = (short *)in;
		int prevwridx;
        if (ssc_mono_sum_info == 1)
        {
            if (prev_ch_type == 2)
                memfill32((int *)sbm_buf, 0, SPEEDPIV_BUFLEN >> 1);
            sbm_buf_ptr = &sbm_buf[SPEEDPIV_BUFLEN];
        }
        else if (prev_ch_type == 2)
            memfill32((int *)(&sbm_buf[SPEEDPIV_BUFLEN]), 0, SPEEDPIV_BUFLEN >> 1);

        prevwridx = wridx + (SPEEDPIV_BUFLEN >> 1);
        do {

      //      int d;

            int in1 = (*in_ptr++);
            sbm_buf_ptr[wridx] = in1;
            if (++wridx >= SPEEDPIV_BUFLEN) wridx = 0;
            if (SpeedPiV_bypass_flag)
            {
                if (prevwridx >= SPEEDPIV_BUFLEN)
                    prevwridx = 0;
                *out++ = sbm_buf_ptr[prevwridx++];
            }
        } while (--n > 0);
    }
    return nout;
}

int SBM_Exe_Frame_StereoMonoBypass(short *out, const short *in, int n)
{
    int nout = 0;
    int bwridx = wridx;
    int brdidx0 = rdidx0;
    int brdidx1 = rdidx1;
    int bwinpos = winpos;   // right corner of triangle window
    if (SpeedPiV_bypass_flag)
        nout = SBM_Exe_Frame_Bypass(out, in, n);
    else if (ssc_mono_sum_info == 2)
    {
        memcopy32((int *)bsbm_buf, (int *)sbm_buf, n);
        nout = SBM_Exe_Frame_Stereo(out, in, n);
        if (nout < oFsz)
        {
            memcopy32((int *)sbm_buf, (int *)bsbm_buf, n);
            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
            r -= 10;
            nout = SBM_Exe_Frame_Stereo(out, in, n);

			if (nout<oFsz)/*Tested this never happens but just for protection*/
			{
				out[oFsz - 2] = in[n - 2];
				out[oFsz - 1] = in[n - 1];
			}

            r += 10;
        }
        else if (nout > oFsz)
        {
            memcopy32((int *)sbm_buf, (int *)bsbm_buf, n);
            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
            r += 10;
            nout = SBM_Exe_Frame_Stereo(out, in, n);
            r -= 10;
        }
    }
    else
    {
        memcopy32((int *)bsbm_buf, (int *)sbm_buf, n);
        nout = SBM_Exe_Frame_Mono(out, in, n);
        if (nout < oFsz)
        {
            memcopy32((int *)sbm_buf, (int *)bsbm_buf, n);
            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
            r -= 10;
            nout = SBM_Exe_Frame_Mono(out, in, n);
			if (nout<oFsz)/*Tested this never happens but just for protection*/
			{
				out[oFsz - 2] = in[n - 2];
				out[oFsz - 1] = in[n - 1];
			}
            r += 10;
        }
        else if (nout > oFsz)
        {
            memcopy32((int *)sbm_buf, (int *)bsbm_buf, n);
            wridx = bwridx;
            rdidx0 = brdidx0;
            rdidx1 = brdidx1;
            winpos = bwinpos;
            r += 10;
            nout = SBM_Exe_Frame_Mono(out, in, n);
            r -= 10;
        }
    }
	nout = oFsz;
    return nout;
}
int SBM_Exe_Frame(short *out, const short *in, int n)
{
    int nout = SBM_Exe_Frame_StereoMonoBypass(out, in, n);

    return nout;
}
#ifndef DISABLETRANSITION
//static void SBM_Effect_tr(short(*out)[2], const short(*new_buf)[2], const short(*old_buf)[2], int n, int trcnt)
static void SBM_Effect_tr_stereo(short *out, const short *new_buf, const short *old_buf, int n, int trcnt)
{
    do{
        int new_data, old_data;
        int tmp;

#ifdef KHW_OPTI_HIFI
		ae_int64 tmp_val;
#endif

        int gain = trcnt; if (gain>TRMAXLEVEL) gain = TRMAXLEVEL;

        // left

        old_data = (*old_buf++);
        new_data = (*new_buf++);

        // saturation need?
#ifndef KHW_OPTI_HIFI
        tmp = ((((old_data - new_data)*gain) >> QTR) + new_data);
        if (tmp < -32768) tmp = -32768; if (tmp > 32767) tmp = 32767;
        *out++ = (short)tmp;
#else
		tmp_val = AE_MUL32_HH((old_data - new_data), gain);
		tmp = (int)((long long)AE_SRAI64(tmp_val, QTR));
		*out++ = AE_SAT16X4_scalar(tmp+new_data);
#endif

        // right
        old_data = *old_buf++;
        new_data = *new_buf++;

        // saturation need?
#ifndef KHW_OPTI_HIFI
        tmp = (int)((((old_data - new_data)*gain) >> QTR) + new_data);
        if (tmp < -32768) tmp = -32768; if (tmp > 32767) tmp = 32767;
        *out++ = (short)tmp;
#else
		tmp_val = AE_MUL32_HH((old_data - new_data), gain);
		tmp = (int)((long long)AE_SRAI64(tmp_val, QTR));
		*out++ = AE_SAT16X4_scalar(tmp+new_data);
#endif
        trcnt -= TRDECR; if (trcnt<0) trcnt = 0;
    } while (--n>0);
}
static void SBM_Effect_tr_mono(short *out, const short *new_buf, const short *old_buf, int n, int trcnt)
{
    do{
        int new_data, old_data;
        int tmp;
#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++);
        new_buf++;//Skip other channel;
        // saturation need?
#ifndef KHW_OPTI_HIFI
        tmp = ((((old_data - new_data)*gain) >> QTR) + new_data);
        if (tmp < -32768) tmp = -32768; if (tmp > 32767) tmp = 32767;
        *out++ = (short)tmp;
#else
		tmp_val = AE_MUL32_HH((old_data - new_data), gain);
		tmp = (int)((long long)AE_SRAI64(tmp_val, QTR));
		*out++ = AE_SAT16X4_scalar(tmp+new_data);
#endif
        trcnt -= TRDECR; if (trcnt<0) trcnt = 0;
    } while (--n>0);
}

static void SBM_Effect_tr(short *out, const short *new_buf, const short *old_buf, int n, int trcnt)
{
    if (ssc_mono_sum_info == 2)
        SBM_Effect_tr_stereo(out, new_buf, old_buf, n, trcnt);
    else if (ssc_mono_sum_info == 0)
        SBM_Effect_tr_mono(out, new_buf, old_buf, n, trcnt);
    else
        SBM_Effect_tr_mono(out, new_buf+1, old_buf, n, trcnt);
}



#ifndef SBM_FIXED_HIFI_2
static void SBM_SetPar_Apply(float speed, int n)
#else
static void SBM_SetPar_Apply(int speed, int n)
#endif
{
#ifndef DISABLETRANSITION


#ifndef SBM_FIXED_HIFI_2
    float cspeed;
    goFsz = (int)((float)n/speed);
    cspeed = (float)n / (float)goFsz;
    speed = cspeed;
    Speed_level = (int)(speed*(1 << 16) + 0.5f);
#else
    goFsz = (int)((n << 16) / speed);
    Speed_level = ((n << 17) / goFsz + 1) >> 1;
    /*
    Speed_level = speed;


    if(Speed_level>70000)
    {
    Speed_level= Speed_level+23;
    }
    */

#endif

    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*/
        ////////////////////////////////////////////////////////       
        // reset internal buffer
        //memfill32((int*)sbm_buf, 0, sizeof(sbm_buf) >> 2/*MAXWINLEN*/);
        // 'Win.winstep' will be set after transiion period
    }
    else // ((Speed_level==ONE_Q16) && (Win.winstep==ONE_Q16))
        SpeedPiV_bypass_flag = 1;
#else
    r = (int)(speed*(1 << 16) + 0.5f);
#endif

}

static void SBM_InitSetPar_EXE(int n)
{
    if (DJ_SpeedPiV_Init_flag)
    {
        SBM_Init();
        DJ_SpeedPiV_Init_flag = 0;
    }
    if (DJ_SpeedPiV_SetPar_flag)
    {
#ifndef SBM_FIXED_HIFI_2
        SBM_SetPar_Apply(DJ_SpeedPiV_speed,n);
#else
		SBM_SetPar_Apply(DJ_SpeedPiV_speed_fix,n);
#endif
        DJ_SpeedPiV_SetPar_flag = 0;
    }
}


void SBM_Exe_AdjustBuffers(const short *in, int n)
{
    if (ssc_mono_sum_info == 2)
    {
        memcopy32((int *)(sbm_bufIn + SPEEDPIV_BUFLEN), (int *)in, n);
    }
    else if (ssc_mono_sum_info == 1)
    {
        if (prev_ch_type == 2)
        {
            memfill16Alt(sbm_bufIn, 0, ((SPEEDPIV_WINLEN)+(SPEEDPIV_WINLEN >> 1)));
        }
        memcopy16Alt(sbm_bufIn + (SPEEDPIV_WINLEN)+1, (short *)in, n);
    }
    else
    {
        if (prev_ch_type == 2)
        {
            memfill16Alt(sbm_bufIn + 1, 0, ((SPEEDPIV_WINLEN)+(SPEEDPIV_WINLEN >> 1)));
        }
        memcopy16Alt(sbm_bufIn + (SPEEDPIV_WINLEN), (short *)in, n);
    }
}

int SBM_Exe(short *out, const short *in, int n)
{
    int outnum;
	int bupssc_mono_sum_info;
    // Init and SetPar apply
    SBM_InitSetPar_EXE(n);
    bupssc_mono_sum_info = ssc_mono_sum_info;
    SBM_Exe_AdjustBuffers(in, n);
    switch (transition_flag)
    {

    case NORMAL_TO_EFFECT:
    {
        r = Speed_level; oFsz = goFsz;
        wridx = 0;
        rdidx0 = SPEEDPIV_WINLEN >> 1;
        rdidx1 = 0;
        winpos = 0;   // right corner of triangle window

        outnum = SBM_Exe_Frame(out, in, n);
        transition_flag = NO_TRANSITION;
    }
    break;

    case EFFECT_TO_NORMAL:
    {
        oFsz = goFsz;
        outnum = SBM_Exe_Frame(out, in, n);
        outnum = n;
        SBM_Effect_tr(out, sbm_bufIn, out, n, trcnt);
        trcnt -= n; if (trcnt <= 0) { trcnt = 0; transition_flag = NO_TRANSITION; SpeedPiV_bypass_flag = 1;}
    }
    break;

    default:
        outnum = SBM_Exe_Frame(out, in, n);
        break;
    }
    if (ssc_mono_sum_info == 2)
    {
        memcopy32((int *)(sbm_bufIn), (int *)(sbm_bufIn + (n<<1)), (SPEEDPIV_WINLEN >> 1));
    }
    else {
        memcopy32((int *)(sbm_bufIn), (int *)(sbm_bufIn + (n << 1)), (SPEEDPIV_WINLEN >> 1));
    }

    prev_ch_type = bupssc_mono_sum_info;
    //gout += outnum;
    return(outnum);
}

#else
int SBM_Exe(short(*out)[2], const short(*in)[2], int n)
{
    int nout = 0;

    if (n_prefit < SPEEDPIV_BUFLEN)
    {
        int k = MIN(n, SPEEDPIV_BUFLEN - n_prefit);    // how many samples copy to sbm_buf
        memcpy(sbm_buf + n_prefit, in, k * sizeof(short) * 2);
        in += k;    n -= k;
        n_prefit += k;
//        oFsz = goFsz;
    }

    if ((n_prefit >= SPEEDPIV_BUFLEN) && (n > 0))
    {
        nout = SBM_Exe_Frame(out, in, n);
    }

    return nout;
}
#endif

#ifndef KHW_OPTI_C
int SBM_GetPrefitSampleNum(void)
{
    return SPEEDPIV_BUFLEN;
}

void SBM_SetPhase(int phc, int phidx)
{
    winpos = (-phc + (SPEEDPIV_WINLEN << 16)) % (SPEEDPIV_WINLEN << 16);
    //rdidx0=(phidx+(SPEEDPIV_WINLEN<<16)) % (SPEEDPIV_WINLEN<<16);
    //rdidx1 = (rdidx0 + SPEEDPIV_WINLEN / 2) % (SPEEDPIV_WINLEN << 16);
    rdidx0 = (phidx + (SPEEDPIV_WINLEN)) % (SPEEDPIV_WINLEN);
    rdidx1 = (rdidx0 + SPEEDPIV_WINLEN / 2) % (SPEEDPIV_WINLEN);
}
#endif

#define INT_SETPAR
#ifdef INT_SETPAR
void SBM_SetPar(int speed)
{
#ifndef DISABLETRANSITION
    DJ_SpeedPiV_SetPar_flag = 1;

#ifndef SBM_FIXED_HIFI_2
    DJ_SpeedPiV_speed = ((float)speed)/(1<<16);
#else
	 DJ_SpeedPiV_speed_fix = speed;
#endif
#else
    goFsz = (int)((float)864 / ((float)speed) / (1 << 16));
    float cspeed = (float)864 / (float)goFsz;
    oFsz = goFsz;
    r = (int)(cspeed*(1 << 16) + 0.5f);
#endif
}
#else
void SBM_SetPar(float speed)
{
#ifndef DISABLETRANSITION
    DJ_SpeedPiV_SetPar_flag = 1;
    DJ_SpeedPiV_speed = speed;
#else
    goFsz = (int)((float)864 / speed);
    float cspeed = (float)864 / (float)goFsz;
    oFsz = goFsz;
    speed = cspeed;
    r = (int)(speed*(1 << 16) + 0.5f);
#endif
}
#endif
void SBM_Init(void)
{
//	short sbm_buf[SPEEDPIV_BUFLEN][2];
#if 0
    memset(buf, 0, sizeof(buf));
#else
	short i;
	for(i=0; i<SPEEDPIV_BUFLEN; i++)
	{
		sbm_buf[i] = 0;
        sbm_buf[i + SPEEDPIV_BUFLEN] = 0;
	}

#endif


    // default values
#ifndef DISABLETRANSITION
    transition_flag = NO_TRANSITION;
    SpeedPiV_bypass_flag = 0;
#endif
    wridx = 0;
	rdidx0 = SPEEDPIV_WINLEN>>1 ;
    rdidx1 = 0;
    winpos = 0;   // right corner of triangle window
    r = 1 << 16;    // default speed 1.0x
    n_prefit = 0;
}



