diff options
author | Chris Robinson <[email protected]> | 2018-11-17 04:14:57 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2018-11-17 04:14:57 -0800 |
commit | ccdaca80c910047e16f710d44f640a6d6f86a195 (patch) | |
tree | 0cf95ed7a5fd6478c01cea8bd8e9c521478ccf0d /common | |
parent | 09943683b5872943cd1f9211ef2a77922906b906 (diff) |
Use standard complex types instead of custom
Diffstat (limited to 'common')
-rw-r--r-- | common/alcomplex.c | 122 | ||||
-rw-r--r-- | common/alcomplex.cpp | 76 | ||||
-rw-r--r-- | common/alcomplex.h | 20 |
3 files changed, 79 insertions, 139 deletions
diff --git a/common/alcomplex.c b/common/alcomplex.c deleted file mode 100644 index 851f4105..00000000 --- a/common/alcomplex.c +++ /dev/null @@ -1,122 +0,0 @@ - -#include "config.h" - -#include "alcomplex.h" -#include "math_defs.h" - - -/** Addition of two complex numbers. */ -static inline ALcomplex complex_add(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real + b.Real; - result.Imag = a.Imag + b.Imag; - - return result; -} - -/** Subtraction of two complex numbers. */ -static inline ALcomplex complex_sub(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real - b.Real; - result.Imag = a.Imag - b.Imag; - - return result; -} - -/** Multiplication of two complex numbers. */ -static inline ALcomplex complex_mult(ALcomplex a, ALcomplex b) -{ - ALcomplex result; - - result.Real = a.Real*b.Real - a.Imag*b.Imag; - result.Imag = a.Imag*b.Real + a.Real*b.Imag; - - return result; -} - - -void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign) -{ - ALsizei i, j, k, mask, step, step2; - ALcomplex temp, u, w; - ALdouble arg; - - /* Bit-reversal permutation applied to a sequence of FFTSize items */ - for(i = 1;i < FFTSize-1;i++) - { - for(mask = 0x1, j = 0;mask < FFTSize;mask <<= 1) - { - if((i&mask) != 0) - j++; - j <<= 1; - } - j >>= 1; - - if(i < j) - { - temp = FFTBuffer[i]; - FFTBuffer[i] = FFTBuffer[j]; - FFTBuffer[j] = temp; - } - } - - /* Iterative form of Danielson–Lanczos lemma */ - for(i = 1, step = 2;i < FFTSize;i<<=1, step<<=1) - { - step2 = step >> 1; - arg = M_PI / step2; - - w.Real = cos(arg); - w.Imag = sin(arg) * Sign; - - u.Real = 1.0; - u.Imag = 0.0; - - for(j = 0;j < step2;j++) - { - for(k = j;k < FFTSize;k+=step) - { - temp = complex_mult(FFTBuffer[k+step2], u); - FFTBuffer[k+step2] = complex_sub(FFTBuffer[k], temp); - FFTBuffer[k] = complex_add(FFTBuffer[k], temp); - } - - u = complex_mult(u, w); - } - } -} - -void complex_hilbert(ALcomplex *Buffer, ALsizei size) -{ - const ALdouble inverse_size = 1.0/(ALdouble)size; - ALsizei todo, i; - - for(i = 0;i < size;i++) - Buffer[i].Imag = 0.0; - - complex_fft(Buffer, size, 1.0); - - todo = size >> 1; - Buffer[0].Real *= inverse_size; - Buffer[0].Imag *= inverse_size; - for(i = 1;i < todo;i++) - { - Buffer[i].Real *= 2.0*inverse_size; - Buffer[i].Imag *= 2.0*inverse_size; - } - Buffer[i].Real *= inverse_size; - Buffer[i].Imag *= inverse_size; - i++; - - for(;i < size;i++) - { - Buffer[i].Real = 0.0; - Buffer[i].Imag = 0.0; - } - - complex_fft(Buffer, size, -1.0); -} diff --git a/common/alcomplex.cpp b/common/alcomplex.cpp new file mode 100644 index 00000000..de2d1be9 --- /dev/null +++ b/common/alcomplex.cpp @@ -0,0 +1,76 @@ + +#include "config.h" + +#include "alcomplex.h" + +#include <cmath> + +namespace { + +constexpr double Pi{3.141592653589793238462643383279502884}; + +} // namespace + +void complex_fft(std::complex<double> *FFTBuffer, int FFTSize, double Sign) +{ + /* Bit-reversal permutation applied to a sequence of FFTSize items */ + for(int i{1};i < FFTSize-1;i++) + { + int j{0}; + for(int mask{1};mask < FFTSize;mask <<= 1) + { + if((i&mask) != 0) + j++; + j <<= 1; + } + j >>= 1; + + if(i < j) + std::swap(FFTBuffer[i], FFTBuffer[j]); + } + + /* Iterative form of Danielson–Lanczos lemma */ + int step{2}; + for(int i{1};i < FFTSize;i<<=1, step<<=1) + { + int step2{step >> 1}; + double arg{Pi / step2}; + + std::complex<double> w{std::cos(arg), std::sin(arg)*Sign}; + std::complex<double> u{1.0, 0.0}; + for(int j{0};j < step2;j++) + { + for(int k{j};k < FFTSize;k+=step) + { + std::complex<double> temp{FFTBuffer[k+step2] * u}; + FFTBuffer[k+step2] = FFTBuffer[k] - temp; + FFTBuffer[k] += temp; + } + + u *= w; + } + } +} + +void complex_hilbert(std::complex<double> *Buffer, int size) +{ + const double inverse_size = 1.0/(double)size; + + for(int i{0};i < size;i++) + Buffer[i].imag(0.0); + + complex_fft(Buffer, size, 1.0); + + int todo{size>>1}; + int i{0}; + + Buffer[i++] *= inverse_size; + while(i < todo) + Buffer[i++] *= 2.0*inverse_size; + Buffer[i++] *= inverse_size; + + for(;i < size;i++) + Buffer[i] = std::complex<double>{}; + + complex_fft(Buffer, size, -1.0); +} diff --git a/common/alcomplex.h b/common/alcomplex.h index 0070ac13..554886c4 100644 --- a/common/alcomplex.h +++ b/common/alcomplex.h @@ -1,17 +1,7 @@ #ifndef ALCOMPLEX_H #define ALCOMPLEX_H -#include "AL/al.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ALcomplex { - ALdouble Real; - ALdouble Imag; -} ALcomplex; +#include <complex> /** * Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is @@ -20,7 +10,7 @@ typedef struct ALcomplex { * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers, FFTSize * MUST BE power of two. */ -void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); +void complex_fft(std::complex<double> *FFTBuffer, int FFTSize, double Sign); /** * Calculate the complex helical sequence (discrete-time analytical signal) of @@ -29,10 +19,6 @@ void complex_fft(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign); * Buffer[0...size-1]. Buffer is an array of complex numbers, size MUST BE * power of two. */ -void complex_hilbert(ALcomplex *Buffer, ALsizei size); - -#ifdef __cplusplus -} // extern "C" -#endif +void complex_hilbert(std::complex<double> *Buffer, int size); #endif /* ALCOMPLEX_H */ |