/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
*/
 
/* misc2.c  requantization, stereo processing, reordering(shortbl) and antialiasing butterflies
 *
 * misc.c was created by tomislav uzelac in May 1996, and was completely awful
 * Created by: tomislav uzelac Dec 22 1996
 * new stereo_l code by ???, May 7 1997
 */
#include "amp.h"
#include "audio.h"
#include "getdata.h"
#include "huffman.h"

#define MISC2
#include "misc2.h"

/* 
 * fras == Formula for Requantization and All Scaling **************************
 */
static inline float fras_l(int sfb,int global_gain,int scalefac_scale,int scalefac,int preflag)
{
register int a,scale;
	/*
        if (scalefac_scale) scale=2;
	else scale=1;
	*/
	scale=scalefac_scale+1;
	a= global_gain -210 -(scalefac << scale);
        if (preflag) a-=(t_pretab[sfb] << scale);

/* bugfix, Mar 13 97: shifting won't produce a legal result if we shift by more than 31
 * since global_gain<256, this can only occur for (very) negative values of a.
*/
	if (a < -127) return 0;

/* a minor change here as well, no point in abs() if we now that a<0
*/
        if (a>=0) return tab[a&3]*(1 << (a>>2));
	else return tabi[(-a)&3]/(1 << ((-a) >> 2));
}

static inline float fras_s(int global_gain,int subblock_gain,int scalefac_scale,int scalefac)
{
int a;
        a=global_gain - 210 - (subblock_gain << 3);
	if (scalefac_scale) a-= (scalefac << 2);
	else a-= (scalefac << 1);

        if (a < -127) return 0;

        if (a>=0) return tab[a&3]*(1 << (a>>2));
        else return tabi[(-a)&3]/(1 << ((-a) >> 2));
}

/* this should be faster than pow()
 */
static inline float fras2(int is,float a)
{
        if (is > 0) return t_43[is]*a;
        else return -t_43[-is]*a;
}

/*
 * requantize_mono *************************************************************
 */

/* generally, the two channels do not have to be of the same block type - that's why we do two passes with requantize_mono.
 * if ms or intensity stereo is enabled we do a single pass with requantize_ms because both channels are same block type
 */

