From 618ab3f0382bb61c54233913d2bfd3b379edba85 Mon Sep 17 00:00:00 2001 From: "andrew@webrtc.org" Date: Tue, 4 Sep 2012 23:39:05 +0000 Subject: [PATCH] Add a real FFT wrapper around the complex FFT. BUG=issue762 Review URL: https://webrtc-codereview.appspot.com/769004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2703 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../signal_processing/include/real_fft.h | 37 ++++++++ src/common_audio/signal_processing/real_fft.c | 42 +++++++++ .../signal_processing/real_fft_unittest.cc | 85 +++++++++++++++++++ .../signal_processing/signal_processing.gypi | 5 +- 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/common_audio/signal_processing/include/real_fft.h create mode 100644 src/common_audio/signal_processing/real_fft.c create mode 100644 src/common_audio/signal_processing/real_fft_unittest.cc diff --git a/src/common_audio/signal_processing/include/real_fft.h b/src/common_audio/signal_processing/include/real_fft.h new file mode 100644 index 000000000..129eb8c21 --- /dev/null +++ b/src/common_audio/signal_processing/include/real_fft.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ +#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ + +#include "typedefs.h" + +struct RealFFT; + +#ifdef __cplusplus +extern "C" { +#endif + +// TODO(andrew): documentation. +struct RealFFT* WebRtcSpl_CreateRealFFT(int order); +void WebRtcSpl_FreeRealFFT(struct RealFFT* self); + +// TODO(andrew): This currently functions exactly the same as ComplexFFT(). +// Manage the surrounding operations (ComplexBitReverse etc) here instead. +// +// data must be of length 2^(order + 1) to hold the complex output. +int WebRtcSpl_RealForwardFFT(struct RealFFT* self, int16_t* data); +int WebRtcSpl_RealInverseFFT(struct RealFFT* self, int16_t* data); + +#ifdef __cplusplus +} +#endif + +#endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ diff --git a/src/common_audio/signal_processing/real_fft.c b/src/common_audio/signal_processing/real_fft.c new file mode 100644 index 000000000..e87654e1d --- /dev/null +++ b/src/common_audio/signal_processing/real_fft.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/real_fft.h" + +#include + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +struct RealFFT { + int order; +}; + +struct RealFFT* WebRtcSpl_CreateRealFFT(int order) { + struct RealFFT* self = NULL; + // This constraint comes from ComplexFFT(). + if (order > 10 || order < 0) { + return NULL; + } + self = malloc(sizeof(struct RealFFT)); + self->order = order; + return self; +} + +void WebRtcSpl_FreeRealFFT(struct RealFFT* self) { + free(self); +} + +int WebRtcSpl_RealForwardFFT(struct RealFFT* self, int16_t* data) { + return WebRtcSpl_ComplexFFT(data, self->order, 1); +} + +int WebRtcSpl_RealInverseFFT(struct RealFFT* self, int16_t* data) { + return WebRtcSpl_ComplexIFFT(data, self->order, 1); +} diff --git a/src/common_audio/signal_processing/real_fft_unittest.cc b/src/common_audio/signal_processing/real_fft_unittest.cc new file mode 100644 index 000000000..dab0d1503 --- /dev/null +++ b/src/common_audio/signal_processing/real_fft_unittest.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/real_fft.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "typedefs.h" + +#include "gtest/gtest.h" + +namespace webrtc { +namespace { + +const int kOrder = 3; +const int kLength = 1 << (kOrder + 1); // +1 to hold complex data. +const int16_t kRefData[kLength] = { + 11739, -6848, -8688, 31980, -30295, 25242, 27085, 19410, -26299, -15607, + -10791, 11778, -23819, 14498, -25772, 10076 +}; + +class RealFFTTest : public ::testing::Test { +}; + +TEST_F(RealFFTTest, CreateFailsOnBadInput) { + RealFFT* fft = WebRtcSpl_CreateRealFFT(11); + EXPECT_TRUE(fft == NULL); + fft = WebRtcSpl_CreateRealFFT(-1); + EXPECT_TRUE(fft == NULL); +} + +// TODO(andrew): Look more into why this was failing. +TEST_F(RealFFTTest, DISABLED_TransformIsInvertible) { + int16_t data[kLength] = {0}; + memcpy(data, kRefData, sizeof(kRefData)); + + RealFFT* fft = NULL; + fft = WebRtcSpl_CreateRealFFT(kOrder); + EXPECT_TRUE(fft != NULL); + + EXPECT_EQ(0, WebRtcSpl_RealForwardFFT(fft, data)); + int scale = WebRtcSpl_RealInverseFFT(fft, data); + + EXPECT_GE(scale, 0); + for (int i = 0; i < kLength; i++) { + EXPECT_EQ(data[i] << scale, kRefData[i]); + } + WebRtcSpl_FreeRealFFT(fft); +} + +// TODO(andrew): This won't always be the case, but verifies the current code +// at least. +TEST_F(RealFFTTest, RealAndComplexAreIdentical) { + int16_t real_data[kLength] = {0}; + int16_t complex_data[kLength] = {0}; + memcpy(real_data, kRefData, sizeof(kRefData)); + memcpy(complex_data, kRefData, sizeof(kRefData)); + + RealFFT* fft = NULL; + fft = WebRtcSpl_CreateRealFFT(kOrder); + EXPECT_TRUE(fft != NULL); + + EXPECT_EQ(0, WebRtcSpl_RealForwardFFT(fft, real_data)); + EXPECT_EQ(0, WebRtcSpl_ComplexFFT(complex_data, kOrder, 1)); + for (int i = 0; i < kLength; i++) { + EXPECT_EQ(real_data[i], complex_data[i]); + } + + int real_scale = WebRtcSpl_RealInverseFFT(fft, real_data); + int complex_scale = WebRtcSpl_ComplexIFFT(complex_data, kOrder, 1); + EXPECT_GE(real_scale, 0); + EXPECT_EQ(real_scale, complex_scale); + for (int i = 0; i < kLength; i++) { + EXPECT_EQ(real_data[i], complex_data[i]); + } + WebRtcSpl_FreeRealFFT(fft); +} + +} // namespace +} // namespace webrtc diff --git a/src/common_audio/signal_processing/signal_processing.gypi b/src/common_audio/signal_processing/signal_processing.gypi index 83d2380ad..9d6a977c4 100644 --- a/src/common_audio/signal_processing/signal_processing.gypi +++ b/src/common_audio/signal_processing/signal_processing.gypi @@ -20,6 +20,7 @@ ], }, 'sources': [ + 'include/real_fft.h', 'include/signal_processing_library.h', 'include/spl_inl.h', 'auto_corr_to_refl_coef.c', @@ -43,6 +44,7 @@ 'min_max_operations.c', 'randomization_functions.c', 'refl_coef_to_lpc.c', + 'real_fft.c', 'resample.c', 'resample_48khz.c', 'resample_by_2.c', @@ -100,10 +102,11 @@ 'type': 'executable', 'dependencies': [ 'signal_processing', - '<(webrtc_root)/test/test.gyp:test_support_main', '<(DEPTH)/testing/gtest.gyp:gtest', + '<(webrtc_root)/test/test.gyp:test_support_main', ], 'sources': [ + 'real_fft_unittest.cc', 'signal_processing_unittest.cc', ], }, # spl_unittests