diff --git a/webrtc/modules/audio_processing/BUILD.gn b/webrtc/modules/audio_processing/BUILD.gn index 2ef2bdfc28..8f5186b06d 100644 --- a/webrtc/modules/audio_processing/BUILD.gn +++ b/webrtc/modules/audio_processing/BUILD.gn @@ -63,6 +63,8 @@ source_set("audio_processing") { "processing_component.h", "rms_level.cc", "rms_level.h", + "splitting_filter.cc", + "splitting_filter.h", "typing_detection.cc", "typing_detection.h", "utility/delay_estimator.c", diff --git a/webrtc/modules/audio_processing/audio_buffer.cc b/webrtc/modules/audio_processing/audio_buffer.cc index 63d69cfb30..2556bcda31 100644 --- a/webrtc/modules/audio_processing/audio_buffer.cc +++ b/webrtc/modules/audio_processing/audio_buffer.cc @@ -177,7 +177,7 @@ AudioBuffer::AudioBuffer(int input_samples_per_channel, num_proc_channels_)); split_channels_high_.reset(new IFChannelBuffer(samples_per_split_channel_, num_proc_channels_)); - filter_states_.reset(new SplitFilterStates[num_proc_channels_]); + splitting_filter_.reset(new SplittingFilter(num_proc_channels_)); } } @@ -266,6 +266,15 @@ int16_t* AudioBuffer::data(int channel) { return channels_->ibuf()->channel(channel); } +const int16_t* const* AudioBuffer::channels() const { + return channels_->ibuf_const()->channels(); +} + +int16_t* const* AudioBuffer::channels() { + mixed_low_pass_valid_ = false; + return channels_->ibuf()->channels(); +} + const float* AudioBuffer::data_f(int channel) const { return channels_->fbuf_const()->channel(channel); } @@ -297,6 +306,18 @@ int16_t* AudioBuffer::low_pass_split_data(int channel) { : data(channel); } +const int16_t* const* AudioBuffer::low_pass_split_channels() const { + return split_channels_low_.get() + ? split_channels_low_->ibuf_const()->channels() + : channels(); +} + +int16_t* const* AudioBuffer::low_pass_split_channels() { + mixed_low_pass_valid_ = false; + return split_channels_low_.get() ? split_channels_low_->ibuf()->channels() + : channels(); +} + const float* AudioBuffer::low_pass_split_data_f(int channel) const { return split_channels_low_.get() ? split_channels_low_->fbuf_const()->channel(channel) @@ -335,6 +356,17 @@ int16_t* AudioBuffer::high_pass_split_data(int channel) { : NULL; } +const int16_t* const* AudioBuffer::high_pass_split_channels() const { + return split_channels_high_.get() + ? split_channels_high_->ibuf_const()->channels() + : NULL; +} + +int16_t* const* AudioBuffer::high_pass_split_channels() { + return split_channels_high_.get() ? split_channels_high_->ibuf()->channels() + : NULL; +} + const float* AudioBuffer::high_pass_split_data_f(int channel) const { return split_channels_high_.get() ? split_channels_high_->fbuf_const()->channel(channel) @@ -393,11 +425,6 @@ const float* AudioBuffer::keyboard_data() const { return keyboard_data_; } -SplitFilterStates* AudioBuffer::filter_states(int channel) { - assert(channel >= 0 && channel < num_proc_channels_); - return &filter_states_[channel]; -} - void AudioBuffer::set_activity(AudioFrame::VADActivity activity) { activity_ = activity; } @@ -485,4 +512,16 @@ void AudioBuffer::CopyLowPassToReference() { } } +void AudioBuffer::SplitIntoFrequencyBands() { + splitting_filter_->TwoBandsAnalysis( + channels(), samples_per_channel(), num_proc_channels_, + low_pass_split_channels(), high_pass_split_channels()); +} + +void AudioBuffer::MergeFrequencyBands() { + splitting_filter_->TwoBandsSynthesis( + low_pass_split_channels(), high_pass_split_channels(), + samples_per_split_channel(), num_proc_channels_, channels()); +} + } // namespace webrtc diff --git a/webrtc/modules/audio_processing/audio_buffer.h b/webrtc/modules/audio_processing/audio_buffer.h index 12a99eccdc..7faa8a18c4 100644 --- a/webrtc/modules/audio_processing/audio_buffer.h +++ b/webrtc/modules/audio_processing/audio_buffer.h @@ -15,6 +15,7 @@ #include "webrtc/modules/audio_processing/common.h" #include "webrtc/modules/audio_processing/include/audio_processing.h" +#include "webrtc/modules/audio_processing/splitting_filter.h" #include "webrtc/modules/interface/module_common_types.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/scoped_vector.h" @@ -25,21 +26,6 @@ namespace webrtc { class PushSincResampler; class IFChannelBuffer; -struct SplitFilterStates { - SplitFilterStates() { - memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1)); - memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2)); - memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1)); - memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2)); - } - - static const int kStateSize = 6; - int analysis_filter_state1[kStateSize]; - int analysis_filter_state2[kStateSize]; - int synthesis_filter_state1[kStateSize]; - int synthesis_filter_state2[kStateSize]; -}; - class AudioBuffer { public: // TODO(ajm): Switch to take ChannelLayouts. @@ -60,10 +46,16 @@ class AudioBuffer { // possible, since they incur less float<->int16 conversion overhead. int16_t* data(int channel); const int16_t* data(int channel) const; + int16_t* const* channels(); + const int16_t* const* channels() const; int16_t* low_pass_split_data(int channel); const int16_t* low_pass_split_data(int channel) const; int16_t* high_pass_split_data(int channel); - const int16_t* high_pass_split_data(int channel) const;\ + const int16_t* high_pass_split_data(int channel) const; + int16_t* const* low_pass_split_channels(); + const int16_t* const* low_pass_split_channels() const; + int16_t* const* high_pass_split_channels(); + const int16_t* const* high_pass_split_channels() const; // Returns a pointer to the low-pass data downmixed to mono. If this data // isn't already available it re-calculates it. const int16_t* mixed_low_pass_data(); @@ -89,8 +81,6 @@ class AudioBuffer { const float* keyboard_data() const; - SplitFilterStates* filter_states(int channel); - void set_activity(AudioFrame::VADActivity activity); AudioFrame::VADActivity activity() const; @@ -109,6 +99,11 @@ class AudioBuffer { float* const* data); void CopyLowPassToReference(); + // Splits the signal into different bands. + void SplitIntoFrequencyBands(); + // Recombine the different bands into one signal. + void MergeFrequencyBands(); + private: // Called from DeinterleaveFrom() and CopyFrom(). void InitForNewData(); @@ -127,7 +122,7 @@ class AudioBuffer { scoped_ptr channels_; scoped_ptr split_channels_low_; scoped_ptr split_channels_high_; - scoped_ptr filter_states_; + scoped_ptr splitting_filter_; scoped_ptr > mixed_low_pass_channels_; scoped_ptr > low_pass_reference_channels_; scoped_ptr > input_buffer_; diff --git a/webrtc/modules/audio_processing/audio_processing.gypi b/webrtc/modules/audio_processing/audio_processing.gypi index 2ddcffc99b..89d0ffc33d 100644 --- a/webrtc/modules/audio_processing/audio_processing.gypi +++ b/webrtc/modules/audio_processing/audio_processing.gypi @@ -72,6 +72,8 @@ 'noise_suppression_impl.h', 'processing_component.cc', 'processing_component.h', + 'splitting_filter.cc', + 'splitting_filter.h', 'rms_level.cc', 'rms_level.h', 'typing_detection.cc', diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index d6e29060ce..61a6f00f92 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -469,15 +469,7 @@ int AudioProcessingImpl::ProcessStreamLocked() { AudioBuffer* ca = capture_audio_.get(); // For brevity. bool data_processed = is_data_processed(); if (analysis_needed(data_processed)) { - for (int i = 0; i < fwd_proc_format_.num_channels(); i++) { - // Split into a low and high band. - WebRtcSpl_AnalysisQMF(ca->data(i), - ca->samples_per_channel(), - ca->low_pass_split_data(i), - ca->high_pass_split_data(i), - ca->filter_states(i)->analysis_filter_state1, - ca->filter_states(i)->analysis_filter_state2); - } + ca->SplitIntoFrequencyBands(); } RETURN_ON_ERR(high_pass_filter_->ProcessCaptureAudio(ca)); @@ -494,15 +486,7 @@ int AudioProcessingImpl::ProcessStreamLocked() { RETURN_ON_ERR(gain_control_->ProcessCaptureAudio(ca)); if (synthesis_needed(data_processed)) { - for (int i = 0; i < fwd_proc_format_.num_channels(); i++) { - // Recombine low and high bands. - WebRtcSpl_SynthesisQMF(ca->low_pass_split_data(i), - ca->high_pass_split_data(i), - ca->samples_per_split_channel(), - ca->data(i), - ca->filter_states(i)->synthesis_filter_state1, - ca->filter_states(i)->synthesis_filter_state2); - } + ca->MergeFrequencyBands(); } // The level estimator operates on the recombined data. @@ -593,15 +577,7 @@ int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) { int AudioProcessingImpl::AnalyzeReverseStreamLocked() { AudioBuffer* ra = render_audio_.get(); // For brevity. if (rev_proc_format_.rate() == kSampleRate32kHz) { - for (int i = 0; i < rev_proc_format_.num_channels(); i++) { - // Split into low and high band. - WebRtcSpl_AnalysisQMF(ra->data(i), - ra->samples_per_channel(), - ra->low_pass_split_data(i), - ra->high_pass_split_data(i), - ra->filter_states(i)->analysis_filter_state1, - ra->filter_states(i)->analysis_filter_state2); - } + ra->SplitIntoFrequencyBands(); } RETURN_ON_ERR(echo_cancellation_->ProcessRenderAudio(ra)); diff --git a/webrtc/modules/audio_processing/splitting_filter.cc b/webrtc/modules/audio_processing/splitting_filter.cc new file mode 100644 index 0000000000..d2b5cc072e --- /dev/null +++ b/webrtc/modules/audio_processing/splitting_filter.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/audio_processing/splitting_filter.h" + +#include + +#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" + +namespace webrtc { + +SplittingFilter::SplittingFilter(int channels) + : channels_(channels), two_bands_states_(new TwoBandsStates[channels]) { +} + +void SplittingFilter::TwoBandsAnalysis(const int16_t* const* in_data, + int in_data_length, + int channels, + int16_t* const* low_band, + int16_t* const* high_band) { + assert(channels_ == channels); + for (int i = 0; i < channels_; ++i) { + WebRtcSpl_AnalysisQMF(in_data[i], in_data_length, low_band[i], high_band[i], + two_bands_states_[i].analysis_filter_state1, + two_bands_states_[i].analysis_filter_state2); + } +} + +void SplittingFilter::TwoBandsSynthesis(const int16_t* const* low_band, + const int16_t* const* high_band, + int band_length, + int channels, + int16_t* const* out_data) { + assert(channels_ == channels); + for (int i = 0; i < channels_; ++i) { + WebRtcSpl_SynthesisQMF(low_band[i], high_band[i], band_length, out_data[i], + two_bands_states_[i].synthesis_filter_state1, + two_bands_states_[i].synthesis_filter_state2); + } +} + +} // namespace webrtc diff --git a/webrtc/modules/audio_processing/splitting_filter.h b/webrtc/modules/audio_processing/splitting_filter.h new file mode 100644 index 0000000000..d316d9519a --- /dev/null +++ b/webrtc/modules/audio_processing/splitting_filter.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_ + +#include + +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/typedefs.h" + +namespace webrtc { + +struct TwoBandsStates { + TwoBandsStates() { + memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1)); + memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2)); + memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1)); + memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2)); + } + + static const int kStateSize = 6; + int analysis_filter_state1[kStateSize]; + int analysis_filter_state2[kStateSize]; + int synthesis_filter_state1[kStateSize]; + int synthesis_filter_state2[kStateSize]; +}; + +class SplittingFilter { + public: + SplittingFilter(int channels); + + void TwoBandsAnalysis(const int16_t* const* in_data, + int in_data_length, + int channels, + int16_t* const* low_band, + int16_t* const* high_band); + void TwoBandsSynthesis(const int16_t* const* low_band, + const int16_t* const* high_band, + int band_length, + int channels, + int16_t* const* out_data); + + private: + int channels_; + scoped_ptr two_bands_states_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_