void requantize_mono(int gr,int ch,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
{
int l,i,sfb;
float a;
int global_gain=info->global_gain[gr][ch];
int scalefac_scale=info->scalefac_scale[gr][ch];
int sfreq=header->sampling_frequency;


	no_of_imdcts[0]=no_of_imdcts[1]=32;

	if (info->window_switching_flag[gr][ch] && info->block_type[gr][ch]==2)	
		if (info->mixed_block_flag[gr][ch]) {
	/*
	 * requantize_mono - mixed blocks/long block part **********************
	 */
	                int window,window_len,preflag=0; /* pretab is all zero in this low frequency area */
	                int scalefac=scalefac_l[gr][ch][0];

			l=0;sfb=0;
			a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
	                while (l<36) {
	                        xr[ch][0][l]=fras2(is[ch][l],a);
	                        if (l==t_l[sfb]) {
					scalefac=scalefac_l[gr][ch][++sfb];
					a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
				}
	                        l++;
	                }
	/*
	 * requantize_mono - mixed blocks/short block part *********************
	 */
			sfb=3; 
			window_len=t_s[sfb]-t_s[sfb-1];
	                while (l<non_zero[ch]) {
	                	for (window=0;window<3;window++) {
	                        	int scalefac=scalefac_s[gr][ch][sfb][window];
	                                int subblock_gain=info->subblock_gain[gr][ch][window];
					a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
	                                for (i=0;i<window_len;i++) {
      		                                xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
	                                	l++;
                                       	}
                               	}
                               	sfb++;
                               	window_len=t_s[sfb]-t_s[sfb-1];
			}
			while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
		} else {
	/*
	 * requantize mono - short blocks **************************************
	 */
			int window,window_len;

			sfb=0; l=0;
			window_len=t_s[0]+1;
			while (l<non_zero[ch]) {
				for (window=0;window<3;window++) {
					int scalefac=scalefac_s[gr][ch][sfb][window];
					int subblock_gain=info->subblock_gain[gr][ch][window];
					float a=fras_s(global_gain,subblock_gain,scalefac_scale,scalefac);
					for (i=0;i<window_len;i++) {
						xr[ch][0][t_reorder[header->ID][sfreq][l]]=fras2(is[ch][l],a);
						l++;
					}
				}
				sfb++;
				window_len=t_s[sfb]-t_s[sfb-1];
			}
			while (l<576) xr[ch][0][t_reorder[header->ID][sfreq][l++]]=0;
		}
	else {
	/* long blocks */
		int preflag=info->preflag[gr][ch];
		int scalefac=scalefac_l[gr][ch][0];

		sfb=0; l=0;
		a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
		while (l<non_zero[ch]) {
			xr[ch][0][l]=fras2(is[ch][l],a); 
			if (l==t_l[sfb]) {
				scalefac=scalefac_l[gr][ch][++sfb];
				a=fras_l(sfb,global_gain,scalefac_scale,scalefac,preflag);
			}
			l++;
		}		
		while (l<576) xr[ch][0][l++]=0;
	}
}

/*
 * stereo stuff ****************************************************************
 */
static int find_isbound(int isbound[3],int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
{
int sfb,window,window_len,ms_flag,tmp,i;

	isbound[0]=isbound[1]=isbound[2]=-1;
	no_of_imdcts[0]=no_of_imdcts[1]=32;

   if (header->mode_extension==1 || header->mode_extension==3) {
	if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {

	/* find that isbound!
	 */
		tmp=non_zero[1];
		sfb=0; while ((3*t_s[sfb]+2) < tmp  && sfb < 12) sfb++;
		while ((isbound[0]<0 || isbound[1]<0 || isbound[2]<0) && !(info->mixed_block_flag[gr][0] && sfb<3) && sfb) {
			for (window=0;window<3;window++) {
				if (sfb==0) {
					window_len=t_s[0]+1;
					tmp=(window+1)*window_len - 1;
				} else {
					window_len=t_s[sfb]-t_s[sfb-1];
					tmp=(3*t_s[sfb-1]+2) + (window+1)*window_len;
				}
				if (isbound[window] < 0)
					for (i=0;i<window_len;i++)
						if (is[1][tmp--] != 0) {
							isbound[window]=t_s[sfb]+1; 
							break;
						}
			}
			sfb--;
		}
	
	/* mixed block magic now...
	 */
		if (sfb==2 && info->mixed_block_flag[gr][0]) 
			if (isbound[0]<0 && isbound[1]<0 && isbound[2]<0) {
				tmp=35;
				while (is[1][tmp] == 0) tmp--;
				sfb=0; while (t_l[sfb] < tmp  && sfb < 21) sfb++;
				isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
			} else for (window=0;window<3;window++) 
				if (isbound[window]<0) isbound[window]=36;
		if (header->ID==1) isbound[0]=isbound[1]=isbound[2]=MAX(isbound[0],MAX(isbound[1],isbound[2]));

	/* just how many imdcts?
	 */
		tmp=non_zero[0];
		sfb=0; while ((3*t_s[sfb]+2) < tmp && sfb < 12) sfb++;
		no_of_imdcts[0]=no_of_imdcts[1]=(t_s[sfb]-1)/6+1; 
	} else {

	/* long blocks now
	 */
                tmp=non_zero[1];
                while (is[1][tmp] == 0) tmp--;
                sfb=0; while (t_l[sfb] < tmp && sfb < 21) sfb++;
		isbound[0]=isbound[1]=isbound[2]=t_l[sfb]+1;
		no_of_imdcts[0]=no_of_imdcts[1]=(non_zero[0]-1)/18+1; 
	}
	if (header->mode_extension==1) ms_flag=0;
	else ms_flag=1;
   } else {

   /* intensity stereo is, regretably, turned off
    */
	ms_flag=1;

	/* i really put a lot of work in this, but it still looks like shit (works, though)
	 */ 
	if (!info->window_switching_flag[gr][0] || (info->window_switching_flag[gr][0] && info->block_type[gr][0]!=2)) 
		isbound[0]=isbound[1]=isbound[2]=(MAX(non_zero[0],non_zero[1]));
	else isbound[0]=isbound[1]=isbound[2]=576;

	if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2) {
		/* should do for mixed blocks too, though i havent tested... */
			tmp=(MAX(non_zero[0],non_zero[1]))/3;
			sfb=0; while (t_s[sfb]<tmp && sfb<12) sfb++;
			no_of_imdcts[0]=no_of_imdcts[1]=(t_s[sfb]-1)/6+1;
	}
	else no_of_imdcts[0]=no_of_imdcts[1]=(isbound[0]-1)/18+1;

   }

   return ms_flag;
}

static inline void stereo_s(int l,float a[2],int pos,int ms_flag,int is_pos,struct AUDIO_HEADER *header)
{
float ftmp,Mi,Si;

	if (l>=576) return; /* brrr... */

        if ((is_pos != IS_ILLEGAL) && (header->ID==1)) {
                ftmp=fras2(is[0][l],a[0]);
                xr[0][0][pos]=(1-t_is[is_pos])*ftmp;
                xr[1][0][pos]=t_is[is_pos]*ftmp;
		return;
	}

	if ((is_pos != IS_ILLEGAL) && (header->ID==0)) {
		ftmp=fras2(is[0][l],a[0]);
		if (is_pos&1) {
			xr[0][0][pos]= t_is2[intensity_scale][(is_pos+1)>>1] * ftmp;
			xr[1][0][pos]= ftmp;
		} else {
			xr[0][0][pos]= ftmp;
			xr[1][0][pos]= t_is2[intensity_scale][is_pos>>1] * ftmp;
		}
		return;
	}

        if (ms_flag) {
                Mi=fras2(is[0][l],a[0]);
                Si=fras2(is[1][l],a[1]);
                xr[0][0][pos]=(Mi+Si)*i_sq2;
                xr[1][0][pos]=(Mi-Si)*i_sq2;
        } else {
                xr[0][0][pos]=fras2(is[0][l],a[0]);
                xr[1][0][pos]=fras2(is[1][l],a[1]);
        }
}

static inline void stereo_l(int l,float a[2],int ms_flag,int is_pos,struct AUDIO_HEADER *header)
{
float ftmp,Mi,Si;
	if (l>=576) return;

/* new code by ???
*/
	if (is_pos != IS_ILLEGAL) {
		ftmp = fras2(is[0][l], a[0]);
		if (header -> ID ==1) {
			xr[0][0][l] = (1 - t_is[is_pos]) * ftmp;
			xr[1][0][l] = t_is[is_pos] * ftmp;
			return;
		} else if (is_pos & 1) {
			xr[0][0][l] = t_is2[intensity_scale][(is_pos + 1) >> 1] * ftmp;
			xr[1][0][l] = ftmp;
		} else {
			xr[0][0][l] = ftmp;
			xr[1][0][l] = t_is2[intensity_scale][is_pos >> 1] * ftmp;
		}
		return;
	}

	if (ms_flag) {
		Mi=fras2(is[0][l],a[0]);
		Si=fras2(is[1][l],a[1]);
		xr[0][0][l]=(Mi+Si)*i_sq2;
		xr[1][0][l]=(Mi-Si)*i_sq2;
	} else {
		xr[0][0][l]=fras2(is[0][l],a[0]);
		xr[1][0][l]=fras2(is[1][l],a[1]);
	}

}


/*
 * requantize_ms ***************************************************************
 */
void requantize_ms(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header)
{
int l,sfb,ms_flag,is_pos,i,ch;
int *global_gain,subblock_gain[2],*scalefac_scale,scalefac[2],isbound[3];
int sfreq=header->sampling_frequency;
int id = header->ID;
float a[2];

global_gain=info->global_gain[gr];
scalefac_scale=info->scalefac_scale[gr];

        if (info->window_switching_flag[gr][0] && info->block_type[gr][0]==2)  
                if (info->mixed_block_flag[gr][0]) {
	/* 
	 * mixed blocks w/stereo processing - long block part ******************
	 */
                        int window,window_len;
                        int preflag[2]={0,0};

			ms_flag=find_isbound(isbound,gr,info,header);

			sfb=0; l=0;
			for (ch=0;ch<2;ch++) {
				scalefac[ch]=scalefac_l[gr][ch][0];
				a[ch]=fras_l(0,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
			}


			while (l<36) {
				int is_pos;
				if (l<isbound[0]) is_pos=IS_ILLEGAL;
				else {
					is_pos=scalefac[1];
					if (id==1) /* MPEG1 */
						if (is_pos==7) is_pos=IS_ILLEGAL;
					else /* MPEG2 */
						if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;
				}

				stereo_l(l,a,ms_flag,is_pos,header);

				if (l==t_l[sfb]) {
					sfb++;
					for (ch=0;ch<2;ch++) {
						scalefac[ch]=scalefac_l[gr][ch][sfb];
						a[ch]=fras_l(sfb,global_gain[ch],scalefac_scale[ch],scalefac[ch],preflag[ch]);
					}
				}

				l++;
			}
	/*
	 * mixed blocks w/stereo processing - short block part *****************
	 */
                        sfb=3;
                        window_len=t_s[sfb]-t_s[sfb-1];

                        while (l<(MAX(non_zero[0],non_zero[1]))) {
                                for (window=0;window<3;window++) {
                                        subblock_gain[0]=info->subblock_gain[gr][0][window];
					subblock_gain[1]=info->subblock_gain[gr][1][window];
					scalefac[0]=scalefac_s[gr][0][sfb][window];
					scalefac[1]=scalefac_s[gr][1][sfb][window];

					if (t_s[sfb] < isbound[window]) {
						is_pos=IS_ILLEGAL;
						a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
						a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
					} else {
						is_pos=scalefac[1];
						if (id==1) /* MPEG1 */
							if (is_pos==7) is_pos=IS_ILLEGAL;
						else /* MPEG2 */
							if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;
 
						a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
					}

                                        for (i=0;i<window_len;i++) {
                                                stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
                                                l++;
                                        }
                                }
                                sfb++;
                                window_len=t_s[sfb]-t_s[sfb-1];
                        }
                        while (l<576) {
			        int reorder = t_reorder[id][sfreq][l++];
			  
				xr[0][0][reorder]=xr[1][0][reorder]=0;
			}
                } else {                                                                       
        /*
	 * requantize_ms - short blocks w/stereo processing ********************
	 */
                        int window,window_len;

			ms_flag=find_isbound(isbound,gr,info,header);	
			sfb=0; l=0;
			window_len=t_s[0]+1;

                        while (l<(MAX(non_zero[0],non_zero[1]))) {
                                for (window=0;window<3;window++) {
					subblock_gain[0]=info->subblock_gain[gr][0][window];
					subblock_gain[1]=info->subblock_gain[gr][1][window];
					scalefac[0]=scalefac_s[gr][0][sfb][window];
					scalefac[1]=scalefac_s[gr][1][sfb][window];

                                        if (t_s[sfb] < isbound[window]) {
                                                is_pos=IS_ILLEGAL;
						a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
						a[1]=fras_s(global_gain[1],subblock_gain[1],scalefac_scale[1],scalefac[1]);
                                        } else {
                                                is_pos=scalefac[1];
                                                if (id==1) /* MPEG1 */
                                                        if (is_pos==7) is_pos=IS_ILLEGAL;
                                                else /* MPEG2 */
                                                        if (is_pos==is_max[sfb+6]) is_pos=IS_ILLEGAL;

                                                a[0]=fras_s(global_gain[0],subblock_gain[0],scalefac_scale[0],scalefac[0]);
                                        }

                                        for (i=0;i<window_len;i++) {
						stereo_s(l,a,t_reorder[id][sfreq][l],ms_flag,is_pos,header);
						l++;
					}
                                }
                                /* this won't do anymore
				 * window_len=-t_s[sfb]+t_s[++sfb];
				 */
				window_len  = -t_s[sfb++];
				window_len +=  t_s[sfb];

                        }
                        while (l<576) {
			        int reorder = t_reorder[id][sfreq][l++];
			  
				xr[0][0][reorder]=xr[1][0][reorder]=0;
			}
                }
        else {
        /*
	 * long blocks w/stereo processing *************************************
	 */
                int *preflag=info->preflag[gr];

		ms_flag=find_isbound(isbound,gr,info,header);

		sfb=0; l=0;
		scalefac[0]=scalefac_l[gr][0][sfb];
		a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
		scalefac[1]=scalefac_l[gr][1][sfb];
		a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);

		/* no intensity stereo part
		*/
	if (ms_flag)
                while (l< isbound[0]) {
//#define PENTIUM_RDTSC
#if defined(PENTIUM_RDTSC)

unsigned int cnt4, cnt3, cnt2, cnt1;
static int min_cycles = 99999999;

        __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt4));
#endif

			{
				register float Mi = fras2(is[0][l],a[0]);
				register float Si = fras2(is[1][l],a[1]);
				register float tmp = i_sq2;
				xr[0][0][l]=(Mi+Si)*tmp;
				xr[1][0][l]=(Mi-Si)*tmp;
			}

#if defined(PENTIUM_RDTSC)
                        __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt4));

                        if (cnt2-cnt1 < min_cycles) {
                          min_cycles = cnt2-cnt1;
                          printf("%d cycles\n", min_cycles);
                        }

