#include <fftw3.h>
#include <math.h>
#include <limits.h>

#define FRAME_LEN 256
#define OUT_FILE_PCM "input.raw"
#define OUT_FILE_FFT "fft.raw"

int main(int argc, char *argv[])
{
	FILE *fhOutPcm = NULL;
	FILE *fhOutFft = NULL;
	
	if((fhOutPcm = fopen(OUT_FILE_PCM, "wb")) == NULL) {
		printf("file open error : %s", OUT_FILE_PCM);
		return 1;
	}

	if((fhOutFft = fopen(OUT_FILE_FFT, "wb")) == NULL) {
		printf("file open error : %s", OUT_FILE_FFT);
		return 1;
	}

	// FFTW  time sig -> freq sig -> time sig 
	double *sig1 = new double[FRAME_LEN];
	double *sig2 = new double[FRAME_LEN];
	
	size_t fft_buf_size = sizeof(fftw_complex) * FRAME_LEN;
	
	fftw_plan plan_r2c    = NULL;
	fftw_plan plan_c2r    = NULL;
	
	fftw_complex *fft_buf = NULL;
	fft_buf = (fftw_complex*) fftw_malloc( fft_buf_size );

	plan_r2c = fftw_plan_dft_r2c_1d(FRAME_LEN, sig1, fft_buf, FFTW_ESTIMATE);
	
	// input data sig1
	for(int i = 0; i < FRAME_LEN; i++) {
		sig1[i] = sin( 2 * M_PI * i / FRAME_LEN ) * 0.5 + sin( 44 * M_PI * i / FRAME_LEN ) * 0.5;
	}
	
	// fft exec time sig -> freq sig
	fftw_execute(plan_r2c);

	// ----- debug out 
	short *tmps = new short[FRAME_LEN];
	
	for(int i = 0; i < FRAME_LEN; i++) {
		tmps[i] = (short) (fft_buf[i][0] / FRAME_LEN * SHRT_MAX);
	}
	fwrite(tmps, sizeof(short), FRAME_LEN, fhOutFft);
	fclose(fhOutFft);
	// ----------
	for(int i = 0; i < FRAME_LEN; i++) {
		tmps[i] = (short) (sig1[i] * SHRT_MAX);
	}
	fwrite(tmps, sizeof(short), FRAME_LEN, fhOutPcm);
	fclose(fhOutPcm);
	// ----- debug out [end]

	// -- c2r --
	plan_c2r = fftw_plan_dft_c2r_1d(FRAME_LEN, fft_buf, sig2, FFTW_ESTIMATE);

	fftw_execute(plan_c2r);

	// print signal data
	printf("num\tsig1\t\tsig2\t\treal\t\timag\n");
	for(int i = 0; i < FRAME_LEN; i++) {
		printf("%d\t%lf\t%lf\t%lf\t%lf\n", i, sig1[i], sig2[i] / FRAME_LEN
		                                 , fft_buf[i][0], fft_buf[i][1]);
	}
	
	if(sig1) {
		delete[] sig1;
	}
	
	if(sig2) {
		delete[] sig2;
	}

	if(plan_r2c) {
		fftw_destroy_plan(plan_r2c);
	}

	if(fft_buf) {
		fftw_free(fft_buf);
	}
	
	return 0;
}
