andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 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 |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
pbos@webrtc.org | 9fb1613 | 2013-05-28 08:11:59 +0000 | [diff] [blame] | 11 | #include "webrtc/modules/audio_processing/high_pass_filter_impl.h" |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 12 | |
pbos@webrtc.org | 3f45c2e | 2013-08-05 16:22:53 +0000 | [diff] [blame] | 13 | #include <assert.h> |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 14 | |
pbos@webrtc.org | 9fb1613 | 2013-05-28 08:11:59 +0000 | [diff] [blame] | 15 | #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" |
| 16 | #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" |
| 17 | #include "webrtc/typedefs.h" |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 18 | |
pbos@webrtc.org | 9fb1613 | 2013-05-28 08:11:59 +0000 | [diff] [blame] | 19 | #include "webrtc/modules/audio_processing/audio_buffer.h" |
| 20 | #include "webrtc/modules/audio_processing/audio_processing_impl.h" |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 21 | |
| 22 | namespace webrtc { |
| 23 | namespace { |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 24 | const int16_t kFilterCoefficients8kHz[5] = |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 25 | {3798, -7596, 3798, 7807, -3733}; |
| 26 | |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 27 | const int16_t kFilterCoefficients[5] = |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 28 | {4012, -8024, 4012, 8002, -3913}; |
| 29 | |
| 30 | struct FilterState { |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 31 | int16_t y[4]; |
| 32 | int16_t x[2]; |
| 33 | const int16_t* ba; |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 34 | }; |
| 35 | |
| 36 | int InitializeFilter(FilterState* hpf, int sample_rate_hz) { |
| 37 | assert(hpf != NULL); |
| 38 | |
| 39 | if (sample_rate_hz == AudioProcessingImpl::kSampleRate8kHz) { |
| 40 | hpf->ba = kFilterCoefficients8kHz; |
| 41 | } else { |
| 42 | hpf->ba = kFilterCoefficients; |
| 43 | } |
| 44 | |
| 45 | WebRtcSpl_MemSetW16(hpf->x, 0, 2); |
| 46 | WebRtcSpl_MemSetW16(hpf->y, 0, 4); |
| 47 | |
| 48 | return AudioProcessing::kNoError; |
| 49 | } |
| 50 | |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 51 | int Filter(FilterState* hpf, int16_t* data, int length) { |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 52 | assert(hpf != NULL); |
| 53 | |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 54 | int32_t tmp_int32 = 0; |
| 55 | int16_t* y = hpf->y; |
| 56 | int16_t* x = hpf->x; |
| 57 | const int16_t* ba = hpf->ba; |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 58 | |
| 59 | for (int i = 0; i < length; i++) { |
| 60 | // y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2] |
| 61 | // + -a[1] * y[i-1] + -a[2] * y[i-2]; |
| 62 | |
| 63 | tmp_int32 = |
| 64 | WEBRTC_SPL_MUL_16_16(y[1], ba[3]); // -a[1] * y[i-1] (low part) |
| 65 | tmp_int32 += |
| 66 | WEBRTC_SPL_MUL_16_16(y[3], ba[4]); // -a[2] * y[i-2] (low part) |
| 67 | tmp_int32 = (tmp_int32 >> 15); |
| 68 | tmp_int32 += |
| 69 | WEBRTC_SPL_MUL_16_16(y[0], ba[3]); // -a[1] * y[i-1] (high part) |
| 70 | tmp_int32 += |
| 71 | WEBRTC_SPL_MUL_16_16(y[2], ba[4]); // -a[2] * y[i-2] (high part) |
| 72 | tmp_int32 = (tmp_int32 << 1); |
| 73 | |
| 74 | tmp_int32 += WEBRTC_SPL_MUL_16_16(data[i], ba[0]); // b[0]*x[0] |
| 75 | tmp_int32 += WEBRTC_SPL_MUL_16_16(x[0], ba[1]); // b[1]*x[i-1] |
| 76 | tmp_int32 += WEBRTC_SPL_MUL_16_16(x[1], ba[2]); // b[2]*x[i-2] |
| 77 | |
| 78 | // Update state (input part) |
| 79 | x[1] = x[0]; |
| 80 | x[0] = data[i]; |
| 81 | |
| 82 | // Update state (filtered part) |
| 83 | y[2] = y[0]; |
| 84 | y[3] = y[1]; |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 85 | y[0] = static_cast<int16_t>(tmp_int32 >> 13); |
| 86 | y[1] = static_cast<int16_t>((tmp_int32 - |
| 87 | WEBRTC_SPL_LSHIFT_W32(static_cast<int32_t>(y[0]), 13)) << 2); |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 88 | |
| 89 | // Rounding in Q12, i.e. add 2^11 |
| 90 | tmp_int32 += 2048; |
| 91 | |
| 92 | // Saturate (to 2^27) so that the HP filtered signal does not overflow |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 93 | tmp_int32 = WEBRTC_SPL_SAT(static_cast<int32_t>(134217727), |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 94 | tmp_int32, |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 95 | static_cast<int32_t>(-134217728)); |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 96 | |
| 97 | // Convert back to Q0 and use rounding |
pbos@webrtc.org | 3f6d5e0 | 2013-04-10 07:50:54 +0000 | [diff] [blame] | 98 | data[i] = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmp_int32, 12); |
andrew@webrtc.org | b015cbe | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 99 | |
| 100 | } |
| 101 | |
| 102 | return AudioProcessing::kNoError; |
| 103 | } |
| 104 | } // namespace |
| 105 | |
| 106 | typedef FilterState Handle; |
| 107 | |
| 108 | HighPassFilterImpl::HighPassFilterImpl(const AudioProcessingImpl* apm) |
| 109 | : ProcessingComponent(apm), |
| 110 | apm_(apm) {} |
| 111 | |
| 112 | HighPassFilterImpl::~HighPassFilterImpl() {} |
| 113 | |
| 114 | int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) { |
| 115 | int err = apm_->kNoError; |
| 116 | |
| 117 | if (!is_component_enabled()) { |
| 118 | return apm_->kNoError; |
| 119 | } |
| 120 | |
| 121 | assert(audio->samples_per_split_channel() <= 160); |
| 122 | |
| 123 | for (int i = 0; i < num_handles(); i++) { |
| 124 | Handle* my_handle = static_cast<Handle*>(handle(i)); |
| 125 | err = Filter(my_handle, |
| 126 | audio->low_pass_split_data(i), |
| 127 | audio->samples_per_split_channel()); |
| 128 | |
| 129 | if (err != apm_->kNoError) { |
| 130 | return GetHandleError(my_handle); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | return apm_->kNoError; |
| 135 | } |
| 136 | |
| 137 | int HighPassFilterImpl::Enable(bool enable) { |
| 138 | CriticalSectionScoped crit_scoped(apm_->crit()); |
| 139 | return EnableComponent(enable); |
| 140 | } |
| 141 | |
| 142 | bool HighPassFilterImpl::is_enabled() const { |
| 143 | return is_component_enabled(); |
| 144 | } |
| 145 | |
| 146 | void* HighPassFilterImpl::CreateHandle() const { |
| 147 | return new FilterState; |
| 148 | } |
| 149 | |
| 150 | int HighPassFilterImpl::DestroyHandle(void* handle) const { |
| 151 | delete static_cast<Handle*>(handle); |
| 152 | return apm_->kNoError; |
| 153 | } |
| 154 | |
| 155 | int HighPassFilterImpl::InitializeHandle(void* handle) const { |
| 156 | return InitializeFilter(static_cast<Handle*>(handle), |
| 157 | apm_->sample_rate_hz()); |
| 158 | } |
| 159 | |
| 160 | int HighPassFilterImpl::ConfigureHandle(void* /*handle*/) const { |
| 161 | return apm_->kNoError; // Not configurable. |
| 162 | } |
| 163 | |
| 164 | int HighPassFilterImpl::num_handles_required() const { |
| 165 | return apm_->num_output_channels(); |
| 166 | } |
| 167 | |
| 168 | int HighPassFilterImpl::GetHandleError(void* handle) const { |
| 169 | // The component has no detailed errors. |
| 170 | assert(handle != NULL); |
| 171 | return apm_->kUnspecifiedError; |
| 172 | } |
| 173 | } // namespace webrtc |