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