1
#ifndef AUDIO_FFT_HPP_INCLUDED
2
#define AUDIO_FFT_HPP_INCLUDED
5
@file fft.hpp FFT and related facilities.
7
Header only, no need to link with libda.
17
/** Calculate the square of val. **/
18
static inline double sqr(double val) { return val * val; }
20
template <unsigned M, unsigned N, unsigned B, unsigned A> struct SinCosSeries {
21
static double value() {
22
return 1 - sqr(A * M_PI / B) / M / (M+1) * SinCosSeries<M + 2, N, B, A>::value();
25
template <unsigned N, unsigned B, unsigned A> struct SinCosSeries<N, N, B, A> {
26
static double value() { return 1.0; }
29
template <unsigned A, unsigned B> struct Sin {
30
static double value() { return (A * M_PI / B) * SinCosSeries<2, 34, B, A>::value(); }
33
template <unsigned A, unsigned B> struct Cos {
34
static double value() { return SinCosSeries<1, 33, B, A>::value(); }
37
/** Calculate sin(2 pi A / B). **/
38
template <unsigned A, unsigned B> double sin() { return Sin<A, B>::value(); }
40
/** Calculate cos(2 pi A / B). **/
41
template <unsigned A, unsigned B> double cos() { return Cos<A, B>::value(); }
45
// Based on the description of Volodymyr Myrnyy in
46
// http://www.dspdesignline.com/showArticle.jhtml?printableArticle=true&articleId=199903272
47
template<unsigned P, typename T> struct DanielsonLanczos {
48
static void apply(std::complex<T>* data) {
49
const std::size_t N = 1 << P;
50
const std::size_t M = N / 2;
51
// Compute even and odd halves
52
DanielsonLanczos<P - 1, T>().apply(data);
53
DanielsonLanczos<P - 1, T>().apply(data + M);
54
// Combine the results
57
const std::complex<T> wp(-2.0 * sqr(sin<1, N>()), -sin<2, N>());
58
std::complex<T> w(1.0);
59
for (std::size_t i = 0; i < M; ++i) {
60
std::complex<T> temp = data[i + M] * w;
61
data[M + i] = data[i] - temp;
68
template<typename T> struct DanielsonLanczos<0, T> { static void apply(std::complex<T>*) {} };
71
/** Perform FFT on data. **/
72
template<unsigned P, typename T> void fft(std::complex<T>* data) {
73
// Perform bit-reversal sorting of sample data.
74
const std::size_t N = 1 << P;
76
for (std::size_t i = 0; i < N; ++i) {
77
if (i < j) std::swap(data[i], data[j]);
78
std::size_t m = N / 2;
79
while (m > 1 && m <= j) { j -= m; m >>= 1; }
82
// Do the actual calculation
83
fourier::DanielsonLanczos<P, T>::apply(data);
86
/** Perform FFT on data from floating point iterator, windowing the input. **/
87
template<unsigned P, typename InIt, typename Window> std::vector<std::complex<float> > fft(InIt begin, Window window) {
88
std::vector<std::complex<float> > data(1 << P);
89
// Perform bit-reversal sorting of sample data.
90
const std::size_t N = 1 << P;
92
for (std::size_t i = 0; i < N; ++i) {
93
data[j] = *begin++ * window[i];
94
std::size_t m = N / 2;
95
while (m > 1 && m <= j) { j -= m; m >>= 1; }
98
// Do the actual calculation
99
fourier::DanielsonLanczos<P, float>::apply(&data[0]);