124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org/* 224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. 324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org * 424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org * Use of this source code is governed by a BSD-style license 524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org * that can be found in the LICENSE file in the root of the source 624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org * tree. An additional intellectual property rights grant can be found 724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org * in the file PATENTS. All contributing project authors may 824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org * be found in the AUTHORS file in the root of the source tree. 924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org */ 1024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 1124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#include "webrtc/common_audio/fir_filter.h" 1224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 1324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#include <assert.h> 1424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#include <string.h> 1524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 1624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#include "webrtc/common_audio/fir_filter_neon.h" 1724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#include "webrtc/common_audio/fir_filter_sse.h" 1824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h" 1924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#include "webrtc/system_wrappers/interface/scoped_ptr.h" 2024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 2124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.orgnamespace webrtc { 2224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 2324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.orgclass FIRFilterC : public FIRFilter { 2424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org public: 2524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org FIRFilterC(const float* coefficients, 2624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org size_t coefficients_length); 2724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 2824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org virtual void Filter(const float* in, size_t length, float* out) OVERRIDE; 2924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 3024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org private: 3124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org size_t coefficients_length_; 3224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org size_t state_length_; 3324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org scoped_ptr<float[]> coefficients_; 3424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org scoped_ptr<float[]> state_; 3524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org}; 3624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 3724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.orgFIRFilter* FIRFilter::Create(const float* coefficients, 3824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org size_t coefficients_length, 3924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org size_t max_input_length) { 4024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) { 4124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org assert(false); 4224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org return NULL; 4324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 4424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 4524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org FIRFilter* filter = NULL; 4624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org// If we know the minimum architecture at compile time, avoid CPU detection. 4724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#if defined(WEBRTC_ARCH_X86_FAMILY) 4824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#if defined(__SSE2__) 4924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org filter = 5024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org new FIRFilterSSE2(coefficients, coefficients_length, max_input_length); 5124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#else 5224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org // x86 CPU detection required. 5324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org if (WebRtc_GetCPUInfo(kSSE2)) { 5424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org filter = 5524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org new FIRFilterSSE2(coefficients, coefficients_length, max_input_length); 5624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } else { 5724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org filter = new FIRFilterC(coefficients, coefficients_length); 5824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 5924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#endif 6024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#elif defined(WEBRTC_ARCH_ARM_V7) 6124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#if defined(WEBRTC_ARCH_ARM_NEON) 6224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org filter = 6324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org new FIRFilterNEON(coefficients, coefficients_length, max_input_length); 6424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#else 6524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org // ARM CPU detection required. 6624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org if (WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) { 6724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org filter = 6824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org new FIRFilterNEON(coefficients, coefficients_length, max_input_length); 6924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } else { 7024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org filter = new FIRFilterC(coefficients, coefficients_length); 7124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 7224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#endif 7324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#else 7424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org filter = new FIRFilterC(coefficients, coefficients_length); 7524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org#endif 7624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 7724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org return filter; 7824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org} 7924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 8024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.orgFIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length) 8124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org : coefficients_length_(coefficients_length), 8224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org state_length_(coefficients_length - 1), 8324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org coefficients_(new float[coefficients_length_]), 8424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org state_(new float[state_length_]) { 8524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org for (size_t i = 0; i < coefficients_length_; ++i) { 8624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org coefficients_[i] = coefficients[coefficients_length_ - i - 1]; 8724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 881f53a8f5c9591dd9e9896b2bb1e5456dbff6cb96bjornv@webrtc.org memset(state_.get(), 0, state_length_ * sizeof(state_[0])); 8924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org} 9024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 9124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.orgvoid FIRFilterC::Filter(const float* in, size_t length, float* out) { 9224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org assert(length > 0); 9324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 9424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org // Convolves the input signal |in| with the filter kernel |coefficients_| 9524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org // taking into account the previous state. 9624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org for (size_t i = 0; i < length; ++i) { 9724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org out[i] = 0.f; 9824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org size_t j; 9924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org for (j = 0; state_length_ > i && j < state_length_ - i; ++j) { 10024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org out[i] += state_[i + j] * coefficients_[j]; 10124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 10224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org for (; j < coefficients_length_; ++j) { 10324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org out[i] += in[j + i - state_length_] * coefficients_[j]; 10424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 10524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 10624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 10724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org // Update current state. 10824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org if (length >= state_length_) { 10924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org memcpy( 11024be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org state_.get(), &in[length - state_length_], state_length_ * sizeof(*in)); 11124be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } else { 11224be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org memmove(state_.get(), 11324be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org &state_[length], 11424be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org (state_length_ - length) * sizeof(state_[0])); 11524be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org memcpy(&state_[state_length_ - length], in, length * sizeof(*in)); 11624be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org } 11724be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org} 11824be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org 11924be06c54a94d1bf555dccdfd4e2a33ad69f70c4aluebs@webrtc.org} // namespace webrtc 120