From d35a5c350617cc9d60ce45201764a99229b7299a Mon Sep 17 00:00:00 2001 From: "aluebs@webrtc.org" Date: Tue, 10 Feb 2015 22:52:15 +0000 Subject: [PATCH] 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 --- webrtc/common_audio/audio_converter.cc | 2 +- .../common_audio/audio_converter_unittest.cc | 16 +- .../audio_ring_buffer_unittest.cc | 9 +- webrtc/common_audio/blocker_unittest.cc | 27 +- webrtc/common_audio/channel_buffer.cc | 28 +- webrtc/common_audio/channel_buffer.h | 148 +++++---- .../modules/audio_processing/audio_buffer.cc | 284 ++++++++---------- .../modules/audio_processing/audio_buffer.h | 35 +-- .../audio_processing/audio_processing_impl.cc | 14 +- .../audio_processing/beamformer/pcm_utils.cc | 4 +- .../echo_cancellation_impl.cc | 8 +- .../echo_control_mobile_impl.cc | 8 +- .../audio_processing/gain_control_impl.cc | 14 +- .../audio_processing/high_pass_filter_impl.cc | 4 +- .../audio_processing/level_estimator_impl.cc | 4 +- .../noise_suppression_impl.cc | 4 +- .../audio_processing/splitting_filter.cc | 106 +++---- .../audio_processing/splitting_filter.h | 24 +- .../splitting_filter_unittest.cc | 26 +- .../test/audio_processing_unittest.cc | 68 +++-- .../audio_processing/test/audioproc_float.cc | 17 +- .../audio_processing/test/process_test.cc | 10 +- .../audio_processing/voice_detection_impl.cc | 2 +- 23 files changed, 430 insertions(+), 432 deletions(-) diff --git a/webrtc/common_audio/audio_converter.cc b/webrtc/common_audio/audio_converter.cc index f085ff13d1..2549393a43 100644 --- a/webrtc/common_audio/audio_converter.cc +++ b/webrtc/common_audio/audio_converter.cc @@ -89,7 +89,7 @@ void AudioConverter::Convert(const float* const* src, if (src_frames != dst_frames) { // Downmix to a buffer for subsequent resampling. DCHECK_EQ(downmix_buffer_->num_channels(), dst_channels); - DCHECK_EQ(downmix_buffer_->samples_per_channel(), src_frames); + DCHECK_EQ(downmix_buffer_->num_frames(), src_frames); dst_ptr = downmix_buffer_->channels(); } diff --git a/webrtc/common_audio/audio_converter_unittest.cc b/webrtc/common_audio/audio_converter_unittest.cc index 435f928bea..205bd984ce 100644 --- a/webrtc/common_audio/audio_converter_unittest.cc +++ b/webrtc/common_audio/audio_converter_unittest.cc @@ -28,14 +28,14 @@ ScopedBuffer CreateBuffer(const std::vector& data, int frames) { ScopedBuffer sb(new ChannelBuffer(frames, num_channels)); for (int i = 0; i < num_channels; ++i) for (int j = 0; j < frames; ++j) - sb->channel(i)[j] = data[i] * j; + sb->channels()[i][j] = data[i] * j; return sb; } void VerifyParams(const ChannelBuffer& ref, const ChannelBuffer& test) { EXPECT_EQ(ref.num_channels(), test.num_channels()); - EXPECT_EQ(ref.samples_per_channel(), test.samples_per_channel()); + EXPECT_EQ(ref.num_frames(), test.num_frames()); } // Computes the best SNR based on the error between |ref_frame| and @@ -50,20 +50,20 @@ float ComputeSNR(const ChannelBuffer& ref, // Search within one sample of the expected delay. for (int delay = std::max(expected_delay - 1, 0); - delay <= std::min(expected_delay + 1, ref.samples_per_channel()); + delay <= std::min(expected_delay + 1, ref.num_frames()); ++delay) { float mse = 0; float variance = 0; float mean = 0; for (int i = 0; i < ref.num_channels(); ++i) { - for (int j = 0; j < ref.samples_per_channel() - delay; ++j) { - float error = ref.channel(i)[j] - test.channel(i)[j + delay]; + for (int j = 0; j < ref.num_frames() - delay; ++j) { + float error = ref.channels()[i][j] - test.channels()[i][j + delay]; mse += error * error; - variance += ref.channel(i)[j] * ref.channel(i)[j]; - mean += ref.channel(i)[j]; + variance += ref.channels()[i][j] * ref.channels()[i][j]; + mean += ref.channels()[i][j]; } } - const int length = ref.num_channels() * (ref.samples_per_channel() - delay); + const int length = ref.num_channels() * (ref.num_frames() - delay); mse /= length; variance /= length; mean /= length; diff --git a/webrtc/common_audio/audio_ring_buffer_unittest.cc b/webrtc/common_audio/audio_ring_buffer_unittest.cc index 582d981c05..2d7d2c7b9a 100644 --- a/webrtc/common_audio/audio_ring_buffer_unittest.cc +++ b/webrtc/common_audio/audio_ring_buffer_unittest.cc @@ -25,7 +25,7 @@ void ReadAndWriteTest(const ChannelBuffer& input, size_t buffer_frames, ChannelBuffer* output) { const size_t num_channels = input.num_channels(); - const size_t total_frames = input.samples_per_channel(); + const size_t total_frames = input.num_frames(); AudioRingBuffer buf(num_channels, buffer_frames); scoped_ptr slice(new float*[num_channels]); @@ -91,17 +91,18 @@ TEST_F(AudioRingBufferTest, MoveReadPosition) { const size_t kNumChannels = 1; const float kInputArray[] = {1, 2, 3, 4}; const size_t kNumFrames = sizeof(kInputArray) / sizeof(*kInputArray); - ChannelBuffer input(kInputArray, kNumFrames, kNumChannels); + ChannelBuffer input(kNumFrames, kNumChannels); + input.SetDataForTesting(kInputArray, kNumFrames); AudioRingBuffer buf(kNumChannels, kNumFrames); buf.Write(input.channels(), kNumChannels, kNumFrames); buf.MoveReadPosition(3); ChannelBuffer output(1, kNumChannels); buf.Read(output.channels(), kNumChannels, 1); - EXPECT_EQ(4, output.data()[0]); + EXPECT_EQ(4, output.channels()[0][0]); buf.MoveReadPosition(-3); buf.Read(output.channels(), kNumChannels, 1); - EXPECT_EQ(2, output.data()[0]); + EXPECT_EQ(2, output.channels()[0][0]); } } // namespace webrtc diff --git a/webrtc/common_audio/blocker_unittest.cc b/webrtc/common_audio/blocker_unittest.cc index d1bfa6981f..bff447f5c8 100644 --- a/webrtc/common_audio/blocker_unittest.cc +++ b/webrtc/common_audio/blocker_unittest.cc @@ -132,13 +132,15 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, {3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; - const ChannelBuffer input_cb(kInput[0], kNumFrames, kNumInputChannels); + ChannelBuffer input_cb(kNumFrames, kNumInputChannels); + input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); const float kExpectedOutput[kNumInputChannels][kNumFrames] = { {6, 6, 12, 20, 20, 20, 20, 20, 20, 20}, {6, 6, 12, 28, 28, 28, 28, 28, 28, 28}}; - const ChannelBuffer expected_output_cb( - kExpectedOutput[0], kNumFrames, kNumInputChannels); + ChannelBuffer expected_output_cb(kNumFrames, kNumInputChannels); + expected_output_cb.SetDataForTesting( + kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; @@ -183,13 +185,15 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; - const ChannelBuffer input_cb(kInput[0], kNumFrames, kNumInputChannels); + ChannelBuffer input_cb(kNumFrames, kNumInputChannels); + input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { {6, 10, 10, 20, 10, 10, 20, 10, 10, 20, 10, 10}, {6, 14, 14, 28, 14, 14, 28, 14, 14, 28, 14, 14}}; - const ChannelBuffer expected_output_cb( - kExpectedOutput[0], kNumFrames, kNumOutputChannels); + ChannelBuffer expected_output_cb(kNumFrames, kNumOutputChannels); + expected_output_cb.SetDataForTesting( + kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; @@ -234,13 +238,15 @@ TEST_F(BlockerTest, TestBlockerNoOverlap) { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; - const ChannelBuffer input_cb(kInput[0], kNumFrames, kNumInputChannels); + ChannelBuffer input_cb(kNumFrames, kNumInputChannels); + input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, {14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}}; - const ChannelBuffer expected_output_cb( - kExpectedOutput[0], kNumFrames, kNumOutputChannels); + ChannelBuffer expected_output_cb(kNumFrames, kNumOutputChannels); + expected_output_cb.SetDataForTesting( + kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; @@ -292,7 +298,8 @@ TEST_F(BlockerTest, InitialDelaysAreMinimum) { input[i][j] = i + 1; } } - const ChannelBuffer input_cb(input[0], kNumFrames, kNumInputChannels); + ChannelBuffer input_cb(kNumFrames, kNumInputChannels); + input_cb.SetDataForTesting(input[0], sizeof(input) / sizeof(**input)); ChannelBuffer output_cb(kNumFrames, kNumOutputChannels); diff --git a/webrtc/common_audio/channel_buffer.cc b/webrtc/common_audio/channel_buffer.cc index 9c07550170..14aaa7af09 100644 --- a/webrtc/common_audio/channel_buffer.cc +++ b/webrtc/common_audio/channel_buffer.cc @@ -12,11 +12,13 @@ namespace webrtc { -IFChannelBuffer::IFChannelBuffer(int samples_per_channel, int num_channels) +IFChannelBuffer::IFChannelBuffer(int num_frames, + int num_channels, + int num_bands) : ivalid_(true), - ibuf_(samples_per_channel, num_channels), + ibuf_(num_frames, num_channels, num_bands), fvalid_(true), - fbuf_(samples_per_channel, num_channels) {} + fbuf_(num_frames, num_channels, num_bands) {} ChannelBuffer* IFChannelBuffer::ibuf() { RefreshI(); @@ -43,11 +45,13 @@ const ChannelBuffer* IFChannelBuffer::fbuf_const() const { void IFChannelBuffer::RefreshF() const { if (!fvalid_) { assert(ivalid_); - const int16_t* const int_data = ibuf_.data(); - float* const float_data = fbuf_.data(); - const int length = fbuf_.length(); - for (int i = 0; i < length; ++i) - float_data[i] = int_data[i]; + const int16_t* const* int_channels = ibuf_.channels(); + float* const* float_channels = fbuf_.channels(); + for (int i = 0; i < ibuf_.num_channels(); ++i) { + for (int j = 0; j < ibuf_.num_frames(); ++j) { + float_channels[i][j] = int_channels[i][j]; + } + } fvalid_ = true; } } @@ -55,7 +59,13 @@ void IFChannelBuffer::RefreshF() const { void IFChannelBuffer::RefreshI() const { if (!ivalid_) { assert(fvalid_); - FloatS16ToS16(fbuf_.data(), ibuf_.length(), ibuf_.data()); + int16_t* const* int_channels = ibuf_.channels(); + const float* const* float_channels = fbuf_.channels(); + for (int i = 0; i < ibuf_.num_channels(); ++i) { + FloatS16ToS16(float_channels[i], + ibuf_.num_frames(), + int_channels[i]); + } ivalid_ = true; } } diff --git a/webrtc/common_audio/channel_buffer.h b/webrtc/common_audio/channel_buffer.h index 31ebaa2d57..a5c4870d35 100644 --- a/webrtc/common_audio/channel_buffer.h +++ b/webrtc/common_audio/channel_buffer.h @@ -15,70 +15,96 @@ #include "webrtc/base/checks.h" #include "webrtc/common_audio/include/audio_util.h" +#include "webrtc/test/testsupport/gtest_prod_util.h" namespace webrtc { -// Helper to encapsulate a contiguous data buffer with access to a pointer -// array of the deinterleaved channels. The buffer is zero initialized at -// creation. +// Helper to encapsulate a contiguous data buffer, full or split into frequency +// bands, with access to a pointer arrays of the deinterleaved channels and +// bands. The buffer is zero initialized at creation. +// +// The buffer structure is showed below for a 2 channel and 2 bands case: +// +// |data_|: +// { [ --- b1ch1 --- ] [ --- b2ch1 --- ] [ --- b1ch2 --- ] [ --- b2ch2 --- ] } +// +// The pointer arrays for the same example are as follows: +// +// |channels_|: +// { [ b1ch1* ] [ b1ch2* ] [ b2ch1* ] [ b2ch2* ] } +// +// |bands_|: +// { [ b1ch1* ] [ b2ch1* ] [ b1ch2* ] [ b2ch2* ] } template class ChannelBuffer { public: - ChannelBuffer(int samples_per_channel, int num_channels) - : data_(new T[samples_per_channel * num_channels]), - channels_(new T*[num_channels]), - samples_per_channel_(samples_per_channel), - num_channels_(num_channels) { - Initialize(); + ChannelBuffer(int num_frames, + int num_channels, + int num_bands = 1) + : data_(new T[num_frames * num_channels]), + channels_(new T*[num_channels * num_bands]), + bands_(new T*[num_channels * num_bands]), + num_frames_(num_frames), + num_frames_per_band_(num_frames / num_bands), + num_channels_(num_channels), + num_bands_(num_bands) { + memset(data_.get(), 0, size() * sizeof(T)); + for (int i = 0; i < num_channels_; ++i) { + for (int j = 0; j < num_bands_; ++j) { + channels_[j * num_channels_ + i] = + &data_[i * num_frames_ + j * num_frames_per_band_]; + bands_[i * num_bands_ + j] = channels_[j * num_channels_ + i]; + } + } } - ChannelBuffer(const T* data, int samples_per_channel, int num_channels) - : data_(new T[samples_per_channel * num_channels]), - channels_(new T*[num_channels]), - samples_per_channel_(samples_per_channel), - num_channels_(num_channels) { - Initialize(); - memcpy(data_.get(), data, length() * sizeof(T)); + // Returns a pointer array to the full-band channels (or lower band channels). + // Usage: + // channels()[channel][sample]. + // Where: + // 0 <= channel < |num_channels_| + // 0 <= sample < |num_frames_| + T* const* channels() { return channels(0); } + const T* const* channels() const { return channels(0); } + + // Returns a pointer array to the channels for a specific band. + // Usage: + // channels(band)[channel][sample]. + // Where: + // 0 <= band < |num_bands_| + // 0 <= channel < |num_channels_| + // 0 <= sample < |num_frames_per_band_| + const T* const* channels(int band) const { + DCHECK_LT(band, num_bands_); + DCHECK_GE(band, 0); + return &channels_[band * num_channels_]; } - - ChannelBuffer(const T* const* channels, int samples_per_channel, - int num_channels) - : data_(new T[samples_per_channel * num_channels]), - channels_(new T*[num_channels]), - samples_per_channel_(samples_per_channel), - num_channels_(num_channels) { - Initialize(); - for (int i = 0; i < num_channels_; ++i) - CopyFrom(channels[i], i); - } - - ~ChannelBuffer() {} - - void CopyFrom(const void* channel_ptr, int i) { - DCHECK_LT(i, num_channels_); - memcpy(channels_[i], channel_ptr, samples_per_channel_ * sizeof(T)); - } - - T* data() { return data_.get(); } - const T* data() const { return data_.get(); } - - const T* channel(int i) const { - DCHECK_GE(i, 0); - DCHECK_LT(i, num_channels_); - return channels_[i]; - } - T* channel(int i) { + T* const* channels(int band) { const ChannelBuffer* t = this; - return const_cast(t->channel(i)); + return const_cast(t->channels(band)); } - T* const* channels() { return channels_.get(); } - const T* const* channels() const { return channels_.get(); } + // Returns a pointer array to the bands for a specific channel. + // Usage: + // bands(channel)[band][sample]. + // Where: + // 0 <= channel < |num_channels_| + // 0 <= band < |num_bands_| + // 0 <= sample < |num_frames_per_band_| + const T* const* bands(int channel) const { + DCHECK_LT(channel, num_channels_); + DCHECK_GE(channel, 0); + return &bands_[channel * num_bands_]; + } + T* const* bands(int channel) { + const ChannelBuffer* t = this; + return const_cast(t->bands(channel)); + } // Sets the |slice| pointers to the |start_frame| position for each channel. // Returns |slice| for convenience. const T* const* Slice(T** slice, int start_frame) const { - DCHECK_LT(start_frame, samples_per_channel_); + DCHECK_LT(start_frame, num_frames_); for (int i = 0; i < num_channels_; ++i) slice[i] = &channels_[i][start_frame]; return slice; @@ -88,21 +114,25 @@ class ChannelBuffer { return const_cast(t->Slice(slice, start_frame)); } - int samples_per_channel() const { return samples_per_channel_; } + int num_frames() const { return num_frames_; } + int num_frames_per_band() const { return num_frames_per_band_; } int num_channels() const { return num_channels_; } - int length() const { return samples_per_channel_ * num_channels_; } + int num_bands() const { return num_bands_; } + size_t size() const {return num_frames_ * num_channels_; } - private: - void Initialize() { - memset(data_.get(), 0, sizeof(T) * length()); - for (int i = 0; i < num_channels_; ++i) - channels_[i] = &data_[i * samples_per_channel_]; + void SetDataForTesting(const T* data, size_t size) { + CHECK_EQ(size, this->size()); + memcpy(data_.get(), data, size * sizeof(*data)); } + private: scoped_ptr data_; scoped_ptr channels_; - const int samples_per_channel_; + scoped_ptr bands_; + const int num_frames_; + const int num_frames_per_band_; const int num_channels_; + const int num_bands_; }; // One int16_t and one float ChannelBuffer that are kept in sync. The sync is @@ -113,15 +143,17 @@ class ChannelBuffer { // fbuf() until the next call to any of the other functions. class IFChannelBuffer { public: - IFChannelBuffer(int samples_per_channel, int num_channels); + IFChannelBuffer(int num_frames, int num_channels, int num_bands = 1); ChannelBuffer* ibuf(); ChannelBuffer* fbuf(); const ChannelBuffer* ibuf_const() const; const ChannelBuffer* fbuf_const() const; + int num_frames() const { return ibuf_.num_frames(); } + int num_frames_per_band() const { return ibuf_.num_frames_per_band(); } int num_channels() const { return ibuf_.num_channels(); } - int samples_per_channel() const { return ibuf_.samples_per_channel(); } + int num_bands() const { return ibuf_.num_bands(); } private: void RefreshF() const; diff --git a/webrtc/modules/audio_processing/audio_buffer.cc b/webrtc/modules/audio_processing/audio_buffer.cc index 7b302cff07..c4dff8a8d0 100644 --- a/webrtc/modules/audio_processing/audio_buffer.cc +++ b/webrtc/modules/audio_processing/audio_buffer.cc @@ -48,92 +48,90 @@ int KeyboardChannelIndex(AudioProcessing::ChannelLayout layout) { template 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(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(input_samples_per_channel_, + input_buffer_.reset(new ChannelBuffer(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(proc_samples_per_channel_, + process_buffer_.reset(new ChannelBuffer(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 @@ void AudioBuffer::CopyFrom(const float* const* data, 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 @@ void AudioBuffer::InitForNewData() { 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(split_channels_const(static_cast(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(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(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(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(split_channels_const_f(static_cast(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(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(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(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 @@ const int16_t* AudioBuffer::mixed_low_pass_data() { if (!mixed_low_pass_valid_) { if (!mixed_low_pass_channels_.get()) { mixed_low_pass_channels_.reset( - new ChannelBuffer(samples_per_split_channel_, 1)); + new ChannelBuffer(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 @@ const int16_t* AudioBuffer::low_pass_reference(int channel) const { 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 @@ void AudioBuffer::set_num_channels(int num_channels) { 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 @@ int AudioBuffer::num_bands() const { // 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::DeinterleaveFrom(AudioFrame* frame) { } 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 @@ void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) const { 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 @@ void AudioBuffer::CopyLowPassToReference() { if (!low_pass_reference_channels_.get() || low_pass_reference_channels_->num_channels() != num_channels_) { low_pass_reference_channels_.reset( - new ChannelBuffer(samples_per_split_channel_, + new ChannelBuffer(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 diff --git a/webrtc/modules/audio_processing/audio_buffer.h b/webrtc/modules/audio_processing/audio_buffer.h index da4f7e8f29..a7f7e892f9 100644 --- a/webrtc/modules/audio_processing/audio_buffer.h +++ b/webrtc/modules/audio_processing/audio_buffer.h @@ -27,7 +27,6 @@ namespace webrtc { class PushSincResampler; class IFChannelBuffer; -static const int kMaxNumBands = 3; enum Band { kBand0To8kHz = 0, kBand8To16kHz = 1, @@ -37,25 +36,23 @@ enum Band { class AudioBuffer { public: // TODO(ajm): Switch to take ChannelLayouts. - AudioBuffer(int input_samples_per_channel, + 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); + int output_num_frames); virtual ~AudioBuffer(); int num_channels() const; void set_num_channels(int num_channels); - int samples_per_channel() const; - int samples_per_split_channel() const; - int samples_per_keyboard_channel() const; + int num_frames() const; + int num_frames_per_band() const; + int num_keyboard_frames() const; int num_bands() const; // Sample array accessors. Channels are guaranteed to be stored contiguously // in memory. Prefer to use the const variants of each accessor when // possible, since they incur less float<->int16 conversion overhead. - int16_t* data(int channel); - const int16_t* data_const(int channel) const; int16_t* const* channels(); const int16_t* const* channels_const() const; int16_t* const* split_bands(int channel); @@ -70,8 +67,6 @@ class AudioBuffer { // Float versions of the accessors, with automatic conversion back and forth // as necessary. The range of the numbers are the same as for int16_t. - float* data_f(int channel); - const float* data_const_f(int channel) const; float* const* channels_f(); const float* const* channels_const_f() const; float* const* split_bands_f(int channel); @@ -92,9 +87,9 @@ class AudioBuffer { // Use for float deinterleaved data. void CopyFrom(const float* const* data, - int samples_per_channel, + int num_frames, AudioProcessing::ChannelLayout layout); - void CopyTo(int samples_per_channel, + void CopyTo(int num_frames, AudioProcessing::ChannelLayout layout, float* const* data); void CopyLowPassToReference(); @@ -110,29 +105,27 @@ class AudioBuffer { // The audio is passed into DeinterleaveFrom() or CopyFrom() with input // format (samples per channel and number of channels). - const int input_samples_per_channel_; + const int input_num_frames_; const int num_input_channels_; // The audio is stored by DeinterleaveFrom() or CopyFrom() with processing // format. - const int proc_samples_per_channel_; + const int proc_num_frames_; const int num_proc_channels_; // The audio is returned by InterleaveTo() and CopyTo() with output samples // per channels and the current number of channels. This last one can be // changed at any time using set_num_channels(). - const int output_samples_per_channel_; + const int output_num_frames_; int num_channels_; int num_bands_; - int samples_per_split_channel_; + int num_split_frames_; bool mixed_low_pass_valid_; bool reference_copied_; AudioFrame::VADActivity activity_; const float* keyboard_data_; - scoped_ptr channels_; - ScopedVector split_channels_; - scoped_ptr bands_; - scoped_ptr bands_f_; + scoped_ptr data_; + scoped_ptr split_data_; scoped_ptr splitting_filter_; scoped_ptr > mixed_low_pass_channels_; scoped_ptr > low_pass_reference_channels_; diff --git a/webrtc/modules/audio_processing/audio_processing_impl.cc b/webrtc/modules/audio_processing/audio_processing_impl.cc index 1319e16962..06b60385c9 100644 --- a/webrtc/modules/audio_processing/audio_processing_impl.cc +++ b/webrtc/modules/audio_processing/audio_processing_impl.cc @@ -598,7 +598,7 @@ int AudioProcessingImpl::ProcessStreamLocked() { AudioBuffer* ca = capture_audio_.get(); // For brevity. if (use_new_agc_ && gain_control_->is_enabled()) { - agc_manager_->AnalyzePreProcess(ca->data(0), + agc_manager_->AnalyzePreProcess(ca->channels()[0], ca->num_channels(), fwd_proc_format_.samples_per_channel()); } @@ -613,7 +613,7 @@ int AudioProcessingImpl::ProcessStreamLocked() { beamformer_->ProcessChunk(ca->split_channels_const_f(kBand0To8kHz), ca->split_channels_const_f(kBand8To16kHz), ca->num_channels(), - ca->samples_per_split_channel(), + ca->num_frames_per_band(), ca->split_channels_f(kBand0To8kHz), ca->split_channels_f(kBand8To16kHz)); ca->set_num_channels(1); @@ -636,7 +636,7 @@ int AudioProcessingImpl::ProcessStreamLocked() { gain_control_->is_enabled() && (!beamformer_enabled_ || beamformer_->is_target_present())) { agc_manager_->Process(ca->split_bands_const(0)[kBand0To8kHz], - ca->samples_per_split_channel(), + ca->num_frames_per_band(), split_rate_); } RETURN_ON_ERR(gain_control_->ProcessCaptureAudio(ca)); @@ -651,13 +651,13 @@ int AudioProcessingImpl::ProcessStreamLocked() { float voice_probability = agc_manager_.get() ? agc_manager_->voice_probability() : 1.f; - transient_suppressor_->Suppress(ca->data_f(0), - ca->samples_per_channel(), + transient_suppressor_->Suppress(ca->channels_f()[0], + ca->num_frames(), ca->num_channels(), ca->split_bands_const_f(0)[kBand0To8kHz], - ca->samples_per_split_channel(), + ca->num_frames_per_band(), ca->keyboard_data(), - ca->samples_per_keyboard_channel(), + ca->num_keyboard_frames(), voice_probability, key_pressed_); } diff --git a/webrtc/modules/audio_processing/beamformer/pcm_utils.cc b/webrtc/modules/audio_processing/beamformer/pcm_utils.cc index 14d9742330..207a2dc30e 100644 --- a/webrtc/modules/audio_processing/beamformer/pcm_utils.cc +++ b/webrtc/modules/audio_processing/beamformer/pcm_utils.cc @@ -51,7 +51,7 @@ size_t PcmReadToFloat(FILE* file, PcmRead(file, length, num_channels, deinterleaved_buffer->channels()); for (int i = 0; i < num_channels; ++i) { - S16ToFloat(deinterleaved_buffer->channel(i), num_frames, buffer[i]); + S16ToFloat(deinterleaved_buffer->channels()[i], num_frames, buffer[i]); } return elements_read; } @@ -82,7 +82,7 @@ void PcmWriteFromFloat(FILE* file, new ChannelBuffer(num_frames, num_channels)); for (int i = 0; i < num_channels; ++i) { - FloatToS16(buffer[i], num_frames, deinterleaved_buffer->channel(i)); + FloatToS16(buffer[i], num_frames, deinterleaved_buffer->channels()[i]); } PcmWrite(file, length, num_channels, deinterleaved_buffer->channels()); } diff --git a/webrtc/modules/audio_processing/echo_cancellation_impl.cc b/webrtc/modules/audio_processing/echo_cancellation_impl.cc index dd3c7f1cc5..245941a426 100644 --- a/webrtc/modules/audio_processing/echo_cancellation_impl.cc +++ b/webrtc/modules/audio_processing/echo_cancellation_impl.cc @@ -77,7 +77,7 @@ int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == apm_->num_reverse_channels()); int err = apm_->kNoError; @@ -90,7 +90,7 @@ int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { err = WebRtcAec_BufferFarend( my_handle, audio->split_bands_const_f(j)[kBand0To8kHz], - static_cast(audio->samples_per_split_channel())); + static_cast(audio->num_frames_per_band())); if (err != apm_->kNoError) { return GetHandleError(my_handle); // TODO(ajm): warning possible? @@ -116,7 +116,7 @@ int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { return apm_->kStreamParameterNotSetError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == apm_->num_output_channels()); int err = apm_->kNoError; @@ -132,7 +132,7 @@ int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { audio->split_bands_const_f(i), audio->num_bands(), audio->split_bands_f(i), - static_cast(audio->samples_per_split_channel()), + static_cast(audio->num_frames_per_band()), apm_->stream_delay_ms(), stream_drift_samples_); diff --git a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc index 534732ee97..0f5b4fe7ab 100644 --- a/webrtc/modules/audio_processing/echo_control_mobile_impl.cc +++ b/webrtc/modules/audio_processing/echo_control_mobile_impl.cc @@ -83,7 +83,7 @@ int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == apm_->num_reverse_channels()); int err = apm_->kNoError; @@ -96,7 +96,7 @@ int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { err = WebRtcAecm_BufferFarend( my_handle, audio->split_bands_const(j)[kBand0To8kHz], - static_cast(audio->samples_per_split_channel())); + static_cast(audio->num_frames_per_band())); if (err != apm_->kNoError) { return GetHandleError(my_handle); // TODO(ajm): warning possible? @@ -118,7 +118,7 @@ int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { return apm_->kStreamParameterNotSetError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == apm_->num_output_channels()); int err = apm_->kNoError; @@ -141,7 +141,7 @@ int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { noisy, clean, audio->split_bands(i)[kBand0To8kHz], - static_cast(audio->samples_per_split_channel()), + static_cast(audio->num_frames_per_band()), apm_->stream_delay_ms()); if (err != apm_->kNoError) { diff --git a/webrtc/modules/audio_processing/gain_control_impl.cc b/webrtc/modules/audio_processing/gain_control_impl.cc index af92b9c149..6211c4985c 100644 --- a/webrtc/modules/audio_processing/gain_control_impl.cc +++ b/webrtc/modules/audio_processing/gain_control_impl.cc @@ -57,14 +57,14 @@ int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) { return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); for (int i = 0; i < num_handles(); i++) { Handle* my_handle = static_cast(handle(i)); int err = WebRtcAgc_AddFarend( my_handle, audio->mixed_low_pass_data(), - static_cast(audio->samples_per_split_channel())); + static_cast(audio->num_frames_per_band())); if (err != apm_->kNoError) { return GetHandleError(my_handle); @@ -79,7 +79,7 @@ int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == num_handles()); int err = apm_->kNoError; @@ -92,7 +92,7 @@ int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { my_handle, audio->split_bands(i), audio->num_bands(), - static_cast(audio->samples_per_split_channel())); + static_cast(audio->num_frames_per_band())); if (err != apm_->kNoError) { return GetHandleError(my_handle); @@ -108,7 +108,7 @@ int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { my_handle, audio->split_bands(i), audio->num_bands(), - static_cast(audio->samples_per_split_channel()), + static_cast(audio->num_frames_per_band()), analog_capture_level_, &capture_level_out); @@ -133,7 +133,7 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { return apm_->kStreamParameterNotSetError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == num_handles()); stream_is_saturated_ = false; @@ -146,7 +146,7 @@ int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { my_handle, audio->split_bands_const(i), audio->num_bands(), - static_cast(audio->samples_per_split_channel()), + static_cast(audio->num_frames_per_band()), audio->split_bands(i), capture_levels_[i], &capture_level_out, diff --git a/webrtc/modules/audio_processing/high_pass_filter_impl.cc b/webrtc/modules/audio_processing/high_pass_filter_impl.cc index 43c3754bdf..588ba41415 100644 --- a/webrtc/modules/audio_processing/high_pass_filter_impl.cc +++ b/webrtc/modules/audio_processing/high_pass_filter_impl.cc @@ -114,13 +114,13 @@ int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) { return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); for (int i = 0; i < num_handles(); i++) { Handle* my_handle = static_cast(handle(i)); err = Filter(my_handle, audio->split_bands(i)[kBand0To8kHz], - audio->samples_per_split_channel()); + audio->num_frames_per_band()); if (err != apm_->kNoError) { return GetHandleError(my_handle); diff --git a/webrtc/modules/audio_processing/level_estimator_impl.cc b/webrtc/modules/audio_processing/level_estimator_impl.cc index 5fbda836e3..26a61dcdb5 100644 --- a/webrtc/modules/audio_processing/level_estimator_impl.cc +++ b/webrtc/modules/audio_processing/level_estimator_impl.cc @@ -31,8 +31,8 @@ int LevelEstimatorImpl::ProcessStream(AudioBuffer* audio) { RMSLevel* rms_level = static_cast(handle(0)); for (int i = 0; i < audio->num_channels(); ++i) { - rms_level->Process(audio->data_const(i), - audio->samples_per_channel()); + rms_level->Process(audio->channels_const()[i], + audio->num_frames()); } return AudioProcessing::kNoError; diff --git a/webrtc/modules/audio_processing/noise_suppression_impl.cc b/webrtc/modules/audio_processing/noise_suppression_impl.cc index 05ef910383..aa37e67fa8 100644 --- a/webrtc/modules/audio_processing/noise_suppression_impl.cc +++ b/webrtc/modules/audio_processing/noise_suppression_impl.cc @@ -60,7 +60,7 @@ int NoiseSuppressionImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { if (!is_component_enabled()) { return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == num_handles()); for (int i = 0; i < num_handles(); ++i) { @@ -76,7 +76,7 @@ int NoiseSuppressionImpl::ProcessCaptureAudio(AudioBuffer* audio) { if (!is_component_enabled()) { return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); assert(audio->num_channels() == num_handles()); for (int i = 0; i < num_handles(); ++i) { diff --git a/webrtc/modules/audio_processing/splitting_filter.cc b/webrtc/modules/audio_processing/splitting_filter.cc index f3cbcadfb1..623bb05891 100644 --- a/webrtc/modules/audio_processing/splitting_filter.cc +++ b/webrtc/modules/audio_processing/splitting_filter.cc @@ -30,59 +30,53 @@ SplittingFilter::SplittingFilter(int channels) } } -void SplittingFilter::Analysis(const IFChannelBuffer* in_data, - const std::vector& bands) { - DCHECK(bands.size() == 2 || bands.size() == 3); - DCHECK_EQ(channels_, in_data->num_channels()); - for (size_t i = 0; i < bands.size(); ++i) { - DCHECK_EQ(channels_, bands[i]->num_channels()); - DCHECK_EQ(in_data->samples_per_channel(), - static_cast(bands.size()) * bands[i]->samples_per_channel()); - } - if (bands.size() == 2) { - TwoBandsAnalysis(in_data, bands[0], bands[1]); - } else if (bands.size() == 3) { - ThreeBandsAnalysis(in_data, bands[0], bands[1], bands[2]); +void SplittingFilter::Analysis(const IFChannelBuffer* data, + IFChannelBuffer* bands) { + DCHECK(bands->num_bands() == 2 || bands->num_bands() == 3); + DCHECK_EQ(channels_, data->num_channels()); + DCHECK_EQ(channels_, bands->num_channels()); + DCHECK_EQ(data->num_frames(), + bands->num_frames_per_band() * bands->num_bands()); + if (bands->num_bands() == 2) { + TwoBandsAnalysis(data, bands); + } else if (bands->num_bands() == 3) { + ThreeBandsAnalysis(data, bands); } } -void SplittingFilter::Synthesis(const std::vector& bands, - IFChannelBuffer* out_data) { - DCHECK(bands.size() == 2 || bands.size() == 3); - DCHECK_EQ(channels_, out_data->num_channels()); - for (size_t i = 0; i < bands.size(); ++i) { - DCHECK_EQ(channels_, bands[i]->num_channels()); - DCHECK_EQ(out_data->samples_per_channel(), - static_cast(bands.size()) * bands[i]->samples_per_channel()); - } - if (bands.size() == 2) { - TwoBandsSynthesis(bands[0], bands[1], out_data); - } else if (bands.size() == 3) { - ThreeBandsSynthesis(bands[0], bands[1], bands[2], out_data); +void SplittingFilter::Synthesis(const IFChannelBuffer* bands, + IFChannelBuffer* data) { + DCHECK(bands->num_bands() == 2 || bands->num_bands() == 3); + DCHECK_EQ(channels_, data->num_channels()); + DCHECK_EQ(channels_, bands->num_channels()); + DCHECK_EQ(data->num_frames(), + bands->num_frames_per_band() * bands->num_bands()); + if (bands->num_bands() == 2) { + TwoBandsSynthesis(bands, data); + } else if (bands->num_bands() == 3) { + ThreeBandsSynthesis(bands, data); } } -void SplittingFilter::TwoBandsAnalysis(const IFChannelBuffer* in_data, - IFChannelBuffer* band1, - IFChannelBuffer* band2) { +void SplittingFilter::TwoBandsAnalysis(const IFChannelBuffer* data, + IFChannelBuffer* bands) { for (int i = 0; i < channels_; ++i) { - WebRtcSpl_AnalysisQMF(in_data->ibuf_const()->channel(i), - in_data->samples_per_channel(), - band1->ibuf()->channel(i), - band2->ibuf()->channel(i), + WebRtcSpl_AnalysisQMF(data->ibuf_const()->channels()[i], + data->num_frames(), + bands->ibuf()->channels(0)[i], + bands->ibuf()->channels(1)[i], two_bands_states_[i].analysis_state1, two_bands_states_[i].analysis_state2); } } -void SplittingFilter::TwoBandsSynthesis(const IFChannelBuffer* band1, - const IFChannelBuffer* band2, - IFChannelBuffer* out_data) { +void SplittingFilter::TwoBandsSynthesis(const IFChannelBuffer* bands, + IFChannelBuffer* data) { for (int i = 0; i < channels_; ++i) { - WebRtcSpl_SynthesisQMF(band1->ibuf_const()->channel(i), - band2->ibuf_const()->channel(i), - band1->samples_per_channel(), - out_data->ibuf()->channel(i), + WebRtcSpl_SynthesisQMF(bands->ibuf_const()->channels(0)[i], + bands->ibuf_const()->channels(1)[i], + bands->num_frames_per_band(), + data->ibuf()->channels()[i], two_bands_states_[i].synthesis_state1, two_bands_states_[i].synthesis_state2); } @@ -92,15 +86,13 @@ void SplittingFilter::TwoBandsSynthesis(const IFChannelBuffer* band1, // by a proper 3 band filter bank. // It up-samples from 48kHz to 64kHz, splits twice into 2 bands and discards the // uppermost band, because it is empty anyway. -void SplittingFilter::ThreeBandsAnalysis(const IFChannelBuffer* in_data, - IFChannelBuffer* band1, - IFChannelBuffer* band2, - IFChannelBuffer* band3) { +void SplittingFilter::ThreeBandsAnalysis(const IFChannelBuffer* data, + IFChannelBuffer* bands) { DCHECK_EQ(kSamplesPer48kHzChannel, - in_data->samples_per_channel()); + data->num_frames()); InitBuffers(); for (int i = 0; i < channels_; ++i) { - analysis_resamplers_[i]->Resample(in_data->ibuf_const()->channel(i), + analysis_resamplers_[i]->Resample(data->ibuf_const()->channels()[i], kSamplesPer48kHzChannel, int_buffer_.get(), kSamplesPer64kHzChannel); @@ -112,14 +104,14 @@ void SplittingFilter::ThreeBandsAnalysis(const IFChannelBuffer* in_data, two_bands_states_[i].analysis_state2); WebRtcSpl_AnalysisQMF(int_buffer_.get(), kSamplesPer32kHzChannel, - band1->ibuf()->channel(i), - band2->ibuf()->channel(i), + bands->ibuf()->channels(0)[i], + bands->ibuf()->channels(1)[i], band1_states_[i].analysis_state1, band1_states_[i].analysis_state2); WebRtcSpl_AnalysisQMF(int_buffer_.get() + kSamplesPer32kHzChannel, kSamplesPer32kHzChannel, int_buffer_.get(), - band3->ibuf()->channel(i), + bands->ibuf()->channels(2)[i], band2_states_[i].analysis_state1, band2_states_[i].analysis_state2); } @@ -129,25 +121,23 @@ void SplittingFilter::ThreeBandsAnalysis(const IFChannelBuffer* in_data, // by a proper 3 band filter bank. // Using an empty uppermost band, it merges the 4 bands in 2 steps and // down-samples from 64kHz to 48kHz. -void SplittingFilter::ThreeBandsSynthesis(const IFChannelBuffer* band1, - const IFChannelBuffer* band2, - const IFChannelBuffer* band3, - IFChannelBuffer* out_data) { +void SplittingFilter::ThreeBandsSynthesis(const IFChannelBuffer* bands, + IFChannelBuffer* data) { DCHECK_EQ(kSamplesPer48kHzChannel, - out_data->samples_per_channel()); + data->num_frames()); InitBuffers(); for (int i = 0; i < channels_; ++i) { memset(int_buffer_.get(), 0, kSamplesPer64kHzChannel * sizeof(int_buffer_[0])); - WebRtcSpl_SynthesisQMF(band1->ibuf_const()->channel(i), - band2->ibuf_const()->channel(i), + WebRtcSpl_SynthesisQMF(bands->ibuf_const()->channels(0)[i], + bands->ibuf_const()->channels(1)[i], kSamplesPer16kHzChannel, int_buffer_.get(), band1_states_[i].synthesis_state1, band1_states_[i].synthesis_state2); WebRtcSpl_SynthesisQMF(int_buffer_.get() + kSamplesPer32kHzChannel, - band3->ibuf_const()->channel(i), + bands->ibuf_const()->channels(2)[i], kSamplesPer16kHzChannel, int_buffer_.get() + kSamplesPer32kHzChannel, band2_states_[i].synthesis_state1, @@ -160,7 +150,7 @@ void SplittingFilter::ThreeBandsSynthesis(const IFChannelBuffer* band1, two_bands_states_[i].synthesis_state2); synthesis_resamplers_[i]->Resample(int_buffer_.get(), kSamplesPer64kHzChannel, - out_data->ibuf()->channel(i), + data->ibuf()->channels()[i], kSamplesPer48kHzChannel); } } diff --git a/webrtc/modules/audio_processing/splitting_filter.h b/webrtc/modules/audio_processing/splitting_filter.h index 119375b51d..16387a8c56 100644 --- a/webrtc/modules/audio_processing/splitting_filter.h +++ b/webrtc/modules/audio_processing/splitting_filter.h @@ -56,28 +56,16 @@ class SplittingFilter { public: SplittingFilter(int channels); - void Analysis(const IFChannelBuffer* in_data, - const std::vector& bands); - void Synthesis(const std::vector& bands, - IFChannelBuffer* out_data); + void Analysis(const IFChannelBuffer* data, IFChannelBuffer* bands); + void Synthesis(const IFChannelBuffer* bands, IFChannelBuffer* data); private: // These work for 640 samples or less. - void TwoBandsAnalysis(const IFChannelBuffer* in_data, - IFChannelBuffer* band1, - IFChannelBuffer* band2); - void TwoBandsSynthesis(const IFChannelBuffer* band1, - const IFChannelBuffer* band2, - IFChannelBuffer* out_data); + void TwoBandsAnalysis(const IFChannelBuffer* data, IFChannelBuffer* bands); + void TwoBandsSynthesis(const IFChannelBuffer* bands, IFChannelBuffer* data); // These only work for 480 samples at the moment. - void ThreeBandsAnalysis(const IFChannelBuffer* in_data, - IFChannelBuffer* band1, - IFChannelBuffer* band2, - IFChannelBuffer* band3); - void ThreeBandsSynthesis(const IFChannelBuffer* band1, - const IFChannelBuffer* band2, - const IFChannelBuffer* band3, - IFChannelBuffer* out_data); + void ThreeBandsAnalysis(const IFChannelBuffer* data, IFChannelBuffer* bands); + void ThreeBandsSynthesis(const IFChannelBuffer* bands, IFChannelBuffer* data); void InitBuffers(); int channels_; diff --git a/webrtc/modules/audio_processing/splitting_filter_unittest.cc b/webrtc/modules/audio_processing/splitting_filter_unittest.cc index 105392d8de..598057f8c2 100644 --- a/webrtc/modules/audio_processing/splitting_filter_unittest.cc +++ b/webrtc/modules/audio_processing/splitting_filter_unittest.cc @@ -35,36 +35,32 @@ TEST(SplittingFilterTest, SplitsIntoThreeBandsAndReconstructs) { static const float kAmplitude = 8192; static const int kChunks = 8; SplittingFilter splitting_filter(kChannels); - IFChannelBuffer in_data(kSamplesPer48kHzChannel, kChannels); - IFChannelBuffer out_data(kSamplesPer48kHzChannel, kChannels); - ScopedVector bands; - for (int i = 0; i < kNumBands; ++i) { - bands.push_back(new IFChannelBuffer(kSamplesPer16kHzChannel, kChannels)); - } + IFChannelBuffer in_data(kSamplesPer48kHzChannel, kChannels, kNumBands); + IFChannelBuffer out_data(kSamplesPer48kHzChannel, kChannels, kNumBands); for (int i = 0; i < kChunks; ++i) { // Input signal generation. bool is_present[kNumBands]; - memset(in_data.fbuf()->channel(0), + memset(in_data.fbuf()->channels()[0], 0, - kSamplesPer48kHzChannel * sizeof(in_data.fbuf()->channel(0)[0])); + kSamplesPer48kHzChannel * sizeof(in_data.fbuf()->channels()[0][0])); for (int j = 0; j < kNumBands; ++j) { is_present[j] = i & (1 << j); float amplitude = is_present[j] ? kAmplitude : 0; for (int k = 0; k < kSamplesPer48kHzChannel; ++k) { - in_data.fbuf()->channel(0)[k] += + in_data.fbuf()->channels()[0][k] += amplitude * sin(2 * M_PI * kFrequenciesHz[j] * (i * kSamplesPer48kHzChannel + k) / kSampleRateHz); } } // Three band splitting filter. - splitting_filter.Analysis(&in_data, bands.get()); + splitting_filter.Analysis(&in_data, &out_data); // Energy calculation. float energy[kNumBands]; for (int j = 0; j < kNumBands; ++j) { energy[j] = 0; for (int k = 0; k < kSamplesPer16kHzChannel; ++k) { - energy[j] += bands[j]->fbuf_const()->channel(0)[k] * - bands[j]->fbuf_const()->channel(0)[k]; + energy[j] += out_data.fbuf_const()->channels(j)[0][k] * + out_data.fbuf_const()->channels(j)[0][k]; } energy[j] /= kSamplesPer16kHzChannel; if (is_present[j]) { @@ -74,14 +70,14 @@ TEST(SplittingFilterTest, SplitsIntoThreeBandsAndReconstructs) { } } // Three band merge. - splitting_filter.Synthesis(bands.get(), &out_data); + splitting_filter.Synthesis(&out_data, &out_data); // Delay and cross correlation estimation. float xcorr = 0; for (int delay = 0; delay < kSamplesPer48kHzChannel; ++delay) { float tmpcorr = 0; for (int j = delay; j < kSamplesPer48kHzChannel; ++j) { - tmpcorr += in_data.fbuf_const()->channel(0)[j] * - out_data.fbuf_const()->channel(0)[j - delay]; + tmpcorr += in_data.fbuf_const()->channels()[0][j] * + out_data.fbuf_const()->channels()[0][j - delay]; } tmpcorr /= kSamplesPer48kHzChannel; if (tmpcorr > xcorr) { diff --git a/webrtc/modules/audio_processing/test/audio_processing_unittest.cc b/webrtc/modules/audio_processing/test/audio_processing_unittest.cc index d9ebe8eca9..0c907580bc 100644 --- a/webrtc/modules/audio_processing/test/audio_processing_unittest.cc +++ b/webrtc/modules/audio_processing/test/audio_processing_unittest.cc @@ -62,15 +62,17 @@ const size_t kProcessSampleRatesSize = sizeof(kProcessSampleRates) / sizeof(*kProcessSampleRates); void ConvertToFloat(const int16_t* int_data, ChannelBuffer* cb) { - ChannelBuffer cb_int(cb->samples_per_channel(), + ChannelBuffer cb_int(cb->num_frames(), cb->num_channels()); Deinterleave(int_data, - cb->samples_per_channel(), + cb->num_frames(), cb->num_channels(), cb_int.channels()); - S16ToFloat(cb_int.data(), - cb->samples_per_channel() * cb->num_channels(), - cb->data()); + for (int i = 0; i < cb->num_channels(); ++i) { + S16ToFloat(cb_int.channels()[i], + cb->num_frames(), + cb->channels()[i]); + } } void ConvertToFloat(const AudioFrame& frame, ChannelBuffer* cb) { @@ -294,7 +296,7 @@ void OpenFileAndReadMessage(const std::string filename, bool ReadChunk(FILE* file, int16_t* int_data, float* float_data, ChannelBuffer* cb) { // The files always contain stereo audio. - size_t frame_size = cb->samples_per_channel() * 2; + size_t frame_size = cb->num_frames() * 2; size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file); if (read_count != frame_size) { // Check that the file really ended. @@ -304,9 +306,9 @@ bool ReadChunk(FILE* file, int16_t* int_data, float* float_data, S16ToFloat(int_data, frame_size, float_data); if (cb->num_channels() == 1) { - MixStereoToMono(float_data, cb->data(), cb->samples_per_channel()); + MixStereoToMono(float_data, cb->channels()[0], cb->num_frames()); } else { - Deinterleave(float_data, cb->samples_per_channel(), 2, + Deinterleave(float_data, cb->num_frames(), 2, cb->channels()); } @@ -1250,12 +1252,14 @@ TEST_F(ApmTest, AgcOnlyAdaptsWhenTargetSignalIsPresent) { int_data.get(), float_data.get(), &src_buf)); - for (int j = 0; j < kNumInputChannels * kSamplesPerChannel; ++j) { - src_buf.data()[j] *= kScaleFactor; + for (int j = 0; j < kNumInputChannels; ++j) { + for (int k = 0; k < kSamplesPerChannel; ++k) { + src_buf.channels()[j][k] *= kScaleFactor; + } } EXPECT_EQ(kNoErr, apm->ProcessStream(src_buf.channels(), - src_buf.samples_per_channel(), + src_buf.num_frames(), kSampleRateHz, LayoutFromChannels(src_buf.num_channels()), kSampleRateHz, @@ -1273,12 +1277,14 @@ TEST_F(ApmTest, AgcOnlyAdaptsWhenTargetSignalIsPresent) { int_data.get(), float_data.get(), &src_buf)); - for (int j = 0; j < kNumInputChannels * kSamplesPerChannel; ++j) { - src_buf.data()[j] *= kScaleFactor; + for (int j = 0; j < kNumInputChannels; ++j) { + for (int k = 0; k < kSamplesPerChannel; ++k) { + src_buf.channels()[j][k] *= kScaleFactor; + } } EXPECT_EQ(kNoErr, apm->ProcessStream(src_buf.channels(), - src_buf.samples_per_channel(), + src_buf.num_frames(), kSampleRateHz, LayoutFromChannels(src_buf.num_channels()), kSampleRateHz, @@ -1648,7 +1654,8 @@ void ApmTest::ProcessDebugDump(const std::string& in_filename, if (msg.channel_size() > 0) { ASSERT_EQ(revframe_->num_channels_, msg.channel_size()); for (int i = 0; i < msg.channel_size(); ++i) { - memcpy(revfloat_cb_->channel(i), msg.channel(i).data(), + memcpy(revfloat_cb_->channels()[i], + msg.channel(i).data(), msg.channel(i).size()); } } else { @@ -1677,7 +1684,8 @@ void ApmTest::ProcessDebugDump(const std::string& in_filename, if (msg.input_channel_size() > 0) { ASSERT_EQ(frame_->num_channels_, msg.input_channel_size()); for (int i = 0; i < msg.input_channel_size(); ++i) { - memcpy(float_cb_->channel(i), msg.input_channel(i).data(), + memcpy(float_cb_->channels()[i], + msg.input_channel(i).data(), msg.input_channel(i).size()); } } else { @@ -1835,7 +1843,6 @@ TEST_F(ApmTest, FloatAndIntInterfacesGiveSimilarResults) { const int num_output_channels = test->num_output_channels(); const int samples_per_channel = test->sample_rate() * AudioProcessing::kChunkSizeMs / 1000; - const int output_length = samples_per_channel * num_output_channels; Init(test->sample_rate(), test->sample_rate(), test->sample_rate(), num_input_channels, num_output_channels, num_render_channels, true); @@ -1876,11 +1883,13 @@ TEST_F(ApmTest, FloatAndIntInterfacesGiveSimilarResults) { test->sample_rate(), LayoutFromChannels(num_output_channels), float_cb_->channels())); - - FloatToS16(float_cb_->data(), output_length, output_cb.data()); for (int j = 0; j < num_output_channels; ++j) { + FloatToS16(float_cb_->channels()[j], + samples_per_channel, + output_cb.channels()[j]); float variance = 0; - float snr = ComputeSNR(output_int16.channel(j), output_cb.channel(j), + float snr = ComputeSNR(output_int16.channels()[j], + output_cb.channels()[j], samples_per_channel, &variance); #if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE) // There are a few chunks in the fixed-point profile that give low SNR. @@ -2171,7 +2180,7 @@ TEST_F(ApmTest, NoErrorsWithKeyboardChannel) { for (int j = 0; j < 10; ++j) { EXPECT_NOERR(ap->ProcessStream( in_cb.channels(), - in_cb.samples_per_channel(), + in_cb.num_frames(), in_rate, cf[i].in_layout, out_rate, @@ -2313,9 +2322,9 @@ class AudioProcessingTest // Temporary buffers. const int max_length = - 2 * std::max(out_cb.samples_per_channel(), - std::max(fwd_cb.samples_per_channel(), - rev_cb.samples_per_channel())); + 2 * std::max(out_cb.num_frames(), + std::max(fwd_cb.num_frames(), + rev_cb.num_frames())); scoped_ptr float_data(new float[max_length]); scoped_ptr int_data(new int16_t[max_length]); @@ -2324,7 +2333,7 @@ class AudioProcessingTest ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) { EXPECT_NOERR(ap->AnalyzeReverseStream( rev_cb.channels(), - rev_cb.samples_per_channel(), + rev_cb.num_frames(), reverse_rate, LayoutFromChannels(num_reverse_channels))); @@ -2334,7 +2343,7 @@ class AudioProcessingTest EXPECT_NOERR(ap->ProcessStream( fwd_cb.channels(), - fwd_cb.samples_per_channel(), + fwd_cb.num_frames(), input_rate, LayoutFromChannels(num_input_channels), output_rate, @@ -2342,13 +2351,14 @@ class AudioProcessingTest out_cb.channels())); Interleave(out_cb.channels(), - out_cb.samples_per_channel(), + out_cb.num_frames(), out_cb.num_channels(), float_data.get()); // Dump output to file. - ASSERT_EQ(static_cast(out_cb.length()), + int out_length = out_cb.num_channels() * out_cb.num_frames(); + ASSERT_EQ(static_cast(out_length), fwrite(float_data.get(), sizeof(float_data[0]), - out_cb.length(), out_file)); + out_length, out_file)); analog_level = ap->gain_control()->stream_analog_level(); } diff --git a/webrtc/modules/audio_processing/test/audioproc_float.cc b/webrtc/modules/audio_processing/test/audioproc_float.cc index bbac9f1c91..e1418e97c8 100644 --- a/webrtc/modules/audio_processing/test/audioproc_float.cc +++ b/webrtc/modules/audio_processing/test/audioproc_float.cc @@ -177,27 +177,30 @@ int main(int argc, char* argv[]) { ChannelBuffer o_buf(o_file.sample_rate() / kChunksPerSecond, o_file.num_channels()); - const size_t c_length = static_cast(c_buf.length()); + const size_t c_length = + static_cast(c_buf.num_channels() * c_buf.num_frames()); + const size_t o_length = + static_cast(o_buf.num_channels() * o_buf.num_frames()); scoped_ptr c_interleaved(new float[c_length]); - scoped_ptr o_interleaved(new float[o_buf.length()]); + scoped_ptr o_interleaved(new float[o_length]); while (c_file.ReadSamples(c_length, c_interleaved.get()) == c_length) { FloatS16ToFloat(c_interleaved.get(), c_length, c_interleaved.get()); - Deinterleave(c_interleaved.get(), c_buf.samples_per_channel(), + Deinterleave(c_interleaved.get(), c_buf.num_frames(), c_buf.num_channels(), c_buf.channels()); CHECK_EQ(kNoErr, ap->ProcessStream(c_buf.channels(), - c_buf.samples_per_channel(), + c_buf.num_frames(), c_file.sample_rate(), LayoutFromChannels(c_buf.num_channels()), o_file.sample_rate(), LayoutFromChannels(o_buf.num_channels()), o_buf.channels())); - Interleave(o_buf.channels(), o_buf.samples_per_channel(), + Interleave(o_buf.channels(), o_buf.num_frames(), o_buf.num_channels(), o_interleaved.get()); - FloatToFloatS16(o_interleaved.get(), o_buf.length(), o_interleaved.get()); - o_file.WriteSamples(o_interleaved.get(), o_buf.length()); + FloatToFloatS16(o_interleaved.get(), o_length, o_interleaved.get()); + o_file.WriteSamples(o_interleaved.get(), o_length); } return 0; diff --git a/webrtc/modules/audio_processing/test/process_test.cc b/webrtc/modules/audio_processing/test/process_test.cc index 3af495c19b..d1fa032a44 100644 --- a/webrtc/modules/audio_processing/test/process_test.cc +++ b/webrtc/modules/audio_processing/test/process_test.cc @@ -654,7 +654,10 @@ void void_main(int argc, char* argv[]) { memcpy(far_frame.data_, msg.data().data(), msg.data().size()); } else { for (int i = 0; i < msg.channel_size(); ++i) { - reverse_cb->CopyFrom(msg.channel(i).data(), i); + memcpy(reverse_cb->channels()[i], + msg.channel(i).data(), + reverse_cb->num_frames() * + sizeof(reverse_cb->channels()[i][0])); } } @@ -704,7 +707,10 @@ void void_main(int argc, char* argv[]) { near_read_bytes += msg.input_data().size(); } else { for (int i = 0; i < msg.input_channel_size(); ++i) { - primary_cb->CopyFrom(msg.input_channel(i).data(), i); + memcpy(primary_cb->channels()[i], + msg.input_channel(i).data(), + primary_cb->num_frames() * + sizeof(primary_cb->channels()[i][0])); near_read_bytes += msg.input_channel(i).size(); } } diff --git a/webrtc/modules/audio_processing/voice_detection_impl.cc b/webrtc/modules/audio_processing/voice_detection_impl.cc index 31336b41df..da51a10ab1 100644 --- a/webrtc/modules/audio_processing/voice_detection_impl.cc +++ b/webrtc/modules/audio_processing/voice_detection_impl.cc @@ -59,7 +59,7 @@ int VoiceDetectionImpl::ProcessCaptureAudio(AudioBuffer* audio) { using_external_vad_ = false; return apm_->kNoError; } - assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_frames_per_band() <= 160); // TODO(ajm): concatenate data in frame buffer here.