From 04c50981f8574b4ef3f8751ac37d0eb50a569a2b Mon Sep 17 00:00:00 2001 From: "andrew@webrtc.org" Date: Thu, 19 Mar 2015 20:06:29 +0000 Subject: [PATCH] Add the Ooura FFT to RealFourier. We are using the Ooura FFT in a few places: - AGC - Transient suppression - Noise suppression The optimized OpenMAX DL FFT is considerably faster, but currently does not compile everywhere, notably on iOS. This change will allow us to use Openmax when possible and otherwise fall back to Ooura. (Unfortunately, noise suppression won't be able to take advantage of it since it's not C++. Upgrade time?) R=aluebs@webrtc.org, mgraczyk@chromium.org Review URL: https://webrtc-codereview.appspot.com/45789004 Cr-Commit-Position: refs/heads/master@{#8798} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8798 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/LICENSE_THIRD_PARTY | 20 +---- webrtc/common_audio/BUILD.gn | 21 +++-- webrtc/common_audio/common_audio.gyp | 26 +++--- .../utility => common_audio}/fft4g.c | 0 .../utility => common_audio}/fft4g.h | 19 ++-- webrtc/common_audio/lapped_transform.cc | 13 +-- webrtc/common_audio/lapped_transform.h | 2 +- webrtc/common_audio/real_fourier.cc | 64 ++++---------- webrtc/common_audio/real_fourier.h | 35 +++----- webrtc/common_audio/real_fourier_ooura.cc | 85 ++++++++++++++++++ webrtc/common_audio/real_fourier_ooura.h | 45 ++++++++++ webrtc/common_audio/real_fourier_openmax.cc | 69 +++++++++++++++ webrtc/common_audio/real_fourier_openmax.h | 44 ++++++++++ webrtc/common_audio/real_fourier_unittest.cc | 87 ++++++++++--------- webrtc/modules/audio_processing/BUILD.gn | 2 - .../audio_processing/agc/agc_audio_proc.cc | 2 +- .../audio_processing/audio_processing.gypi | 2 - webrtc/modules/audio_processing/ns/ns_core.c | 2 +- .../transient/transient_suppressor.cc | 8 +- 19 files changed, 378 insertions(+), 168 deletions(-) rename webrtc/{modules/audio_processing/utility => common_audio}/fft4g.c (100%) rename webrtc/{modules/audio_processing/utility => common_audio}/fft4g.h (54%) create mode 100644 webrtc/common_audio/real_fourier_ooura.cc create mode 100644 webrtc/common_audio/real_fourier_ooura.h create mode 100644 webrtc/common_audio/real_fourier_openmax.cc create mode 100644 webrtc/common_audio/real_fourier_openmax.h diff --git a/webrtc/LICENSE_THIRD_PARTY b/webrtc/LICENSE_THIRD_PARTY index bd47730c3a..b64dbbab46 100644 --- a/webrtc/LICENSE_THIRD_PARTY +++ b/webrtc/LICENSE_THIRD_PARTY @@ -2,6 +2,7 @@ This source tree contains third party source code which is governed by third party licenses. Paths to the files and associated licenses are collected here. Files governed by third party licenses: +common_audio/fft4g.c common_audio/signal_processing/spl_sqrt_floor.c common_audio/signal_processing/spl_sqrt_floor_arm.S modules/audio_coding/codecs/g711/main/source/g711.c @@ -14,8 +15,6 @@ modules/audio_device/mac/portaudio/pa_memorybarrier.h modules/audio_device/mac/portaudio/pa_ringbuffer.c modules/audio_device/mac/portaudio/pa_ringbuffer.h modules/audio_processing/aec/aec_rdft.c -modules/audio_processing/utility/fft4g.c -base/scoped_ptr.h system_wrappers/source/condition_variable_event_win.cc system_wrappers/source/set_thread_name_win.h system_wrappers/source/spreadsortlib/constants.hpp @@ -231,8 +230,8 @@ License: */ ------------------------------------------------------------------------------- Files: +common_audio/fft4g.c modules/audio_processing/aec/aec_rdft.c -modules/audio_processing/utility/fft4g.c License: /* @@ -245,21 +244,6 @@ License: */ ------------------------------------------------------------------------------- Files: -base/scoped_ptr.h - -License: -// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. -// Copyright (c) 2001, 2002 Peter Dimov -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. -// -------------------------------------------------------------------------------- -Files: system_wrappers/source/condition_variable_event_win.cc Source: diff --git a/webrtc/common_audio/BUILD.gn b/webrtc/common_audio/BUILD.gn index c9c3c5b9b3..34e1575b24 100644 --- a/webrtc/common_audio/BUILD.gn +++ b/webrtc/common_audio/BUILD.gn @@ -19,8 +19,6 @@ config("common_audio_config") { source_set("common_audio") { sources = [ - "channel_buffer.cc", - "channel_buffer.h", "audio_converter.cc", "audio_converter.h", "audio_ring_buffer.cc", @@ -28,11 +26,21 @@ source_set("common_audio") { "audio_util.cc", "blocker.cc", "blocker.h", + "channel_buffer.cc", + "channel_buffer.h", + "fft4g.c", + "fft4g.h", "fir_filter.cc", "fir_filter.h", "fir_filter_neon.h", "fir_filter_sse.h", "include/audio_util.h", + "lapped_transform.cc", + "lapped_transform.h", + "real_fourier.cc", + "real_fourier.h", + "real_fourier_ooura.cc", + "real_fourier_ooura.h", "resampler/include/push_resampler.h", "resampler/include/resampler.h", "resampler/push_resampler.cc", @@ -99,14 +107,13 @@ source_set("common_audio") { deps = [ "../system_wrappers" ] + defines = [] if (rtc_use_openmax_dl) { sources += [ - "lapped_transform.cc", - "lapped_transform.h", - "real_fourier.cc", - "real_fourier.h", + "real_fourier_openmax.cc", + "real_fourier_openmax.h", ] - + defines += [ "RTC_USE_OPENMAX_DL" ] deps += [ "//third_party/openmax_dl/dl" ] } diff --git a/webrtc/common_audio/common_audio.gyp b/webrtc/common_audio/common_audio.gyp index 3ea336c202..e28f4b03ff 100644 --- a/webrtc/common_audio/common_audio.gyp +++ b/webrtc/common_audio/common_audio.gyp @@ -29,8 +29,6 @@ ], }, 'sources': [ - 'channel_buffer.cc', - 'channel_buffer.h', 'audio_converter.cc', 'audio_converter.h', 'audio_ring_buffer.cc', @@ -38,11 +36,21 @@ 'audio_util.cc', 'blocker.cc', 'blocker.h', + 'channel_buffer.cc', + 'channel_buffer.h', + 'fft4g.c', + 'fft4g.h', 'fir_filter.cc', 'fir_filter.h', 'fir_filter_neon.h', 'fir_filter_sse.h', 'include/audio_util.h', + 'lapped_transform.cc', + 'lapped_transform.h', + 'real_fourier.cc', + 'real_fourier.h', + 'real_fourier_ooura.cc', + 'real_fourier_ooura.h', 'resampler/include/push_resampler.h', 'resampler/include/resampler.h', 'resampler/push_resampler.cc', @@ -113,11 +121,10 @@ 'conditions': [ ['rtc_use_openmax_dl==1', { 'sources': [ - 'lapped_transform.cc', - 'lapped_transform.h', - 'real_fourier.cc', - 'real_fourier.h', + 'real_fourier_openmax.cc', + 'real_fourier_openmax.h', ], + 'defines': ['RTC_USE_OPENMAX_DL',], 'conditions': [ ['build_openmax_dl==1', { 'dependencies': ['<(DEPTH)/third_party/openmax_dl/dl/dl.gyp:openmax_dl',], @@ -241,6 +248,8 @@ 'audio_util_unittest.cc', 'blocker_unittest.cc', 'fir_filter_unittest.cc', + 'lapped_transform_unittest.cc', + 'real_fourier_unittest.cc', 'resampler/resampler_unittest.cc', 'resampler/push_resampler_unittest.cc', 'resampler/push_sinc_resampler_unittest.cc', @@ -262,10 +271,7 @@ ], 'conditions': [ ['rtc_use_openmax_dl==1', { - 'sources': [ - 'lapped_transform_unittest.cc', - 'real_fourier_unittest.cc', - ], + 'defines': ['RTC_USE_OPENMAX_DL',], }], ['OS=="android"', { 'dependencies': [ diff --git a/webrtc/modules/audio_processing/utility/fft4g.c b/webrtc/common_audio/fft4g.c similarity index 100% rename from webrtc/modules/audio_processing/utility/fft4g.c rename to webrtc/common_audio/fft4g.c diff --git a/webrtc/modules/audio_processing/utility/fft4g.h b/webrtc/common_audio/fft4g.h similarity index 54% rename from webrtc/modules/audio_processing/utility/fft4g.h rename to webrtc/common_audio/fft4g.h index 14a52a106a..90fefa0207 100644 --- a/webrtc/modules/audio_processing/utility/fft4g.h +++ b/webrtc/common_audio/fft4g.h @@ -8,10 +8,19 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_FFT4G_H_ -#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_FFT4G_H_ - -void WebRtc_rdft(int, int, float *, int *, float *); -void WebRtc_cdft(int, int, float *, int *, float *); +#ifndef WEBRTC_COMMON_AUDIO_FFT4G_H_ +#define WEBRTC_COMMON_AUDIO_FFT4G_H_ +#if defined(__cplusplus) +extern "C" { #endif + +// Refer to fft4g.c for documentation. +void WebRtc_rdft(int n, int isgn, float *a, int *ip, float *w); +void WebRtc_cdft(int n, int isgn, float *a, int *ip, float *w); + +#if defined(__cplusplus) +} +#endif + +#endif // WEBRTC_COMMON_AUDIO_FFT4G_H_ diff --git a/webrtc/common_audio/lapped_transform.cc b/webrtc/common_audio/lapped_transform.cc index 6b4f135aff..3883582fc1 100644 --- a/webrtc/common_audio/lapped_transform.cc +++ b/webrtc/common_audio/lapped_transform.cc @@ -31,7 +31,8 @@ void LappedTransform::BlockThunk::ProcessBlock(const float* const* input, for (int i = 0; i < num_input_channels; ++i) { memcpy(parent_->real_buf_.Row(i), input[i], num_frames * sizeof(*input[0])); - parent_->fft_.Forward(parent_->real_buf_.Row(i), parent_->cplx_pre_.Row(i)); + parent_->fft_->Forward(parent_->real_buf_.Row(i), + parent_->cplx_pre_.Row(i)); } int block_length = RealFourier::ComplexLength( @@ -44,8 +45,8 @@ void LappedTransform::BlockThunk::ProcessBlock(const float* const* input, parent_->cplx_post_.Array()); for (int i = 0; i < num_output_channels; ++i) { - parent_->fft_.Inverse(parent_->cplx_post_.Row(i), - parent_->real_buf_.Row(i)); + parent_->fft_->Inverse(parent_->cplx_post_.Row(i), + parent_->real_buf_.Row(i)); memcpy(output[i], parent_->real_buf_.Row(i), num_frames * sizeof(*input[0])); } @@ -64,8 +65,8 @@ LappedTransform::LappedTransform(int in_channels, int out_channels, blocker_( chunk_length_, block_length_, in_channels_, out_channels_, window, shift_amount, &blocker_callback_), - fft_(RealFourier::FftOrder(block_length_)), - cplx_length_(RealFourier::ComplexLength(fft_.order())), + fft_(RealFourier::Create(RealFourier::FftOrder(block_length_))), + cplx_length_(RealFourier::ComplexLength(fft_->order())), real_buf_(in_channels, block_length_, RealFourier::kFftBufferAlignment), cplx_pre_(in_channels, cplx_length_, RealFourier::kFftBufferAlignment), cplx_post_(out_channels, cplx_length_, RealFourier::kFftBufferAlignment) { @@ -81,7 +82,7 @@ LappedTransform::LappedTransform(int in_channels, int out_channels, void LappedTransform::ProcessChunk(const float* const* in_chunk, float* const* out_chunk) { blocker_.ProcessChunk(in_chunk, chunk_length_, in_channels_, out_channels_, - out_chunk); + out_chunk); } } // namespace webrtc diff --git a/webrtc/common_audio/lapped_transform.h b/webrtc/common_audio/lapped_transform.h index f4124b843a..3ed9528de7 100644 --- a/webrtc/common_audio/lapped_transform.h +++ b/webrtc/common_audio/lapped_transform.h @@ -82,7 +82,7 @@ class LappedTransform { Callback* const block_processor_; Blocker blocker_; - RealFourier fft_; + rtc::scoped_ptr fft_; const int cplx_length_; AlignedArray real_buf_; AlignedArray > cplx_pre_; diff --git a/webrtc/common_audio/real_fourier.cc b/webrtc/common_audio/real_fourier.cc index 81fd45cb6b..dec2be6d60 100644 --- a/webrtc/common_audio/real_fourier.cc +++ b/webrtc/common_audio/real_fourier.cc @@ -10,54 +10,37 @@ #include "webrtc/common_audio/real_fourier.h" -#include - -#include "dl/sp/api/omxSP.h" #include "webrtc/base/checks.h" +#include "webrtc/common_audio/real_fourier_ooura.h" +#include "webrtc/common_audio/real_fourier_openmax.h" +#include "webrtc/common_audio/signal_processing/include/spl_inl.h" namespace webrtc { using std::complex; -// The omx implementation uses this macro to check order validity. -const int RealFourier::kMaxFftOrder = TWIDDLE_TABLE_ORDER; const int RealFourier::kFftBufferAlignment = 32; -RealFourier::RealFourier(int fft_order) - : order_(fft_order), - omx_spec_(nullptr) { - CHECK_GE(order_, 1); - CHECK_LE(order_, kMaxFftOrder); - - OMX_INT buffer_size; - OMXResult r; - - r = omxSP_FFTGetBufSize_R_F32(order_, &buffer_size); - CHECK_EQ(r, OMX_Sts_NoErr); - - omx_spec_ = malloc(buffer_size); - DCHECK(omx_spec_); - - r = omxSP_FFTInit_R_F32(omx_spec_, order_); - CHECK_EQ(r, OMX_Sts_NoErr); -} - -RealFourier::~RealFourier() { - free(omx_spec_); +rtc::scoped_ptr RealFourier::Create(int fft_order) { +#if defined(RTC_USE_OPENMAX_DL) + return rtc::scoped_ptr(new RealFourierOpenmax(fft_order)); +#else + return rtc::scoped_ptr(new RealFourierOoura(fft_order)); +#endif } int RealFourier::FftOrder(int length) { - for (int order = 0; order <= kMaxFftOrder; order++) { - if ((1 << order) >= length) { - return order; - } - } - return -1; + CHECK_GT(length, 0); + return WebRtcSpl_GetSizeInBits(length - 1); +} + +int RealFourier::FftLength(int order) { + CHECK_GE(order, 0); + return 1 << order; } int RealFourier::ComplexLength(int order) { - CHECK_LE(order, kMaxFftOrder); - CHECK_GT(order, 0); + CHECK_GE(order, 0); return (1 << order) / 2 + 1; } @@ -71,18 +54,5 @@ RealFourier::fft_cplx_scoper RealFourier::AllocCplxBuffer(int count) { AlignedMalloc(sizeof(complex) * count, kFftBufferAlignment))); } -void RealFourier::Forward(const float* src, complex* dest) const { - OMXResult r; - r = omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast(dest), omx_spec_); - CHECK_EQ(r, OMX_Sts_NoErr); -} - -void RealFourier::Inverse(const complex* src, float* dest) const { - OMXResult r; - r = omxSP_FFTInv_CCSToR_F32(reinterpret_cast(src), dest, - omx_spec_); - CHECK_EQ(r, OMX_Sts_NoErr); -} - } // namespace webrtc diff --git a/webrtc/common_audio/real_fourier.h b/webrtc/common_audio/real_fourier.h index eda3ba3b16..cc49dbf379 100644 --- a/webrtc/common_audio/real_fourier.h +++ b/webrtc/common_audio/real_fourier.h @@ -29,24 +29,23 @@ class RealFourier { typedef rtc::scoped_ptr[], AlignedFreeDeleter> fft_cplx_scoper; - // The maximum input order supported by this implementation. - static const int kMaxFftOrder; - // The alignment required for all input and output buffers, in bytes. static const int kFftBufferAlignment; // Construct a wrapper instance for the given input order, which must be // between 1 and kMaxFftOrder, inclusively. - explicit RealFourier(int fft_order); - ~RealFourier(); + static rtc::scoped_ptr Create(int fft_order); + virtual ~RealFourier() {}; - // Short helper to compute the smallest FFT order (a power of 2) which will - // contain the given input length. Returns -1 if the order would have been - // too big for the implementation. + // Helper to compute the smallest FFT order (a power of 2) which will contain + // the given input length. static int FftOrder(int length); - // Short helper to compute the exact length, in complex floats, of the - // transform output (i.e. |2^order / 2 + 1|). + // Helper to compute the input length from the FFT order. + static int FftLength(int order); + + // Helper to compute the exact length, in complex floats, of the transform + // output (i.e. |2^order / 2 + 1|). static int ComplexLength(int order); // Buffer allocation helpers. The buffers are large enough to hold |count| @@ -61,23 +60,13 @@ class RealFourier { // returned. Input and output must be properly aligned (e.g. through // AllocRealBuffer and AllocCplxBuffer) and input length must be // |2^order| (same as given at construction time). - void Forward(const float* src, std::complex* dest) const; + virtual void Forward(const float* src, std::complex* dest) const = 0; // Inverse transform. Same input format as output above, conjugate pairs // not needed. - void Inverse(const std::complex* src, float* dest) const; + virtual void Inverse(const std::complex* src, float* dest) const = 0; - int order() const { - return order_; - } - - private: - // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the - // dependency on openmax. - typedef void OMXFFTSpec_R_F32_; - const int order_; - - OMXFFTSpec_R_F32_* omx_spec_; + virtual int order() const = 0; }; } // namespace webrtc diff --git a/webrtc/common_audio/real_fourier_ooura.cc b/webrtc/common_audio/real_fourier_ooura.cc new file mode 100644 index 0000000000..6f76516432 --- /dev/null +++ b/webrtc/common_audio/real_fourier_ooura.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 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 "webrtc/common_audio/real_fourier_ooura.h" + +#include +#include + +#include "webrtc/base/checks.h" +#include "webrtc/common_audio/fft4g.h" + +namespace webrtc { + +using std::complex; + +namespace { + +void Conjugate(complex* array, int complex_length) { + std::for_each(array, array + complex_length, + [=](complex& v) { v = std::conj(v); }); +} + +size_t ComputeWorkIpSize(int fft_length) { + return static_cast(2 + std::ceil(std::sqrt( + static_cast(fft_length)))); +} + +} // namespace + +RealFourierOoura::RealFourierOoura(int fft_order) + : order_(fft_order), + length_(FftLength(order_)), + complex_length_(ComplexLength(order_)), + // Zero-initializing work_ip_ will cause rdft to initialize these work + // arrays on the first call. + work_ip_(new int[ComputeWorkIpSize(length_)]()), + work_w_(new float[complex_length_]()) { + CHECK_GE(fft_order, 1); +} + +void RealFourierOoura::Forward(const float* src, complex* dest) const { + { + // This cast is well-defined since C++11. See "Non-static data members" at: + // http://en.cppreference.com/w/cpp/numeric/complex + auto dest_float = reinterpret_cast(dest); + std::copy(src, src + length_, dest_float); + WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get()); + } + + // Ooura places real[n/2] in imag[0]. + dest[complex_length_ - 1] = complex(dest[0].imag(), 0.0f); + dest[0] = complex(dest[0].real(), 0.0f); + // Ooura returns the conjugate of the usual Fourier definition. + Conjugate(dest, complex_length_); +} + +void RealFourierOoura::Inverse(const complex* src, float* dest) const { + { + auto dest_complex = reinterpret_cast*>(dest); + // The real output array is shorter than the input complex array by one + // complex element. + const int dest_complex_length = complex_length_ - 1; + std::copy(src, src + dest_complex_length, dest_complex); + // Restore Ooura's conjugate definition. + Conjugate(dest_complex, dest_complex_length); + // Restore real[n/2] to imag[0]. + dest_complex[0] = complex(dest_complex[0].real(), + src[complex_length_ - 1].real()); + } + + WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get()); + + // Ooura returns a scaled version. + const float scale = 2.0f / length_; + std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; }); +} + +} // namespace webrtc diff --git a/webrtc/common_audio/real_fourier_ooura.h b/webrtc/common_audio/real_fourier_ooura.h new file mode 100644 index 0000000000..67b3ffd77b --- /dev/null +++ b/webrtc/common_audio/real_fourier_ooura.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 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_REAL_FOURIER_OOURA_H_ +#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_ + +#include + +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/common_audio/real_fourier.h" + +namespace webrtc { + +class RealFourierOoura : public RealFourier { + public: + explicit RealFourierOoura(int fft_order); + + void Forward(const float* src, std::complex* dest) const override; + void Inverse(const std::complex* src, float* dest) const override; + + int order() const override { + return order_; + } + + private: + const int order_; + const int length_; + const int complex_length_; + // These are work arrays for Ooura. The names are based on the comments in + // fft4g.c. + const rtc::scoped_ptr work_ip_; + const rtc::scoped_ptr work_w_; +}; + +} // namespace webrtc + +#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_ + diff --git a/webrtc/common_audio/real_fourier_openmax.cc b/webrtc/common_audio/real_fourier_openmax.cc new file mode 100644 index 0000000000..f7a0f64e03 --- /dev/null +++ b/webrtc/common_audio/real_fourier_openmax.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015 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 "webrtc/common_audio/real_fourier_openmax.h" + +#include + +#include "dl/sp/api/omxSP.h" +#include "webrtc/base/checks.h" + +namespace webrtc { + +using std::complex; + +namespace { + +// Creates and initializes the Openmax state. Transfers ownership to caller. +OMXFFTSpec_R_F32* CreateOpenmaxState(int order) { + CHECK_GE(order, 1); + // The omx implementation uses this macro to check order validity. + CHECK_LE(order, TWIDDLE_TABLE_ORDER); + + OMX_INT buffer_size; + OMXResult r = omxSP_FFTGetBufSize_R_F32(order, &buffer_size); + CHECK_EQ(r, OMX_Sts_NoErr); + + OMXFFTSpec_R_F32* omx_spec = malloc(buffer_size); + DCHECK(omx_spec); + + r = omxSP_FFTInit_R_F32(omx_spec, order); + CHECK_EQ(r, OMX_Sts_NoErr); + return omx_spec; +} + +} // namespace + +RealFourierOpenmax::RealFourierOpenmax(int fft_order) + : order_(fft_order), + omx_spec_(CreateOpenmaxState(order_)) { +} + +RealFourierOpenmax::~RealFourierOpenmax() { + free(omx_spec_); +} + +void RealFourierOpenmax::Forward(const float* src, complex* dest) const { + // This cast is well-defined since C++11. See "Non-static data members" at: + // http://en.cppreference.com/w/cpp/numeric/complex + OMXResult r = + omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast(dest), omx_spec_); + CHECK_EQ(r, OMX_Sts_NoErr); +} + +void RealFourierOpenmax::Inverse(const complex* src, float* dest) const { + OMXResult r = + omxSP_FFTInv_CCSToR_F32(reinterpret_cast(src), dest, + omx_spec_); + CHECK_EQ(r, OMX_Sts_NoErr); +} + +} // namespace webrtc + diff --git a/webrtc/common_audio/real_fourier_openmax.h b/webrtc/common_audio/real_fourier_openmax.h new file mode 100644 index 0000000000..63ce5ba0bc --- /dev/null +++ b/webrtc/common_audio/real_fourier_openmax.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 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_REAL_FOURIER_OPENMAX_H_ +#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ + +#include + +#include "webrtc/common_audio/real_fourier.h" + +namespace webrtc { + +class RealFourierOpenmax : public RealFourier { + public: + explicit RealFourierOpenmax(int fft_order); + ~RealFourierOpenmax() override; + + void Forward(const float* src, std::complex* dest) const override; + void Inverse(const std::complex* src, float* dest) const override; + + int order() const override { + return order_; + } + + private: + // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the + // dependency on openmax. + typedef void OMXFFTSpec_R_F32_; + const int order_; + + OMXFFTSpec_R_F32_* const omx_spec_; +}; + +} // namespace webrtc + +#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ + diff --git a/webrtc/common_audio/real_fourier_unittest.cc b/webrtc/common_audio/real_fourier_unittest.cc index 8660d4d72b..a66344187e 100644 --- a/webrtc/common_audio/real_fourier_unittest.cc +++ b/webrtc/common_audio/real_fourier_unittest.cc @@ -13,6 +13,9 @@ #include #include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/common_audio/real_fourier_openmax.h" +#include "webrtc/common_audio/real_fourier_ooura.h" namespace webrtc { @@ -24,81 +27,83 @@ TEST(RealFourierStaticsTest, AllocatorAlignment) { real = RealFourier::AllocRealBuffer(3); ASSERT_TRUE(real.get() != nullptr); int64_t ptr_value = reinterpret_cast(real.get()); - ASSERT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0); + EXPECT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0); } { RealFourier::fft_cplx_scoper cplx; cplx = RealFourier::AllocCplxBuffer(3); ASSERT_TRUE(cplx.get() != nullptr); int64_t ptr_value = reinterpret_cast(cplx.get()); - ASSERT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0); + EXPECT_EQ(ptr_value % RealFourier::kFftBufferAlignment, 0); } } TEST(RealFourierStaticsTest, OrderComputation) { - ASSERT_EQ(RealFourier::FftOrder(2000000), -1); - ASSERT_EQ(RealFourier::FftOrder((1 << RealFourier::kMaxFftOrder) + 1), -1); - ASSERT_EQ(RealFourier::FftOrder(1 << RealFourier::kMaxFftOrder), - RealFourier::kMaxFftOrder); - ASSERT_EQ(RealFourier::FftOrder(13), 4); - ASSERT_EQ(RealFourier::FftOrder(32), 5); - ASSERT_EQ(RealFourier::FftOrder(2), 1); - ASSERT_EQ(RealFourier::FftOrder(1), 0); - ASSERT_EQ(RealFourier::FftOrder(0), 0); + EXPECT_EQ(RealFourier::FftOrder(13), 4); + EXPECT_EQ(RealFourier::FftOrder(32), 5); + EXPECT_EQ(RealFourier::FftOrder(2), 1); + EXPECT_EQ(RealFourier::FftOrder(1), 0); } TEST(RealFourierStaticsTest, ComplexLengthComputation) { - ASSERT_EQ(RealFourier::ComplexLength(1), 2); - ASSERT_EQ(RealFourier::ComplexLength(2), 3); - ASSERT_EQ(RealFourier::ComplexLength(3), 5); - ASSERT_EQ(RealFourier::ComplexLength(4), 9); - ASSERT_EQ(RealFourier::ComplexLength(5), 17); - ASSERT_EQ(RealFourier::ComplexLength(7), 65); + EXPECT_EQ(RealFourier::ComplexLength(1), 2); + EXPECT_EQ(RealFourier::ComplexLength(2), 3); + EXPECT_EQ(RealFourier::ComplexLength(3), 5); + EXPECT_EQ(RealFourier::ComplexLength(4), 9); + EXPECT_EQ(RealFourier::ComplexLength(5), 17); + EXPECT_EQ(RealFourier::ComplexLength(7), 65); } +template class RealFourierTest : public ::testing::Test { protected: RealFourierTest() - : rf_(new RealFourier(2)), + : rf_(2), real_buffer_(RealFourier::AllocRealBuffer(4)), cplx_buffer_(RealFourier::AllocCplxBuffer(3)) {} ~RealFourierTest() { - delete rf_; } - const RealFourier* rf_; + T rf_; const RealFourier::fft_real_scoper real_buffer_; const RealFourier::fft_cplx_scoper cplx_buffer_; }; -TEST_F(RealFourierTest, SimpleForwardTransform) { - real_buffer_[0] = 1.0f; - real_buffer_[1] = 2.0f; - real_buffer_[2] = 3.0f; - real_buffer_[3] = 4.0f; +using FftTypes = ::testing::Types< +#if defined(RTC_USE_OPENMAX_DL) + RealFourierOpenmax, +#endif + RealFourierOoura>; +TYPED_TEST_CASE(RealFourierTest, FftTypes); - rf_->Forward(real_buffer_.get(), cplx_buffer_.get()); +TYPED_TEST(RealFourierTest, SimpleForwardTransform) { + this->real_buffer_[0] = 1.0f; + this->real_buffer_[1] = 2.0f; + this->real_buffer_[2] = 3.0f; + this->real_buffer_[3] = 4.0f; - ASSERT_NEAR(cplx_buffer_[0].real(), 10.0f, 1e-8f); - ASSERT_NEAR(cplx_buffer_[0].imag(), 0.0f, 1e-8f); - ASSERT_NEAR(cplx_buffer_[1].real(), -2.0f, 1e-8f); - ASSERT_NEAR(cplx_buffer_[1].imag(), 2.0f, 1e-8f); - ASSERT_NEAR(cplx_buffer_[2].real(), -2.0f, 1e-8f); - ASSERT_NEAR(cplx_buffer_[2].imag(), 0.0f, 1e-8f); + this->rf_.Forward(this->real_buffer_.get(), this->cplx_buffer_.get()); + + EXPECT_NEAR(this->cplx_buffer_[0].real(), 10.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[0].imag(), 0.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[1].real(), -2.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[1].imag(), 2.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[2].real(), -2.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[2].imag(), 0.0f, 1e-8f); } -TEST_F(RealFourierTest, SimpleBackwardTransform) { - cplx_buffer_[0] = complex(10.0f, 0.0f); - cplx_buffer_[1] = complex(-2.0f, 2.0f); - cplx_buffer_[2] = complex(-2.0f, 0.0f); +TYPED_TEST(RealFourierTest, SimpleBackwardTransform) { + this->cplx_buffer_[0] = complex(10.0f, 0.0f); + this->cplx_buffer_[1] = complex(-2.0f, 2.0f); + this->cplx_buffer_[2] = complex(-2.0f, 0.0f); - rf_->Inverse(cplx_buffer_.get(), real_buffer_.get()); + this->rf_.Inverse(this->cplx_buffer_.get(), this->real_buffer_.get()); - ASSERT_NEAR(real_buffer_[0], 1.0f, 1e-8f); - ASSERT_NEAR(real_buffer_[1], 2.0f, 1e-8f); - ASSERT_NEAR(real_buffer_[2], 3.0f, 1e-8f); - ASSERT_NEAR(real_buffer_[3], 4.0f, 1e-8f); + EXPECT_NEAR(this->real_buffer_[0], 1.0f, 1e-8f); + EXPECT_NEAR(this->real_buffer_[1], 2.0f, 1e-8f); + EXPECT_NEAR(this->real_buffer_[2], 3.0f, 1e-8f); + EXPECT_NEAR(this->real_buffer_[3], 4.0f, 1e-8f); } } // namespace webrtc diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn index b34c41cc32..e4ee78266c 100644 --- a/webrtc/modules/audio_processing/BUILD.gn +++ b/webrtc/modules/audio_processing/BUILD.gn @@ -116,8 +116,6 @@ source_set("audio_processing") { "utility/delay_estimator_internal.h", "utility/delay_estimator_wrapper.c", "utility/delay_estimator_wrapper.h", - "utility/fft4g.c", - "utility/fft4g.h", "voice_detection_impl.cc", "voice_detection_impl.h", ] diff --git a/webrtc/modules/audio_processing/agc/agc_audio_proc.cc b/webrtc/modules/audio_processing/agc/agc_audio_proc.cc index ccc77cc9ea..dc4a5a711c 100644 --- a/webrtc/modules/audio_processing/agc/agc_audio_proc.cc +++ b/webrtc/modules/audio_processing/agc/agc_audio_proc.cc @@ -13,6 +13,7 @@ #include #include +#include "webrtc/common_audio/fft4g.h" #include "webrtc/modules/audio_processing/agc/agc_audio_proc_internal.h" #include "webrtc/modules/audio_processing/agc/pitch_internal.h" #include "webrtc/modules/audio_processing/agc/pole_zero_filter.h" @@ -21,7 +22,6 @@ extern "C" { #include "webrtc/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h" #include "webrtc/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h" #include "webrtc/modules/audio_coding/codecs/isac/main/source/structs.h" -#include "webrtc/modules/audio_processing/utility/fft4g.h" } #include "webrtc/modules/interface/module_common_types.h" diff --git a/webrtc/modules/audio_processing/audio_processing.gypi b/webrtc/modules/audio_processing/audio_processing.gypi index 3175cc66e4..9d1ac8ccbd 100644 --- a/webrtc/modules/audio_processing/audio_processing.gypi +++ b/webrtc/modules/audio_processing/audio_processing.gypi @@ -126,8 +126,6 @@ 'utility/delay_estimator_internal.h', 'utility/delay_estimator_wrapper.c', 'utility/delay_estimator_wrapper.h', - 'utility/fft4g.c', - 'utility/fft4g.h', 'voice_detection_impl.cc', 'voice_detection_impl.h', ], diff --git a/webrtc/modules/audio_processing/ns/ns_core.c b/webrtc/modules/audio_processing/ns/ns_core.c index 56f2f46aa6..9e230dd140 100644 --- a/webrtc/modules/audio_processing/ns/ns_core.c +++ b/webrtc/modules/audio_processing/ns/ns_core.c @@ -13,11 +13,11 @@ #include #include +#include "webrtc/common_audio/fft4g.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_processing/ns/include/noise_suppression.h" #include "webrtc/modules/audio_processing/ns/ns_core.h" #include "webrtc/modules/audio_processing/ns/windows_private.h" -#include "webrtc/modules/audio_processing/utility/fft4g.h" // Set Feature Extraction Parameters. static void set_feature_extraction_parameters(NoiseSuppressionC* self) { diff --git a/webrtc/modules/audio_processing/transient/transient_suppressor.cc b/webrtc/modules/audio_processing/transient/transient_suppressor.cc index 44ea6bf233..2f79a20ac7 100644 --- a/webrtc/modules/audio_processing/transient/transient_suppressor.cc +++ b/webrtc/modules/audio_processing/transient/transient_suppressor.cc @@ -18,14 +18,12 @@ #include #include "webrtc/base/scoped_ptr.h" +#include "webrtc/common_audio/fft4g.h" #include "webrtc/common_audio/include/audio_util.h" #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" #include "webrtc/modules/audio_processing/transient/common.h" #include "webrtc/modules/audio_processing/transient/transient_detector.h" #include "webrtc/modules/audio_processing/ns/windows_private.h" -extern "C" { -#include "webrtc/modules/audio_processing/utility/fft4g.h" -} #include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/typedefs.h" @@ -39,10 +37,12 @@ static const size_t kMinVoiceBin = 3; static const size_t kMaxVoiceBin = 60; namespace { + float ComplexMagnitude(float a, float b) { return std::abs(a) + std::abs(b); } -} + +} // namespace TransientSuppressor::TransientSuppressor() : data_length_(0),