1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
20c6f931420f1e8b697e31810c0b821bbd3d50585bjornv@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
117fad4b8c9f1e9a6e3de9962fb74d4953b4f1bb03pbos@webrtc.org#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"
12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
137fad4b8c9f1e9a6e3de9962fb74d4953b4f1bb03pbos@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
1456e4a05053d6addc7dbbe2b4d07271305fdbea75andrew@webrtc.org#include "webrtc/modules/audio_processing/audio_buffer.h"
1598f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
16470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comnamespace webrtc {
18470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comnamespace {
1970f9903e570931831a027ba6f91c164efc604a85solenbergconst int16_t kFilterCoefficients8kHz[5] = {3798, -7596, 3798, 7807, -3733};
2070f9903e570931831a027ba6f91c164efc604a85solenbergconst int16_t kFilterCoefficients[5] = {4012, -8024, 4012, 8002, -3913};
2170f9903e570931831a027ba6f91c164efc604a85solenberg}  // namespace
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2370f9903e570931831a027ba6f91c164efc604a85solenbergclass HighPassFilterImpl::BiquadFilter {
2470f9903e570931831a027ba6f91c164efc604a85solenberg public:
2570f9903e570931831a027ba6f91c164efc604a85solenberg  explicit BiquadFilter(int sample_rate_hz) :
2670f9903e570931831a027ba6f91c164efc604a85solenberg      ba_(sample_rate_hz == AudioProcessing::kSampleRate8kHz ?
2770f9903e570931831a027ba6f91c164efc604a85solenberg          kFilterCoefficients8kHz : kFilterCoefficients)
2870f9903e570931831a027ba6f91c164efc604a85solenberg  {
29c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg    Reset();
30c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg  }
31c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg
32c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg  void Reset() {
3370f9903e570931831a027ba6f91c164efc604a85solenberg    std::memset(x_, 0, sizeof(x_));
3470f9903e570931831a027ba6f91c164efc604a85solenberg    std::memset(y_, 0, sizeof(y_));
35470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
36470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3770f9903e570931831a027ba6f91c164efc604a85solenberg  void Process(int16_t* data, size_t length) {
3870f9903e570931831a027ba6f91c164efc604a85solenberg    const int16_t* const ba = ba_;
3970f9903e570931831a027ba6f91c164efc604a85solenberg    int16_t* x = x_;
4070f9903e570931831a027ba6f91c164efc604a85solenberg    int16_t* y = y_;
4170f9903e570931831a027ba6f91c164efc604a85solenberg    int32_t tmp_int32 = 0;
4270f9903e570931831a027ba6f91c164efc604a85solenberg
4370f9903e570931831a027ba6f91c164efc604a85solenberg    for (size_t i = 0; i < length; i++) {
4470f9903e570931831a027ba6f91c164efc604a85solenberg      //  y[i] = b[0] * x[i] +  b[1] * x[i-1] +  b[2] * x[i-2]
4570f9903e570931831a027ba6f91c164efc604a85solenberg      //                     + -a[1] * y[i-1] + -a[2] * y[i-2];
4670f9903e570931831a027ba6f91c164efc604a85solenberg
4770f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 = y[1] * ba[3];      // -a[1] * y[i-1] (low part)
4870f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 += y[3] * ba[4];     // -a[2] * y[i-2] (low part)
4970f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 = (tmp_int32 >> 15);
5070f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 += y[0] * ba[3];     // -a[1] * y[i-1] (high part)
5170f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 += y[2] * ba[4];     // -a[2] * y[i-2] (high part)
5270f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 = (tmp_int32 << 1);
5370f9903e570931831a027ba6f91c164efc604a85solenberg
5470f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 += data[i] * ba[0];  // b[0] * x[0]
5570f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 += x[0] * ba[1];     // b[1] * x[i-1]
5670f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 += x[1] * ba[2];     // b[2] * x[i-2]
5770f9903e570931831a027ba6f91c164efc604a85solenberg
5870f9903e570931831a027ba6f91c164efc604a85solenberg      // Update state (input part).
5970f9903e570931831a027ba6f91c164efc604a85solenberg      x[1] = x[0];
6070f9903e570931831a027ba6f91c164efc604a85solenberg      x[0] = data[i];
6170f9903e570931831a027ba6f91c164efc604a85solenberg
6270f9903e570931831a027ba6f91c164efc604a85solenberg      // Update state (filtered part).
6370f9903e570931831a027ba6f91c164efc604a85solenberg      y[2] = y[0];
6470f9903e570931831a027ba6f91c164efc604a85solenberg      y[3] = y[1];
6570f9903e570931831a027ba6f91c164efc604a85solenberg      y[0] = static_cast<int16_t>(tmp_int32 >> 13);
6670f9903e570931831a027ba6f91c164efc604a85solenberg      y[1] = static_cast<int16_t>(
6770f9903e570931831a027ba6f91c164efc604a85solenberg          (tmp_int32 - (static_cast<int32_t>(y[0]) << 13)) << 2);
6870f9903e570931831a027ba6f91c164efc604a85solenberg
6970f9903e570931831a027ba6f91c164efc604a85solenberg      // Rounding in Q12, i.e. add 2^11.
7070f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 += 2048;
7170f9903e570931831a027ba6f91c164efc604a85solenberg
7270f9903e570931831a027ba6f91c164efc604a85solenberg      // Saturate (to 2^27) so that the HP filtered signal does not overflow.
7370f9903e570931831a027ba6f91c164efc604a85solenberg      tmp_int32 = WEBRTC_SPL_SAT(static_cast<int32_t>(134217727),
7470f9903e570931831a027ba6f91c164efc604a85solenberg                                 tmp_int32,
7570f9903e570931831a027ba6f91c164efc604a85solenberg                                 static_cast<int32_t>(-134217728));
7670f9903e570931831a027ba6f91c164efc604a85solenberg
7770f9903e570931831a027ba6f91c164efc604a85solenberg      // Convert back to Q0 and use rounding.
7870f9903e570931831a027ba6f91c164efc604a85solenberg      data[i] = static_cast<int16_t>(tmp_int32 >> 12);
7970f9903e570931831a027ba6f91c164efc604a85solenberg    }
80470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
8270f9903e570931831a027ba6f91c164efc604a85solenberg private:
8370f9903e570931831a027ba6f91c164efc604a85solenberg  const int16_t* const ba_ = nullptr;
8470f9903e570931831a027ba6f91c164efc604a85solenberg  int16_t x_[2];
8570f9903e570931831a027ba6f91c164efc604a85solenberg  int16_t y_[4];
8670f9903e570931831a027ba6f91c164efc604a85solenberg};
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
8870f9903e570931831a027ba6f91c164efc604a85solenbergHighPassFilterImpl::HighPassFilterImpl(rtc::CriticalSection* crit)
8970f9903e570931831a027ba6f91c164efc604a85solenberg    : crit_(crit) {
9070f9903e570931831a027ba6f91c164efc604a85solenberg  RTC_DCHECK(crit_);
91df3efa8c079294857a8b8e0a02634d06a6d6b6d6peah}
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
93470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comHighPassFilterImpl::~HighPassFilterImpl() {}
94470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
956955870806624479723addfae6dcf5d13968796cPeter Kastingvoid HighPassFilterImpl::Initialize(size_t channels, int sample_rate_hz) {
9670f9903e570931831a027ba6f91c164efc604a85solenberg  std::vector<rtc::scoped_ptr<BiquadFilter>> new_filters(channels);
976955870806624479723addfae6dcf5d13968796cPeter Kasting  for (size_t i = 0; i < channels; i++) {
9870f9903e570931831a027ba6f91c164efc604a85solenberg    new_filters[i].reset(new BiquadFilter(sample_rate_hz));
9970f9903e570931831a027ba6f91c164efc604a85solenberg  }
100df3efa8c079294857a8b8e0a02634d06a6d6b6d6peah  rtc::CritScope cs(crit_);
10170f9903e570931831a027ba6f91c164efc604a85solenberg  filters_.swap(new_filters);
10270f9903e570931831a027ba6f91c164efc604a85solenberg}
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10470f9903e570931831a027ba6f91c164efc604a85solenbergvoid HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) {
1055e465c33cac54ed5265f18413f7afc44aae2dfcasolenberg  RTC_DCHECK(audio);
10670f9903e570931831a027ba6f91c164efc604a85solenberg  rtc::CritScope cs(crit_);
10770f9903e570931831a027ba6f91c164efc604a85solenberg  if (!enabled_) {
10870f9903e570931831a027ba6f91c164efc604a85solenberg    return;
109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11170f9903e570931831a027ba6f91c164efc604a85solenberg  RTC_DCHECK_GE(160u, audio->num_frames_per_band());
1126955870806624479723addfae6dcf5d13968796cPeter Kasting  RTC_DCHECK_EQ(filters_.size(), audio->num_channels());
11370f9903e570931831a027ba6f91c164efc604a85solenberg  for (size_t i = 0; i < filters_.size(); i++) {
11470f9903e570931831a027ba6f91c164efc604a85solenberg    filters_[i]->Process(audio->split_bands(i)[kBand0To8kHz],
11570f9903e570931831a027ba6f91c164efc604a85solenberg                         audio->num_frames_per_band());
116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint HighPassFilterImpl::Enable(bool enable) {
120df3efa8c079294857a8b8e0a02634d06a6d6b6d6peah  rtc::CritScope cs(crit_);
121c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg  if (!enabled_ && enable) {
122c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg    for (auto& filter : filters_) {
123c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg      filter->Reset();
124c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg    }
125c1316a1e51231b717e335f2c4c5ed3bf860a42b3solenberg  }
12670f9903e570931831a027ba6f91c164efc604a85solenberg  enabled_ = enable;
12770f9903e570931831a027ba6f91c164efc604a85solenberg  return AudioProcessing::kNoError;
128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.combool HighPassFilterImpl::is_enabled() const {
131df3efa8c079294857a8b8e0a02634d06a6d6b6d6peah  rtc::CritScope cs(crit_);
13270f9903e570931831a027ba6f91c164efc604a85solenberg  return enabled_;
133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}  // namespace webrtc
135