diff options
Diffstat (limited to 'src/audio/fft.cc')
| -rw-r--r-- | src/audio/fft.cc | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/src/audio/fft.cc b/src/audio/fft.cc index 64d7b1a..6029454 100644 --- a/src/audio/fft.cc +++ b/src/audio/fft.cc @@ -140,6 +140,49 @@ void dct_fft(const float* input, float* output, size_t N) { delete[] imag; } +// IMDCT via FFT +// Produces 2N time-domain samples from N MDCT coefficients. +// Formula: x[n] = (2/N) * sum_{k=0}^{N-1} X[k] * cos(pi*(2n+1+N)*(2k+1)/(2N)) +// When windowed (Hann, length 2N) and OLA'd with hop N, gives perfect reconstruction. +void imdct_fft(const float* input, float* output, size_t N) { + const float PI = 3.14159265358979323846f; + const size_t M = 2 * N; // output length + + float* real = new float[M]; + float* imag = new float[M]; + + // Pre-multiply X[k] by exp(-j*pi*(2k+1)/(4N)), build 2N complex FFT input + // via standard IMDCT-via-FFT algorithm (N-point complex FFT) + for (size_t k = 0; k < N; k++) { + const float angle = -PI * (2.0f * k + 1.0f) / (4.0f * N); + real[k] = input[k] * cosf(angle); + imag[k] = input[k] * sinf(angle); + } + for (size_t k = N; k < M; k++) { + real[k] = 0.0f; + imag[k] = 0.0f; + } + + // Inverse FFT of length 2N + bit_reverse_permute(real, imag, M); + fft_radix2(real, imag, M, -1); + const float scale = 1.0f / (float)M; + for (size_t i = 0; i < M; i++) { + real[i] *= scale; + imag[i] *= scale; + } + + // Post-multiply by 2N * exp(-j*pi*(2n+1)/(4N)) and take real part, scale by 2/N + const float gain = 2.0f; + for (size_t n = 0; n < M; n++) { + const float angle = -PI * (2.0f * n + 1.0f) / (4.0f * N); + output[n] = gain * (real[n] * cosf(angle) - imag[n] * sinf(angle)); + } + + delete[] real; + delete[] imag; +} + // IDCT (DCT-III) via FFT - inverse of the DCT-II reordering method // Reference: Numerical Recipes Chapter 12.3, Press et al. void idct_fft(const float* input, float* output, size_t N) { |