#endif
                        if (l==t_l[sfb]) {
//#define PENTIUM_RDTSC2
#if defined(PENTIUM_RDTSC2)

unsigned int cnt4, cnt2, cnt1;
static int min_cycles = 99999999;

        __asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt4));
#endif

                                sfb++;
				scalefac[0]=scalefac_l[gr][0][sfb];
				a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
				scalefac[1]=scalefac_l[gr][1][sfb];
				a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
#if defined(PENTIUM_RDTSC2)
                        __asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt4));

                        if (cnt2-cnt1 < min_cycles) {
                          min_cycles = cnt2-cnt1;
                          printf("%d cycles, sfb %d\n", min_cycles, sfb);
                        }

#endif
                        }
                        l++;
                }
	else
                while (l< isbound[0]) {
                        xr[0][0][l]=fras2(is[0][l],a[0]);
                        xr[1][0][l]=fras2(is[1][l],a[1]);
                        if (l==t_l[sfb]) {
                                sfb++;
                                scalefac[0]=scalefac_l[gr][0][sfb];
                                a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
                                scalefac[1]=scalefac_l[gr][1][sfb];
                                a[1]=fras_l(sfb,global_gain[1],scalefac_scale[1],scalefac[1],preflag[1]);
                        }
                        l++;
                }


		/* intensity stereo part
		*/
		while (l<(MAX(non_zero[0],non_zero[1]))) {
			int is_pos=scalefac[1];
	
			if (id==1) /* MPEG1 */
				if (is_pos==7) is_pos=IS_ILLEGAL;
			else /* MPEG2 */
				if (is_pos==is_max[sfb]) is_pos=IS_ILLEGAL;

			stereo_l(l,a,ms_flag,is_pos,header);

			if (l==t_l[sfb]) {
				sfb++;
				scalefac[0]=scalefac_l[gr][0][sfb];
				scalefac[1]=scalefac_l[gr][1][sfb];
				a[0]=fras_l(sfb,global_gain[0],scalefac_scale[0],scalefac[0],preflag[0]);
			}
			l++;
		}

                while (l<576) {
			xr[0][0][l]=0;
			xr[1][0][l]=0;
			l++;
		}
        }
}

