OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/audio_processing/high_pass_filter_impl.h" | 11 #include "webrtc/modules/audio_processing/high_pass_filter_impl.h" |
12 | 12 |
13 #include <assert.h> | |
14 | |
15 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar y.h" | 13 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar y.h" |
16 #include "webrtc/modules/audio_processing/audio_buffer.h" | 14 #include "webrtc/modules/audio_processing/audio_buffer.h" |
17 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 15 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
18 #include "webrtc/typedefs.h" | |
19 | |
20 | 16 |
21 namespace webrtc { | 17 namespace webrtc { |
22 namespace { | 18 namespace { |
23 const int16_t kFilterCoefficients8kHz[5] = | 19 const int16_t kFilterCoefficients8kHz[5] = {3798, -7596, 3798, 7807, -3733}; |
24 {3798, -7596, 3798, 7807, -3733}; | 20 const int16_t kFilterCoefficients[5] = {4012, -8024, 4012, 8002, -3913}; |
21 } // namespace | |
25 | 22 |
26 const int16_t kFilterCoefficients[5] = | 23 class HighPassFilterImpl::MonoFilter { |
peah-webrtc
2015/12/08 14:52:27
I think we should call this a MonoBiquadFilter, or
the sun
2015/12/08 15:08:06
Good idea. I changed it to BiquadFilter, and the p
| |
27 {4012, -8024, 4012, 8002, -3913}; | 24 public: |
25 explicit MonoFilter(int sample_rate_hz) : | |
26 ba_(sample_rate_hz == AudioProcessing::kSampleRate8kHz ? | |
27 kFilterCoefficients8kHz : kFilterCoefficients) | |
28 { | |
29 std::memset(x_, 0, sizeof(x_)); | |
30 std::memset(y_, 0, sizeof(y_)); | |
31 } | |
28 | 32 |
29 struct FilterState { | 33 void Filter(int16_t* data, size_t length) { |
30 int16_t y[4]; | 34 const int16_t* const ba = ba_; |
31 int16_t x[2]; | 35 int16_t* x = x_; |
32 const int16_t* ba; | 36 int16_t* y = y_; |
37 int32_t tmp_int32 = 0; | |
38 | |
39 for (size_t i = 0; i < length; i++) { | |
40 // y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2] | |
41 // + -a[1] * y[i-1] + -a[2] * y[i-2]; | |
42 | |
43 tmp_int32 = y[1] * ba[3]; // -a[1] * y[i-1] (low part) | |
44 tmp_int32 += y[3] * ba[4]; // -a[2] * y[i-2] (low part) | |
45 tmp_int32 = (tmp_int32 >> 15); | |
46 tmp_int32 += y[0] * ba[3]; // -a[1] * y[i-1] (high part) | |
47 tmp_int32 += y[2] * ba[4]; // -a[2] * y[i-2] (high part) | |
48 tmp_int32 = (tmp_int32 << 1); | |
49 | |
50 tmp_int32 += data[i] * ba[0]; // b[0] * x[0] | |
51 tmp_int32 += x[0] * ba[1]; // b[1] * x[i-1] | |
52 tmp_int32 += x[1] * ba[2]; // b[2] * x[i-2] | |
53 | |
54 // Update state (input part). | |
55 x[1] = x[0]; | |
56 x[0] = data[i]; | |
57 | |
58 // Update state (filtered part). | |
59 y[2] = y[0]; | |
60 y[3] = y[1]; | |
61 y[0] = static_cast<int16_t>(tmp_int32 >> 13); | |
62 y[1] = static_cast<int16_t>( | |
63 (tmp_int32 - (static_cast<int32_t>(y[0]) << 13)) << 2); | |
64 | |
65 // Rounding in Q12, i.e. add 2^11. | |
66 tmp_int32 += 2048; | |
67 | |
68 // Saturate (to 2^27) so that the HP filtered signal does not overflow. | |
69 tmp_int32 = WEBRTC_SPL_SAT(static_cast<int32_t>(134217727), | |
70 tmp_int32, | |
71 static_cast<int32_t>(-134217728)); | |
72 | |
73 // Convert back to Q0 and use rounding. | |
74 data[i] = static_cast<int16_t>(tmp_int32 >> 12); | |
75 } | |
76 } | |
77 | |
78 private: | |
79 const int16_t* const ba_ = nullptr; | |
80 int16_t x_[2]; | |
81 int16_t y_[4]; | |
33 }; | 82 }; |
34 | 83 |
35 int InitializeFilter(FilterState* hpf, int sample_rate_hz) { | 84 HighPassFilterImpl::HighPassFilterImpl(rtc::CriticalSection* crit) |
36 assert(hpf != NULL); | 85 : crit_(crit) { |
37 | 86 RTC_DCHECK(crit_); |
38 if (sample_rate_hz == AudioProcessing::kSampleRate8kHz) { | |
39 hpf->ba = kFilterCoefficients8kHz; | |
40 } else { | |
41 hpf->ba = kFilterCoefficients; | |
42 } | |
43 | |
44 WebRtcSpl_MemSetW16(hpf->x, 0, 2); | |
45 WebRtcSpl_MemSetW16(hpf->y, 0, 4); | |
46 | |
47 return AudioProcessing::kNoError; | |
48 } | |
49 | |
50 int Filter(FilterState* hpf, int16_t* data, size_t length) { | |
51 assert(hpf != NULL); | |
52 | |
53 int32_t tmp_int32 = 0; | |
54 int16_t* y = hpf->y; | |
55 int16_t* x = hpf->x; | |
56 const int16_t* ba = hpf->ba; | |
57 | |
58 for (size_t i = 0; i < length; i++) { | |
59 // y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2] | |
60 // + -a[1] * y[i-1] + -a[2] * y[i-2]; | |
61 | |
62 tmp_int32 = y[1] * ba[3]; // -a[1] * y[i-1] (low part) | |
63 tmp_int32 += y[3] * ba[4]; // -a[2] * y[i-2] (low part) | |
64 tmp_int32 = (tmp_int32 >> 15); | |
65 tmp_int32 += y[0] * ba[3]; // -a[1] * y[i-1] (high part) | |
66 tmp_int32 += y[2] * ba[4]; // -a[2] * y[i-2] (high part) | |
67 tmp_int32 = (tmp_int32 << 1); | |
68 | |
69 tmp_int32 += data[i] * ba[0]; // b[0]*x[0] | |
70 tmp_int32 += x[0] * ba[1]; // b[1]*x[i-1] | |
71 tmp_int32 += x[1] * ba[2]; // b[2]*x[i-2] | |
72 | |
73 // Update state (input part) | |
74 x[1] = x[0]; | |
75 x[0] = data[i]; | |
76 | |
77 // Update state (filtered part) | |
78 y[2] = y[0]; | |
79 y[3] = y[1]; | |
80 y[0] = static_cast<int16_t>(tmp_int32 >> 13); | |
81 y[1] = static_cast<int16_t>( | |
82 (tmp_int32 - (static_cast<int32_t>(y[0]) << 13)) << 2); | |
83 | |
84 // Rounding in Q12, i.e. add 2^11 | |
85 tmp_int32 += 2048; | |
86 | |
87 // Saturate (to 2^27) so that the HP filtered signal does not overflow | |
88 tmp_int32 = WEBRTC_SPL_SAT(static_cast<int32_t>(134217727), | |
89 tmp_int32, | |
90 static_cast<int32_t>(-134217728)); | |
91 | |
92 // Convert back to Q0 and use rounding. | |
93 data[i] = (int16_t)(tmp_int32 >> 12); | |
94 } | |
95 | |
96 return AudioProcessing::kNoError; | |
97 } | |
98 } // namespace | |
99 | |
100 typedef FilterState Handle; | |
101 | |
102 HighPassFilterImpl::HighPassFilterImpl(const AudioProcessing* apm, | |
103 rtc::CriticalSection* crit) | |
104 : ProcessingComponent(), apm_(apm), crit_(crit) { | |
105 RTC_DCHECK(apm); | |
106 RTC_DCHECK(crit); | |
107 } | 87 } |
108 | 88 |
109 HighPassFilterImpl::~HighPassFilterImpl() {} | 89 HighPassFilterImpl::~HighPassFilterImpl() {} |
110 | 90 |
111 int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) { | 91 void HighPassFilterImpl::Initialize(int channels, int sample_rate_hz) { |
92 std::vector<rtc::scoped_ptr<MonoFilter>> new_filters(channels); | |
93 for (int i = 0; i < channels; i++) { | |
94 new_filters[i].reset(new MonoFilter(sample_rate_hz)); | |
95 } | |
112 rtc::CritScope cs(crit_); | 96 rtc::CritScope cs(crit_); |
113 int err = AudioProcessing::kNoError; | 97 filters_.swap(new_filters); |
98 } | |
114 | 99 |
115 if (!is_component_enabled()) { | 100 void HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
116 return AudioProcessing::kNoError; | 101 rtc::CritScope cs(crit_); |
102 if (!enabled_) { | |
103 return; | |
117 } | 104 } |
118 | 105 |
119 assert(audio->num_frames_per_band() <= 160); | 106 RTC_DCHECK_GE(160u, audio->num_frames_per_band()); |
120 | 107 RTC_DCHECK_EQ(filters_.size(), static_cast<size_t>(audio->num_channels())); |
121 for (int i = 0; i < num_handles(); i++) { | 108 for (size_t i = 0; i < filters_.size(); i++) { |
122 Handle* my_handle = static_cast<Handle*>(handle(i)); | 109 filters_[i]->Filter(audio->split_bands(i)[kBand0To8kHz], |
123 err = Filter(my_handle, | 110 audio->num_frames_per_band()); |
124 audio->split_bands(i)[kBand0To8kHz], | |
125 audio->num_frames_per_band()); | |
126 | |
127 if (err != AudioProcessing::kNoError) { | |
128 return GetHandleError(my_handle); | |
129 } | |
130 } | 111 } |
131 | |
132 return AudioProcessing::kNoError; | |
133 } | 112 } |
134 | 113 |
135 int HighPassFilterImpl::Enable(bool enable) { | 114 int HighPassFilterImpl::Enable(bool enable) { |
136 rtc::CritScope cs(crit_); | 115 rtc::CritScope cs(crit_); |
137 return EnableComponent(enable); | 116 enabled_ = enable; |
117 return AudioProcessing::kNoError; | |
138 } | 118 } |
139 | 119 |
140 bool HighPassFilterImpl::is_enabled() const { | 120 bool HighPassFilterImpl::is_enabled() const { |
141 rtc::CritScope cs(crit_); | 121 rtc::CritScope cs(crit_); |
142 return is_component_enabled(); | 122 return enabled_; |
143 } | |
144 | |
145 void* HighPassFilterImpl::CreateHandle() const { | |
146 return new FilterState; | |
147 } | |
148 | |
149 void HighPassFilterImpl::DestroyHandle(void* handle) const { | |
150 delete static_cast<Handle*>(handle); | |
151 } | |
152 | |
153 int HighPassFilterImpl::InitializeHandle(void* handle) const { | |
154 // TODO(peah): Remove dependency on apm for the | |
155 // capture side sample rate. | |
156 rtc::CritScope cs(crit_); | |
157 return InitializeFilter(static_cast<Handle*>(handle), | |
158 apm_->proc_sample_rate_hz()); | |
159 } | |
160 | |
161 int HighPassFilterImpl::ConfigureHandle(void* /*handle*/) const { | |
162 return AudioProcessing::kNoError; // Not configurable. | |
163 } | |
164 | |
165 int HighPassFilterImpl::num_handles_required() const { | |
166 return apm_->num_output_channels(); | |
167 } | |
168 | |
169 int HighPassFilterImpl::GetHandleError(void* handle) const { | |
170 // The component has no detailed errors. | |
171 assert(handle != NULL); | |
172 return AudioProcessing::kUnspecifiedError; | |
173 } | 123 } |
174 } // namespace webrtc | 124 } // namespace webrtc |
OLD | NEW |