Wrap the splitting filter in its own class
This doesn't change the behavior at all. The logic behind this is having one class which manages all the splitting filters, because in the future we plan to add a 3 band one for 48kHz support. It also breaks the dependency of the AudioBuffer with the filter states of these filters (which are going to be different for the 3 band one). The AudioBuffer is complicated enough and is going to need changes to support 3 bands in the future, so any simplification is a good idea. On top of that it eliminates repeated code in the APM (now only iterating over channels, but then also deciding in how many bands to split). This should be managed by the AudioBuffer directly. BUG=webrtc:3146 R=bjornv@webrtc.org, kwiberg@webrtc.org Review URL: https://webrtc-codereview.appspot.com/32469004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7705 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
67c22478a4
commit
be05c74ec8
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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<IFChannelBuffer> channels_;
|
||||
scoped_ptr<IFChannelBuffer> split_channels_low_;
|
||||
scoped_ptr<IFChannelBuffer> split_channels_high_;
|
||||
scoped_ptr<SplitFilterStates[]> filter_states_;
|
||||
scoped_ptr<SplittingFilter> splitting_filter_;
|
||||
scoped_ptr<ChannelBuffer<int16_t> > mixed_low_pass_channels_;
|
||||
scoped_ptr<ChannelBuffer<int16_t> > low_pass_reference_channels_;
|
||||
scoped_ptr<ChannelBuffer<float> > input_buffer_;
|
||||
|
@ -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',
|
||||
|
@ -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));
|
||||
|
49
webrtc/modules/audio_processing/splitting_filter.cc
Normal file
49
webrtc/modules/audio_processing/splitting_filter.cc
Normal file
@ -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 <assert.h>
|
||||
|
||||
#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
|
58
webrtc/modules/audio_processing/splitting_filter.h
Normal file
58
webrtc/modules/audio_processing/splitting_filter.h
Normal file
@ -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 <string.h>
|
||||
|
||||
#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<TwoBandsStates[]> two_bands_states_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_SPLITTING_FILTER_H_
|
Loading…
x
Reference in New Issue
Block a user