/* FFT Program */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.141592653589793
#define SIZE 512
#define SIZEMAX SIZE*4

float Sin[SIZEMAX], Cos[SIZEMAX];
int maketable = 0;
int tablesize;


/*	f[^́Cȉ̂悤ɒɃ[g̃f[^D
	Data is given as    data[0] ---- data[63] data[64] ---- data[127]
	                     -64           -1       0              +63
	flag : Select FFT (1) or Inverse FFT (-1)
*/

FFT1D( RealData, ImageData, n, flag, normalize )
float RealData[], ImageData[];
int n, flag;
int normalize;
{
	int i, j, it, xp, xp2, k, j1, j2, im1, jm1;
	float sign, wr, wi, dr1, dr2, di1, di2, tr, ti;
	static float *WReal, *WImage;
	int arg, w;
	int iter;
	if( n < 2 )
		return( -1 );

	if( maketable == 0 )
	{
		MakeTable( n ); /* Op֐e[u̍쐬 */
		maketable = 1;	
		tablesize = n;
	}
	WReal = (float *)malloc( sizeof(float)*n ); /* f[^i[̈̊m */
	WImage = (float *)malloc( sizeof(float)*n );
	if( WReal == NULL || WImage == NULL )
	{
		printf( "Memory Over\n" );
		exit(0);
	}
  
/* f[^̓ւ */
	memcpy( WReal, &RealData[n/2], sizeof(float)*(n/2) );
	memcpy( WImage, &ImageData[n/2], sizeof(float)*(n/2) );
	memcpy( &WReal[n/2], &RealData[0], sizeof(float)*(n/2) );
	memcpy( &WImage[n/2], &ImageData[0], sizeof(float)*(n/2) );	
	
	iter = 0;
	i = n;
	while( 1 )
	{
		if( ( i /= 2 ) == 0 )
			break;
		iter++;
	}

	j = 1;

	for( i = 0; i < iter; i++ )
		j << 1;

	if( flag == 1 || flag == 0 )
		sign = 1.0;
	else
		sign = -1.0;

	xp2 = n;

	for( it = 0; it < iter; it++ )
	{
		xp = xp2;
		xp2 = xp / 2;
		w = n / xp2;
		for( k = 0; k < xp2; k++ )
		{
			arg = k * w;
			wr = Cos[arg];
			wi = sign * Sin[arg];
			i = k - xp;
			for( j = xp; j <= n; j+= xp )
			{
				j1 = j + i;
				j2 = j1 + xp2;
				dr1 = WReal[j1];
				dr2 = WReal[j2];
				di1 = WImage[j1];
				di2 = WImage[j2];
				tr = dr1 - dr2;
				ti = di1 - di2;
				WReal[j1] = dr1 + dr2;
				WImage[j1] = di1 + di2;
				WReal[j2] = tr * wr - ti * wi;
				WImage[j2] = ti * wr + tr * wi;
			}
		}
	}

	j1 = n / 2;
	j2 = n - 1;
	j = 1;

	for( i = 1; i < j2; i++ )
	{
		if( i < j )
		{
			im1 = i - 1;
			jm1 = j - 1;
			tr = WReal[jm1];
			ti = WImage[jm1];
			WReal[jm1] = WReal[im1];
			WImage[jm1] = WImage[im1];
			WReal[im1] = tr;
			WImage[im1] = ti;
		}
		k = j1;
		while( k < j )
		{
			j -= k;
			k /= 2;
		}
		j += k;
	}

/*Ki@*/
	if( normalize != 0 )
	{
		w = sqrt((float)n);
		for( i = 0; i < n; i++ )
		{	
			WReal[i] = WReal[i] / w;
			WImage[i] = WImage[i] / w;
		}
	}

/* vZʂ̕ёւ */
	memcpy( &RealData[n/2], WReal, sizeof(float)*(n/2) );
	memcpy( &ImageData[n/2], WImage, sizeof(float)*(n/2) );
	memcpy( &RealData[0], &WReal[n/2], sizeof(float)*(n/2) );
	memcpy( &ImageData[0], &WImage[n/2], sizeof(float)*(n/2) );	
	
	return(0);
}

MakeTable(n)@/*@Op֐e[u̍쐬@*/
int n;
{
	int i;

	for( i = 0; i < n; i++ )
	{
		Sin[i] = sin((float)PI*i/n);
		Cos[i] = cos((float)PI*i/n);
	}
}