137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org/*
237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org *
437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org *  Use of this source code is governed by a BSD-style license
537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org *  that can be found in the LICENSE file in the root of the source
637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org *  tree. An additional intellectual property rights grant can be found
737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org *  in the file PATENTS.  All contributing project authors may
837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org */
1037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
1137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#include "webrtc/common_audio/fir_filter.h"
1237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
1337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#include <assert.h>
1437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#include <string.h>
1537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
1600b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org#include "webrtc/base/scoped_ptr.h"
1737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#include "webrtc/common_audio/fir_filter_neon.h"
1837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#include "webrtc/common_audio/fir_filter_sse.h"
1998f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
2037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
2137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.orgnamespace webrtc {
2237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
2337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.orgclass FIRFilterC : public FIRFilter {
2437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org public:
2537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  FIRFilterC(const float* coefficients,
2637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org             size_t coefficients_length);
2737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
2814665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void Filter(const float* in, size_t length, float* out) override;
2937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
3037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org private:
3137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  size_t coefficients_length_;
3237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  size_t state_length_;
3300b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<float[]> coefficients_;
3400b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<float[]> state_;
3537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org};
3637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
3737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.orgFIRFilter* FIRFilter::Create(const float* coefficients,
3837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org                             size_t coefficients_length,
3937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org                             size_t max_input_length) {
4037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) {
4137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    assert(false);
4237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    return NULL;
4337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  }
4437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
4537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  FIRFilter* filter = NULL;
4637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org// If we know the minimum architecture at compile time, avoid CPU detection.
4737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#if defined(WEBRTC_ARCH_X86_FAMILY)
4837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#if defined(__SSE2__)
4937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  filter =
5037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org      new FIRFilterSSE2(coefficients, coefficients_length, max_input_length);
5137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#else
5237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  // x86 CPU detection required.
5337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  if (WebRtc_GetCPUInfo(kSSE2)) {
5437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    filter =
5537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org        new FIRFilterSSE2(coefficients, coefficients_length, max_input_length);
5637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  } else {
5737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    filter = new FIRFilterC(coefficients, coefficients_length);
5837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  }
5937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#endif
60cb7f8ce2df7564546936d3041a96ccc86a90f988Andrew MacDonald#elif defined(WEBRTC_HAS_NEON)
6137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  filter =
6237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org      new FIRFilterNEON(coefficients, coefficients_length, max_input_length);
63cb7f8ce2df7564546936d3041a96ccc86a90f988Andrew MacDonald#elif defined(WEBRTC_DETECT_NEON)
6437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  if (WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) {
6537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    filter =
6637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org        new FIRFilterNEON(coefficients, coefficients_length, max_input_length);
6737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  } else {
6837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    filter = new FIRFilterC(coefficients, coefficients_length);
6937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  }
7037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#else
7137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  filter = new FIRFilterC(coefficients, coefficients_length);
7237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org#endif
7337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
7437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  return filter;
7537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org}
7637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
7737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.orgFIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length)
7837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    : coefficients_length_(coefficients_length),
7937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org      state_length_(coefficients_length - 1),
8037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org      coefficients_(new float[coefficients_length_]),
8137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org      state_(new float[state_length_]) {
8237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  for (size_t i = 0; i < coefficients_length_; ++i) {
8337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    coefficients_[i] = coefficients[coefficients_length_ - i - 1];
8437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  }
853cbd6c26c861a63f8f6164b7142d532a599f00e5bjornv@webrtc.org  memset(state_.get(), 0, state_length_ * sizeof(state_[0]));
8637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org}
8737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
8837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.orgvoid FIRFilterC::Filter(const float* in, size_t length, float* out) {
8937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  assert(length > 0);
9037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
9137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  // Convolves the input signal |in| with the filter kernel |coefficients_|
9237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  // taking into account the previous state.
9337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  for (size_t i = 0; i < length; ++i) {
9437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    out[i] = 0.f;
9537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    size_t j;
9637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    for (j = 0; state_length_ > i && j < state_length_ - i; ++j) {
9737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org      out[i] += state_[i + j] * coefficients_[j];
9837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    }
9937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    for (; j < coefficients_length_; ++j) {
10037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org      out[i] += in[j + i - state_length_] * coefficients_[j];
10137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    }
10237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  }
10337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
10437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  // Update current state.
10537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  if (length >= state_length_) {
10637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    memcpy(
10737ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org        state_.get(), &in[length - state_length_], state_length_ * sizeof(*in));
10837ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  } else {
10937ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    memmove(state_.get(),
11037ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org            &state_[length],
11137ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org            (state_length_ - length) * sizeof(state_[0]));
11237ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org    memcpy(&state_[state_length_ - length], in, length * sizeof(*in));
11337ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org  }
11437ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org}
11537ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org
11637ca765650adb36d3dd0ab84a507e660f44766c6aluebs@webrtc.org}  // namespace webrtc
117