/* 
 * antialiasing butterflies ****************************************************
 * 
 */
#ifdef __POWERPC__
void alias_reduction(int ch)
{
	int sb,i;
	float t;
	float x1,x2;
	float *xrchsb=&((float *)xr[ch])[18*1];	
	float Cs0=Cs[0];
	float Cs1=Cs[1];
	float Cs2=Cs[2];
	float Cs3=Cs[3];
	float Cs4=Cs[4];
	float Cs5=Cs[5];
	float Cs6=Cs[6];
	float Cs7=Cs[7];
	float Ca0=Ca[0];
	float Ca1=Ca[1];
	float Ca2=Ca[2];
	float Ca3=Ca[3];
	float Ca4=Ca[4];
	float Ca5=Ca[5];
	float Ca6=Ca[6];
	float Ca7=Ca[7];

    for (sb=1;sb<32;sb++) 
    {
		x1=xrchsb[-1]; 
		x2=xrchsb[ 0];
        xrchsb[ 0]=x2*Cs0+x1*Ca0;
        xrchsb[-1]=x1*Cs0-x2*Ca0;

		x1=xrchsb[-2]; 
		x2=xrchsb[ 1];
        xrchsb[ 1]=x2*Cs1+x1*Ca1;
        xrchsb[-2]=x1*Cs1-x2*Ca1;

		x1=xrchsb[-3]; 
		x2=xrchsb[ 2];
        xrchsb[ 2]=x2*Cs2+x1*Ca2;
        xrchsb[-3]=x1*Cs2-x2*Ca2;

		x1=xrchsb[-4]; 
		x2=xrchsb[ 3];
        xrchsb[ 3]=x2*Cs3+x1*Ca3;
        xrchsb[-4]=x1*Cs3-x2*Ca3;  

   		x1=xrchsb[-5]; 
   		x2=xrchsb[ 4];
        xrchsb[ 4]=x2*Cs4+x1*Ca4;
        xrchsb[-5]=x1*Cs4-x2*Ca4;

		x1=xrchsb[-6]; 
		x2=xrchsb[ 5];
        xrchsb[ 5]=x2*Cs5+x1*Ca5;
        xrchsb[-6]=x1*Cs5-x2*Ca5;

		x1=xrchsb[-7]; 
		x2=xrchsb[ 6];
        xrchsb[ 6]=x2*Cs6+x1*Ca6;
        xrchsb[-7]=x1*Cs6-x2*Ca6;
        
		x1=xrchsb[-8]; 
		x2=xrchsb[ 7];
        xrchsb[ 7]=x2*Cs7+x1*Ca7;
        xrchsb[-8]=x1*Cs7-x2*Ca7;
        
        xrchsb+=18;
	}
}
#else
void alias_reduction(int ch)
{
unsigned int sb;

        for (sb=1;sb<32;sb++) {
	        float *x = xr[ch][sb];
		register float a, b;

	        a = x[0];
		b = x[-1];
                x[-1] = b * Cs[0] - a * Ca[0];
                x[0]  = a * Cs[0] + b * Ca[0];

	        a = x[1];
		b = x[-2];
                x[-2] = b * Cs[1] - a * Ca[1];
                x[1]  = a * Cs[1] + b * Ca[1];

	        a = x[2];
		b = x[-3];
                x[-3] = b * Cs[2] - a * Ca[2];
                x[2]  = a * Cs[2] + b * Ca[2];

	        a = x[3];
		b = x[-4];
                x[-4] = b * Cs[3] - a * Ca[3];
                x[3]  = a * Cs[3] + b * Ca[3];

	        a = x[4];
		b = x[-5];
                x[-5] = b * Cs[4] - a * Ca[4];
                x[4]  = a * Cs[4] + b * Ca[4];

	        a = x[5];
		b = x[-6];
                x[-6] = b * Cs[5] - a * Ca[5];
                x[5]  = a * Cs[5] + b * Ca[5];

	        a = x[6];
		b = x[-7];
                x[-7] = b * Cs[6] - a * Ca[6];
                x[6]  = a * Cs[6] + b * Ca[6];

	        a = x[7];
		b = x[-8];
                x[-8] = b * Cs[7] - a * Ca[7];
                x[7]  = a * Cs[7] + b * Ca[7];
	}
}
#endif