aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2018-05-15 18:31:41 -0700
committerChris Robinson <[email protected]>2018-05-15 18:31:41 -0700
commit2b9064cb6e4ec08b00619f5d61fd81d2a4f2c4f2 (patch)
treeb6b8f6643f7ee9db3fe13797e4aa27c606ea4427
parent197e88cdcc62ac1c9e8be2240c52c4f108ac27b6 (diff)
Move the ALcomplex and FFT functions to a separate file
-rw-r--r--Alc/effects/pshifter.c107
-rw-r--r--CMakeLists.txt2
-rw-r--r--common/alcomplex.c62
-rw-r--r--common/alcomplex.h62
4 files changed, 134 insertions, 99 deletions
diff --git a/Alc/effects/pshifter.c b/Alc/effects/pshifter.c
index 9c2bb2e9..f27c413c 100644
--- a/Alc/effects/pshifter.c
+++ b/Alc/effects/pshifter.c
@@ -29,6 +29,8 @@
#include "alu.h"
#include "filters/defs.h"
+#include "alcomplex.h"
+
#define STFT_SIZE 1024
#define STFT_HALF_SIZE (STFT_SIZE>>1)
@@ -37,10 +39,6 @@
#define STFT_STEP (STFT_SIZE / OVERSAMP)
#define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1))
-typedef struct ALcomplex {
- ALdouble Real;
- ALdouble Imag;
-} ALcomplex;
typedef struct ALphasor {
ALdouble Amplitude;
@@ -52,6 +50,7 @@ typedef struct ALFrequencyDomain {
ALdouble Frequency;
} ALfrequencyDomain;
+
typedef struct ALpshifterState {
DERIVE_FROM_TYPE(ALeffectState);
@@ -149,7 +148,7 @@ static inline ALphasor rect2polar(ALcomplex number)
}
/* Converts ALphasor to ALcomplex */
-static inline ALcomplex polar2rect(ALphasor number)
+static inline ALcomplex polar2rect(ALphasor number)
{
ALcomplex cartesian;
@@ -159,96 +158,6 @@ static inline ALcomplex polar2rect(ALphasor number)
return cartesian;
}
-/* Addition of two complex numbers (ALcomplex format) */
-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 (ALcomplex format) */
-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 (ALcomplex format) */
-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;
-}
-
-/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is
- * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the
- * Discrete Fourier Transform (DFT) of the time domain data stored in
- * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers
- * (ALcomplex), FFTSize MUST BE power of two.
- */
-static inline ALvoid 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);
- }
- }
-}
-
static void ALpshifterState_Construct(ALpshifterState *state)
{
@@ -295,8 +204,8 @@ static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *c
pitch = powf(2.0f,
(ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f
);
- state->PitchShiftI = (ALsizei)(pitch*FRACTIONONE + 0.5f);
- state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE);
+ state->PitchShiftI = fastf2i(pitch*FRACTIONONE);
+ state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE);
CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains);
@@ -337,7 +246,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD
/* ANALYSIS */
/* Apply FFT to FFTbuffer data */
- FFT(state->FFTbuffer, STFT_SIZE, -1.0);
+ complex_fft(state->FFTbuffer, STFT_SIZE, -1.0);
/* Analyze the obtained data. Since the real FFT is symmetric, only
* STFT_HALF_SIZE+1 samples are needed.
@@ -417,7 +326,7 @@ static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToD
}
/* Apply iFFT to buffer data */
- FFT(state->FFTbuffer, STFT_SIZE, 1.0);
+ complex_fft(state->FFTbuffer, STFT_SIZE, 1.0);
/* Windowing and add to output */
for(k = 0;k < STFT_SIZE;k++)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a4f8ff4..cd3ecbed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -700,6 +700,8 @@ ENDIF()
SET(COMMON_OBJS
+ common/alcomplex.c
+ common/alcomplex.h
common/align.h
common/almalloc.c
common/almalloc.h
diff --git a/common/alcomplex.c b/common/alcomplex.c
new file mode 100644
index 00000000..c1a312e3
--- /dev/null
+++ b/common/alcomplex.c
@@ -0,0 +1,62 @@
+
+#include "config.h"
+
+#include "alcomplex.h"
+
+#include <math.h>
+
+
+extern inline ALcomplex complex_add(ALcomplex a, ALcomplex b);
+extern inline ALcomplex complex_sub(ALcomplex a, ALcomplex b);
+extern inline ALcomplex complex_mult(ALcomplex a, ALcomplex b);
+
+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);
+ }
+ }
+}
diff --git a/common/alcomplex.h b/common/alcomplex.h
new file mode 100644
index 00000000..cf4683fa
--- /dev/null
+++ b/common/alcomplex.h
@@ -0,0 +1,62 @@
+#ifndef ALCOMPLEX_H
+#define ALCOMPLEX_H
+
+#include "AL/al.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ALcomplex {
+ ALdouble Real;
+ ALdouble Imag;
+} ALcomplex;
+
+/** Addition of two complex numbers. */
+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. */
+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. */
+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;
+}
+
+/**
+ * Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is
+ * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the
+ * Discrete Fourier Transform (DFT) of the time domain data stored in
+ * 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);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* ALCOMPLEX_H */