Make ChannelBuffer aware of frequency bands
Now the ChannelBuffer has 2 separate arrays, one for the full-band data and one for the splitted one. The corresponding accessors are added to the ChannelBuffer.
This is done to avoid having to refresh the bands pointers in AudioBuffer. It will also allow us to have a general accessor like data()[band][channel][sample].
All the files using the ChannelBuffer needed to be re-factored.
Tested with modules_unittests, common_audio_unittests, audioproc, audioproc_f, voe_cmd_test.
R=andrew@webrtc.org, kwiberg@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/36999004
Cr-Commit-Position: refs/heads/master@{#8318}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8318 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_processing/audio_buffer.cc b/webrtc/modules/audio_processing/audio_buffer.cc
index 7b302cf..c4dff8a 100644
--- a/webrtc/modules/audio_processing/audio_buffer.cc
+++ b/webrtc/modules/audio_processing/audio_buffer.cc
@@ -48,92 +48,90 @@
template <typename T>
void StereoToMono(const T* left, const T* right, T* out,
- int samples_per_channel) {
- for (int i = 0; i < samples_per_channel; ++i)
+ int num_frames) {
+ for (int i = 0; i < num_frames; ++i)
out[i] = (left[i] + right[i]) / 2;
}
+int NumBandsFromSamplesPerChannel(int num_frames) {
+ int num_bands = 1;
+ if (num_frames == kSamplesPer32kHzChannel ||
+ num_frames == kSamplesPer48kHzChannel) {
+ num_bands = rtc::CheckedDivExact(num_frames,
+ static_cast<int>(kSamplesPer16kHzChannel));
+ }
+ return num_bands;
+}
+
} // namespace
-AudioBuffer::AudioBuffer(int input_samples_per_channel,
+AudioBuffer::AudioBuffer(int input_num_frames,
int num_input_channels,
- int process_samples_per_channel,
+ int process_num_frames,
int num_process_channels,
- int output_samples_per_channel)
- : input_samples_per_channel_(input_samples_per_channel),
+ int output_num_frames)
+ : input_num_frames_(input_num_frames),
num_input_channels_(num_input_channels),
- proc_samples_per_channel_(process_samples_per_channel),
+ proc_num_frames_(process_num_frames),
num_proc_channels_(num_process_channels),
- output_samples_per_channel_(output_samples_per_channel),
+ output_num_frames_(output_num_frames),
num_channels_(num_process_channels),
- num_bands_(1),
- samples_per_split_channel_(proc_samples_per_channel_),
+ num_bands_(NumBandsFromSamplesPerChannel(proc_num_frames_)),
+ num_split_frames_(rtc::CheckedDivExact(
+ proc_num_frames_, num_bands_)),
mixed_low_pass_valid_(false),
reference_copied_(false),
activity_(AudioFrame::kVadUnknown),
keyboard_data_(NULL),
- channels_(new IFChannelBuffer(proc_samples_per_channel_,
- num_proc_channels_)) {
- assert(input_samples_per_channel_ > 0);
- assert(proc_samples_per_channel_ > 0);
- assert(output_samples_per_channel_ > 0);
+ data_(new IFChannelBuffer(proc_num_frames_, num_proc_channels_)) {
+ assert(input_num_frames_ > 0);
+ assert(proc_num_frames_ > 0);
+ assert(output_num_frames_ > 0);
assert(num_input_channels_ > 0 && num_input_channels_ <= 2);
- assert(num_proc_channels_ <= num_input_channels_);
+ assert(num_proc_channels_ > 0 && num_proc_channels_ <= num_input_channels_);
if (num_input_channels_ == 2 && num_proc_channels_ == 1) {
- input_buffer_.reset(new ChannelBuffer<float>(input_samples_per_channel_,
+ input_buffer_.reset(new ChannelBuffer<float>(input_num_frames_,
num_proc_channels_));
}
- if (input_samples_per_channel_ != proc_samples_per_channel_ ||
- output_samples_per_channel_ != proc_samples_per_channel_) {
+ if (input_num_frames_ != proc_num_frames_ ||
+ output_num_frames_ != proc_num_frames_) {
// Create an intermediate buffer for resampling.
- process_buffer_.reset(new ChannelBuffer<float>(proc_samples_per_channel_,
+ process_buffer_.reset(new ChannelBuffer<float>(proc_num_frames_,
num_proc_channels_));
- }
- if (input_samples_per_channel_ != proc_samples_per_channel_) {
- input_resamplers_.reserve(num_proc_channels_);
- for (int i = 0; i < num_proc_channels_; ++i) {
- input_resamplers_.push_back(
- new PushSincResampler(input_samples_per_channel_,
- proc_samples_per_channel_));
+ if (input_num_frames_ != proc_num_frames_) {
+ for (int i = 0; i < num_proc_channels_; ++i) {
+ input_resamplers_.push_back(
+ new PushSincResampler(input_num_frames_,
+ proc_num_frames_));
+ }
+ }
+
+ if (output_num_frames_ != proc_num_frames_) {
+ for (int i = 0; i < num_proc_channels_; ++i) {
+ output_resamplers_.push_back(
+ new PushSincResampler(proc_num_frames_,
+ output_num_frames_));
+ }
}
}
- if (output_samples_per_channel_ != proc_samples_per_channel_) {
- output_resamplers_.reserve(num_proc_channels_);
- for (int i = 0; i < num_proc_channels_; ++i) {
- output_resamplers_.push_back(
- new PushSincResampler(proc_samples_per_channel_,
- output_samples_per_channel_));
- }
- }
-
- if (proc_samples_per_channel_ == kSamplesPer32kHzChannel ||
- proc_samples_per_channel_ == kSamplesPer48kHzChannel) {
- samples_per_split_channel_ = kSamplesPer16kHzChannel;
- num_bands_ = proc_samples_per_channel_ / samples_per_split_channel_;
- split_channels_.push_back(new IFChannelBuffer(samples_per_split_channel_,
- num_proc_channels_));
- split_channels_.push_back(new IFChannelBuffer(samples_per_split_channel_,
- num_proc_channels_));
+ if (num_bands_ > 1) {
+ split_data_.reset(new IFChannelBuffer(proc_num_frames_,
+ num_proc_channels_,
+ num_bands_));
splitting_filter_.reset(new SplittingFilter(num_proc_channels_));
- if (proc_samples_per_channel_ == kSamplesPer48kHzChannel) {
- split_channels_.push_back(new IFChannelBuffer(samples_per_split_channel_,
- num_proc_channels_));
- }
}
- bands_.reset(new int16_t*[num_proc_channels_ * kMaxNumBands]);
- bands_f_.reset(new float*[num_proc_channels_ * kMaxNumBands]);
}
AudioBuffer::~AudioBuffer() {}
void AudioBuffer::CopyFrom(const float* const* data,
- int samples_per_channel,
+ int num_frames,
AudioProcessing::ChannelLayout layout) {
- assert(samples_per_channel == input_samples_per_channel_);
+ assert(num_frames == input_num_frames_);
assert(ChannelsFromLayout(layout) == num_input_channels_);
InitForNewData();
@@ -146,53 +144,55 @@
if (num_input_channels_ == 2 && num_proc_channels_ == 1) {
StereoToMono(data[0],
data[1],
- input_buffer_->channel(0),
- input_samples_per_channel_);
+ input_buffer_->channels()[0],
+ input_num_frames_);
data_ptr = input_buffer_->channels();
}
// Resample.
- if (input_samples_per_channel_ != proc_samples_per_channel_) {
+ if (input_num_frames_ != proc_num_frames_) {
for (int i = 0; i < num_proc_channels_; ++i) {
input_resamplers_[i]->Resample(data_ptr[i],
- input_samples_per_channel_,
- process_buffer_->channel(i),
- proc_samples_per_channel_);
+ input_num_frames_,
+ process_buffer_->channels()[i],
+ proc_num_frames_);
}
data_ptr = process_buffer_->channels();
}
// Convert to the S16 range.
for (int i = 0; i < num_proc_channels_; ++i) {
- FloatToFloatS16(data_ptr[i], proc_samples_per_channel_,
- channels_->fbuf()->channel(i));
+ FloatToFloatS16(data_ptr[i],
+ proc_num_frames_,
+ data_->fbuf()->channels()[i]);
}
}
-void AudioBuffer::CopyTo(int samples_per_channel,
+void AudioBuffer::CopyTo(int num_frames,
AudioProcessing::ChannelLayout layout,
float* const* data) {
- assert(samples_per_channel == output_samples_per_channel_);
+ assert(num_frames == output_num_frames_);
assert(ChannelsFromLayout(layout) == num_channels_);
// Convert to the float range.
float* const* data_ptr = data;
- if (output_samples_per_channel_ != proc_samples_per_channel_) {
+ if (output_num_frames_ != proc_num_frames_) {
// Convert to an intermediate buffer for subsequent resampling.
data_ptr = process_buffer_->channels();
}
for (int i = 0; i < num_channels_; ++i) {
- FloatS16ToFloat(channels_->fbuf()->channel(i), proc_samples_per_channel_,
+ FloatS16ToFloat(data_->fbuf()->channels()[i],
+ proc_num_frames_,
data_ptr[i]);
}
// Resample.
- if (output_samples_per_channel_ != proc_samples_per_channel_) {
+ if (output_num_frames_ != proc_num_frames_) {
for (int i = 0; i < num_channels_; ++i) {
output_resamplers_[i]->Resample(data_ptr[i],
- proc_samples_per_channel_,
+ proc_num_frames_,
data[i],
- output_samples_per_channel_);
+ output_num_frames_);
}
}
}
@@ -205,119 +205,81 @@
num_channels_ = num_proc_channels_;
}
-const int16_t* AudioBuffer::data_const(int channel) const {
- return channels_const()[channel];
-}
-
-int16_t* AudioBuffer::data(int channel) {
- return channels()[channel];
-}
-
const int16_t* const* AudioBuffer::channels_const() const {
- return channels_->ibuf_const()->channels();
+ return data_->ibuf_const()->channels();
}
int16_t* const* AudioBuffer::channels() {
mixed_low_pass_valid_ = false;
- return channels_->ibuf()->channels();
+ return data_->ibuf()->channels();
}
const int16_t* const* AudioBuffer::split_bands_const(int channel) const {
- // This is necessary to make sure that the int16_t data is up to date in the
- // IFChannelBuffer.
- // TODO(aluebs): Having to depend on this to get the updated data is bug
- // prone. One solution is to have ChannelBuffer track the bands as well.
- for (int i = 0; i < kMaxNumBands; ++i) {
- int16_t* const* channels =
- const_cast<int16_t* const*>(split_channels_const(static_cast<Band>(i)));
- bands_[kMaxNumBands * channel + i] = channels ? channels[channel] : NULL;
- }
- return &bands_[kMaxNumBands * channel];
+ return split_data_.get() ?
+ split_data_->ibuf_const()->bands(channel) :
+ data_->ibuf_const()->bands(channel);
}
int16_t* const* AudioBuffer::split_bands(int channel) {
mixed_low_pass_valid_ = false;
- // This is necessary to make sure that the int16_t data is up to date and the
- // float data is marked as invalid in the IFChannelBuffer.
- for (int i = 0; i < kMaxNumBands; ++i) {
- int16_t* const* channels = split_channels(static_cast<Band>(i));
- bands_[kMaxNumBands * channel + i] = channels ? channels[channel] : NULL;
- }
- return &bands_[kMaxNumBands * channel];
+ return split_data_.get() ?
+ split_data_->ibuf()->bands(channel) :
+ data_->ibuf()->bands(channel);
}
const int16_t* const* AudioBuffer::split_channels_const(Band band) const {
- if (split_channels_.size() > static_cast<size_t>(band)) {
- return split_channels_[band]->ibuf_const()->channels();
+ if (split_data_.get()) {
+ return split_data_->ibuf_const()->channels(band);
} else {
- return band == kBand0To8kHz ? channels_->ibuf_const()->channels() : NULL;
+ return band == kBand0To8kHz ? data_->ibuf_const()->channels() : nullptr;
}
}
int16_t* const* AudioBuffer::split_channels(Band band) {
mixed_low_pass_valid_ = false;
- if (split_channels_.size() > static_cast<size_t>(band)) {
- return split_channels_[band]->ibuf()->channels();
+ if (split_data_.get()) {
+ return split_data_->ibuf()->channels(band);
} else {
- return band == kBand0To8kHz ? channels_->ibuf()->channels() : NULL;
+ return band == kBand0To8kHz ? data_->ibuf()->channels() : nullptr;
}
}
-const float* AudioBuffer::data_const_f(int channel) const {
- return channels_const_f()[channel];
-}
-
-float* AudioBuffer::data_f(int channel) {
- return channels_f()[channel];
-}
-
const float* const* AudioBuffer::channels_const_f() const {
- return channels_->fbuf_const()->channels();
+ return data_->fbuf_const()->channels();
}
float* const* AudioBuffer::channels_f() {
mixed_low_pass_valid_ = false;
- return channels_->fbuf()->channels();
+ return data_->fbuf()->channels();
}
const float* const* AudioBuffer::split_bands_const_f(int channel) const {
- // This is necessary to make sure that the float data is up to date in the
- // IFChannelBuffer.
- for (int i = 0; i < kMaxNumBands; ++i) {
- float* const* channels =
- const_cast<float* const*>(split_channels_const_f(static_cast<Band>(i)));
- bands_f_[kMaxNumBands * channel + i] = channels ? channels[channel] : NULL;
-
- }
- return &bands_f_[kMaxNumBands * channel];
+ return split_data_.get() ?
+ split_data_->fbuf_const()->bands(channel) :
+ data_->fbuf_const()->bands(channel);
}
float* const* AudioBuffer::split_bands_f(int channel) {
mixed_low_pass_valid_ = false;
- // This is necessary to make sure that the float data is up to date and the
- // int16_t data is marked as invalid in the IFChannelBuffer.
- for (int i = 0; i < kMaxNumBands; ++i) {
- float* const* channels = split_channels_f(static_cast<Band>(i));
- bands_f_[kMaxNumBands * channel + i] = channels ? channels[channel] : NULL;
-
- }
- return &bands_f_[kMaxNumBands * channel];
+ return split_data_.get() ?
+ split_data_->fbuf()->bands(channel) :
+ data_->fbuf()->bands(channel);
}
const float* const* AudioBuffer::split_channels_const_f(Band band) const {
- if (split_channels_.size() > static_cast<size_t>(band)) {
- return split_channels_[band]->fbuf_const()->channels();
+ if (split_data_.get()) {
+ return split_data_->fbuf_const()->channels(band);
} else {
- return band == kBand0To8kHz ? channels_->fbuf_const()->channels() : NULL;
+ return band == kBand0To8kHz ? data_->fbuf_const()->channels() : nullptr;
}
}
float* const* AudioBuffer::split_channels_f(Band band) {
mixed_low_pass_valid_ = false;
- if (split_channels_.size() > static_cast<size_t>(band)) {
- return split_channels_[band]->fbuf()->channels();
+ if (split_data_.get()) {
+ return split_data_->fbuf()->channels(band);
} else {
- return band == kBand0To8kHz ? channels_->fbuf()->channels() : NULL;
+ return band == kBand0To8kHz ? data_->fbuf()->channels() : nullptr;
}
}
@@ -332,15 +294,15 @@
if (!mixed_low_pass_valid_) {
if (!mixed_low_pass_channels_.get()) {
mixed_low_pass_channels_.reset(
- new ChannelBuffer<int16_t>(samples_per_split_channel_, 1));
+ new ChannelBuffer<int16_t>(num_split_frames_, 1));
}
StereoToMono(split_bands_const(0)[kBand0To8kHz],
split_bands_const(1)[kBand0To8kHz],
- mixed_low_pass_channels_->data(),
- samples_per_split_channel_);
+ mixed_low_pass_channels_->channels()[0],
+ num_split_frames_);
mixed_low_pass_valid_ = true;
}
- return mixed_low_pass_channels_->data();
+ return mixed_low_pass_channels_->channels()[0];
}
const int16_t* AudioBuffer::low_pass_reference(int channel) const {
@@ -348,7 +310,7 @@
return NULL;
}
- return low_pass_reference_channels_->channel(channel);
+ return low_pass_reference_channels_->channels()[channel];
}
const float* AudioBuffer::keyboard_data() const {
@@ -371,17 +333,17 @@
num_channels_ = num_channels;
}
-int AudioBuffer::samples_per_channel() const {
- return proc_samples_per_channel_;
+int AudioBuffer::num_frames() const {
+ return proc_num_frames_;
}
-int AudioBuffer::samples_per_split_channel() const {
- return samples_per_split_channel_;
+int AudioBuffer::num_frames_per_band() const {
+ return num_split_frames_;
}
-int AudioBuffer::samples_per_keyboard_channel() const {
+int AudioBuffer::num_keyboard_frames() const {
// We don't resample the keyboard channel.
- return input_samples_per_channel_;
+ return input_num_frames_;
}
int AudioBuffer::num_bands() const {
@@ -390,25 +352,25 @@
// TODO(andrew): Do deinterleaving and mixing in one step?
void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) {
- assert(proc_samples_per_channel_ == input_samples_per_channel_);
+ assert(proc_num_frames_ == input_num_frames_);
assert(frame->num_channels_ == num_input_channels_);
- assert(frame->samples_per_channel_ == proc_samples_per_channel_);
+ assert(frame->samples_per_channel_ == proc_num_frames_);
InitForNewData();
activity_ = frame->vad_activity_;
if (num_input_channels_ == 2 && num_proc_channels_ == 1) {
// Downmix directly; no explicit deinterleaving needed.
- int16_t* downmixed = channels_->ibuf()->channel(0);
- for (int i = 0; i < input_samples_per_channel_; ++i) {
+ int16_t* downmixed = data_->ibuf()->channels()[0];
+ for (int i = 0; i < input_num_frames_; ++i) {
downmixed[i] = (frame->data_[i * 2] + frame->data_[i * 2 + 1]) / 2;
}
} else {
assert(num_proc_channels_ == num_input_channels_);
int16_t* interleaved = frame->data_;
for (int i = 0; i < num_proc_channels_; ++i) {
- int16_t* deinterleaved = channels_->ibuf()->channel(i);
+ int16_t* deinterleaved = data_->ibuf()->channels()[i];
int interleaved_idx = i;
- for (int j = 0; j < proc_samples_per_channel_; ++j) {
+ for (int j = 0; j < proc_num_frames_; ++j) {
deinterleaved[j] = interleaved[interleaved_idx];
interleaved_idx += num_proc_channels_;
}
@@ -417,10 +379,10 @@
}
void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) const {
- assert(proc_samples_per_channel_ == output_samples_per_channel_);
+ assert(proc_num_frames_ == output_num_frames_);
assert(num_channels_ == num_input_channels_);
assert(frame->num_channels_ == num_channels_);
- assert(frame->samples_per_channel_ == proc_samples_per_channel_);
+ assert(frame->samples_per_channel_ == proc_num_frames_);
frame->vad_activity_ = activity_;
if (!data_changed) {
@@ -429,9 +391,9 @@
int16_t* interleaved = frame->data_;
for (int i = 0; i < num_channels_; i++) {
- int16_t* deinterleaved = channels_->ibuf()->channel(i);
+ int16_t* deinterleaved = data_->ibuf()->channels()[i];
int interleaved_idx = i;
- for (int j = 0; j < proc_samples_per_channel_; j++) {
+ for (int j = 0; j < proc_num_frames_; j++) {
interleaved[interleaved_idx] = deinterleaved[j];
interleaved_idx += num_channels_;
}
@@ -443,23 +405,23 @@
if (!low_pass_reference_channels_.get() ||
low_pass_reference_channels_->num_channels() != num_channels_) {
low_pass_reference_channels_.reset(
- new ChannelBuffer<int16_t>(samples_per_split_channel_,
+ new ChannelBuffer<int16_t>(num_split_frames_,
num_proc_channels_));
}
for (int i = 0; i < num_proc_channels_; i++) {
- low_pass_reference_channels_->CopyFrom(split_bands_const(i)[kBand0To8kHz],
- i);
+ memcpy(low_pass_reference_channels_->channels()[i],
+ split_bands_const(i)[kBand0To8kHz],
+ low_pass_reference_channels_->num_frames_per_band() *
+ sizeof(split_bands_const(i)[kBand0To8kHz][0]));
}
}
void AudioBuffer::SplitIntoFrequencyBands() {
- splitting_filter_->Analysis(channels_.get(),
- split_channels_.get());
+ splitting_filter_->Analysis(data_.get(), split_data_.get());
}
void AudioBuffer::MergeFrequencyBands() {
- splitting_filter_->Synthesis(split_channels_.get(),
- channels_.get());
+ splitting_filter_->Synthesis(split_data_.get(), data_.get());
}
} // namespace webrtc