unit tdkfft;
{
Simple Cooley-Tukey (Gaussian) FFT/IFFT + scaling
Fast enough for display buffers (256/512/1024/2048
Also fast enough for audio processing if the buffers aren't too big.
Simpler than the other options but very lightweight.
All arrays must be N = a power of two
Have fun,
Thaddy
}{$mode objfpc}
interface
type
// adjust here
fft_t = double;
TComplex = record
Re, Im: fft_t;
end;
TComplexArray = array of TComplex;
// helpers
function Complex(const Re, Im: fft_t): TComplex;inline;
operator + (const a, b: TComplex): TComplex;inline;
operator - (const a, b: TComplex): TComplex;inline;
operator * (const a, b: TComplex): TComplex;inline;
function Scale(const a: TComplex; s: fft_t): TComplex;inline;
//FFT IFFT
procedure FFT(var Data: TComplexArray; N: Integer; Inverse: Boolean);inline;
implementation
function Complex(const Re, Im: fft_t): TComplex;inline;
begin
Result.Re := Re;
Result.Im := Im;
end;
operator + (const a, b: TComplex): TComplex;inline;
begin
Result.Re := a.Re + b.Re;
Result.Im := a.Im + b.Im;
end;
operator - (const a, b: TComplex): TComplex;inline;
begin
Result.Re := a.Re - b.Re;
Result.Im := a.Im - b.Im;
end;
operator * (const a, b: TComplex): TComplex;inline;
begin
Result.Re := a.Re * b.Re - a.Im * b.Im;
Result.Im := a.Re * b.Im + a.Im * b.Re;
end;
function Scale(const a: TComplex; s: fft_t): TComplex;inline;
begin
Result.Re := a.Re * s;
Result.Im := a.Im * s;
end;
procedure FFT(var Data: TComplexArray; N: Integer; Inverse: Boolean);inline;
var
i, j, k, m: Integer;
theta: Double;
w, wp, temp: TComplex;
begin
if N <= 1 then Exit;
// Bit-reversal permutation
j := 0;
for i := 0 to N - 1 do
begin
if j > i then
begin
temp := Data[i];
Data[i] := Data[j];
Data[j] := temp;
end;
m := N div 2;
while (m >= 1) and (j >= m) do
begin
j := j - m;
m := m div 2;
end;
j := j + m;
end;
// Cooley-Tukey FFT
m := 1;
while m < N do
begin
theta := Pi / m;
if Inverse then theta := -theta;
wp := Complex(Cos(theta), Sin(theta)); // Correct twiddle factor
w := Complex(1.0, 0.0);
for k := 0 to m - 1 do
begin
i := k;
while i < N do
begin
j := i + m;
temp := w * Data[j];
Data[j] := Data[i] - temp;
Data[i] := Data[i] + temp;
i := i + 2 * m;
end;
w := w * wp;
end;
m := m * 2;
end;
// Scale the result for IFFT
if Inverse then
for i := 0 to N - 1 do
Data[i] := Scale(Data[i], 1.0 / N);
end;
end.