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
This commit is contained in:
andrew@webrtc.org 2015-03-19 20:06:29 +00:00
parent ba86031b34
commit 04c50981f8
19 changed files with 378 additions and 168 deletions

View File

@ -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:

View File

@ -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" ]
}

View File

@ -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': [

View File

@ -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_

View File

@ -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

View File

@ -82,7 +82,7 @@ class LappedTransform {
Callback* const block_processor_;
Blocker blocker_;
RealFourier fft_;
rtc::scoped_ptr<RealFourier> fft_;
const int cplx_length_;
AlignedArray<float> real_buf_;
AlignedArray<std::complex<float> > cplx_pre_;

View File

@ -10,54 +10,37 @@
#include "webrtc/common_audio/real_fourier.h"
#include <cstdlib>
#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> RealFourier::Create(int fft_order) {
#if defined(RTC_USE_OPENMAX_DL)
return rtc::scoped_ptr<RealFourier>(new RealFourierOpenmax(fft_order));
#else
return rtc::scoped_ptr<RealFourier>(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<float>) * count, kFftBufferAlignment)));
}
void RealFourier::Forward(const float* src, complex<float>* dest) const {
OMXResult r;
r = omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast<OMX_F32*>(dest), omx_spec_);
CHECK_EQ(r, OMX_Sts_NoErr);
}
void RealFourier::Inverse(const complex<float>* src, float* dest) const {
OMXResult r;
r = omxSP_FFTInv_CCSToR_F32(reinterpret_cast<const OMX_F32*>(src), dest,
omx_spec_);
CHECK_EQ(r, OMX_Sts_NoErr);
}
} // namespace webrtc

View File

@ -29,24 +29,23 @@ class RealFourier {
typedef rtc::scoped_ptr<std::complex<float>[], 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<RealFourier> 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<float>* dest) const;
virtual void Forward(const float* src, std::complex<float>* dest) const = 0;
// Inverse transform. Same input format as output above, conjugate pairs
// not needed.
void Inverse(const std::complex<float>* src, float* dest) const;
virtual void Inverse(const std::complex<float>* 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

View File

@ -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 <cmath>
#include <algorithm>
#include "webrtc/base/checks.h"
#include "webrtc/common_audio/fft4g.h"
namespace webrtc {
using std::complex;
namespace {
void Conjugate(complex<float>* array, int complex_length) {
std::for_each(array, array + complex_length,
[=](complex<float>& v) { v = std::conj(v); });
}
size_t ComputeWorkIpSize(int fft_length) {
return static_cast<size_t>(2 + std::ceil(std::sqrt(
static_cast<float>(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<float>* 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<float*>(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<float>(dest[0].imag(), 0.0f);
dest[0] = complex<float>(dest[0].real(), 0.0f);
// Ooura returns the conjugate of the usual Fourier definition.
Conjugate(dest, complex_length_);
}
void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const {
{
auto dest_complex = reinterpret_cast<complex<float>*>(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<float>(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

View File

@ -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 <complex>
#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<float>* dest) const override;
void Inverse(const std::complex<float>* 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<int[]> work_ip_;
const rtc::scoped_ptr<float[]> work_w_;
};
} // namespace webrtc
#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_

View File

@ -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 <cstdlib>
#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<float>* 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<OMX_F32*>(dest), omx_spec_);
CHECK_EQ(r, OMX_Sts_NoErr);
}
void RealFourierOpenmax::Inverse(const complex<float>* src, float* dest) const {
OMXResult r =
omxSP_FFTInv_CCSToR_F32(reinterpret_cast<const OMX_F32*>(src), dest,
omx_spec_);
CHECK_EQ(r, OMX_Sts_NoErr);
}
} // namespace webrtc

View File

@ -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 <complex>
#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<float>* dest) const override;
void Inverse(const std::complex<float>* 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_

View File

@ -13,6 +13,9 @@
#include <stdlib.h>
#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<int64_t>(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<int64_t>(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 <typename T>
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<float>(10.0f, 0.0f);
cplx_buffer_[1] = complex<float>(-2.0f, 2.0f);
cplx_buffer_[2] = complex<float>(-2.0f, 0.0f);
TYPED_TEST(RealFourierTest, SimpleBackwardTransform) {
this->cplx_buffer_[0] = complex<float>(10.0f, 0.0f);
this->cplx_buffer_[1] = complex<float>(-2.0f, 2.0f);
this->cplx_buffer_[2] = complex<float>(-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

View File

@ -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",
]

View File

@ -13,6 +13,7 @@
#include <math.h>
#include <stdio.h>
#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"

View File

@ -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',
],

View File

@ -13,11 +13,11 @@
#include <string.h>
#include <stdlib.h>
#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) {

View File

@ -18,14 +18,12 @@
#include <set>
#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),