/*
 * fftw_lite.c -- a minimal interface to the FFTW FFT library
 *
 * Made for use with Visualworks Smalltalk DLLCC
 * Stephen Pope -- stp@create.ucsb.edu -- 2003.07.17
 */

#include <fftw3.h>
#include "fftw_lite.h"

/******** Complex data type ********/

/* typedef fftwf_complex float[2]; */

// Globals

fftwf_plan f_plan, r_plan;		// Plans for IFFT
fftwf_complex * _spectrum;		// Buffer to store the spectrum
float * _samples;				// Buffer to store samples
unsigned fft_size;

/* initialize FFTW data structures and plans */

int fftw_initialize(unsigned size, float * samples, float /* fftwf_complex */ * spectrum) {
	fft_size = size;
	_spectrum = (fftwf_complex *) spectrum;
	_samples = samples;
	f_plan = fftwf_plan_dft_r2c_1d(fft_size, _samples, _spectrum, FFTW_MEASURE);
	r_plan = fftwf_plan_dft_c2r_1d(fft_size, _spectrum, _samples, FFTW_MEASURE);
	return 0;
}

/* perform forward/reverse FFT */

void fftw_forward_transform(void) {
	fftwf_execute(f_plan);	// FFT a window
}

void fftw_reverse_transform(void) {
	fftwf_execute(r_plan);	// IFFT a window
}

/* int/float block copy to/from float sample buffer */

void fftw_short_to_float(short * data) {
	unsigned i;
	short * in = data;
	float * out = _samples;
	for (i=0; i < fft_size; i++)
		*out++ = (float) ((float) *in++) / 32768.0;
}

void fftw_int_to_float(int * data) {
	unsigned i;
	int * in = data;
	float * out = _samples;
	for (i=0; i < fft_size; i++)
		*out++ = (float) ((float) *in++) / 32768.0;
}

void fftw_float_to_short(short * data) {
	unsigned i;
	short * out = data;
	float * in = _samples;
	for (i=0; i < fft_size; i++)
		*out++ = (short) (*in++ * 32768.0);
}

void fftw_float_to_int(int * data) {
	unsigned i;
	int * out = data;
	float * in = _samples;
	for (i=0; i < fft_size; i++)
		*out++ = (int) (*in++ * 32768.0);
}

/* block copy of spectrum to real magnitude buffer */

void fftw_mag_spectrum(float * data) {
	unsigned i;
	float * out = data;
	float * in = (float *) _spectrum;
	float re, im, sum;
	for (i=0; i < fft_size; i++) {
		re = *in++;
		im = *in++;
		*out++ = sqrt((re * re) + (im * im));
	}
}
