Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: webrtc/modules/audio_processing/audio_buffer.cc

Issue 1226093007: Allow more than 2 input channels in AudioProcessing. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fix mac build Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/modules/audio_processing/audio_buffer.h" 11 #include "webrtc/modules/audio_processing/audio_buffer.h"
12 12
13 #include "webrtc/common_audio/include/audio_util.h" 13 #include "webrtc/common_audio/include/audio_util.h"
14 #include "webrtc/common_audio/resampler/push_sinc_resampler.h" 14 #include "webrtc/common_audio/resampler/push_sinc_resampler.h"
15 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar y.h" 15 #include "webrtc/common_audio/signal_processing/include/signal_processing_librar y.h"
16 #include "webrtc/common_audio/channel_buffer.h" 16 #include "webrtc/common_audio/channel_buffer.h"
17 #include "webrtc/modules/audio_processing/common.h" 17 #include "webrtc/modules/audio_processing/common.h"
18 18
19 namespace webrtc { 19 namespace webrtc {
20 namespace { 20 namespace {
21 21
22 const int kSamplesPer16kHzChannel = 160; 22 const int kSamplesPer16kHzChannel = 160;
23 const int kSamplesPer32kHzChannel = 320; 23 const int kSamplesPer32kHzChannel = 320;
24 const int kSamplesPer48kHzChannel = 480; 24 const int kSamplesPer48kHzChannel = 480;
25 25
26 bool HasKeyboardChannel(AudioProcessing::ChannelLayout layout) { 26 int KeyboardChannelIndex(const StreamConfig& stream_config) {
aluebs-webrtc 2015/07/14 23:12:42 You could check inside here if stream_config.has_k
mgraczyk 2015/07/15 01:12:45 Done, although the only callsite is conditional on
27 switch (layout) { 27 switch (stream_config.num_channels()) {
28 case AudioProcessing::kMono: 28 case 1:
29 case AudioProcessing::kStereo:
30 return false;
31 case AudioProcessing::kMonoAndKeyboard:
32 case AudioProcessing::kStereoAndKeyboard:
33 return true;
34 }
35 assert(false);
36 return false;
37 }
38
39 int KeyboardChannelIndex(AudioProcessing::ChannelLayout layout) {
40 switch (layout) {
41 case AudioProcessing::kMono:
42 case AudioProcessing::kStereo:
43 assert(false);
44 return -1;
45 case AudioProcessing::kMonoAndKeyboard:
46 return 1; 29 return 1;
47 case AudioProcessing::kStereoAndKeyboard: 30 case 2:
48 return 2; 31 return 2;
49 } 32 }
50 assert(false); 33 assert(false);
51 return -1; 34 return -1;
52 } 35 }
53 36
54 template <typename T> 37 template <typename T>
55 void StereoToMono(const T* left, const T* right, T* out, 38 void DownmixInterleavedToMono(const T* interleaved,
aluebs-webrtc 2015/07/14 23:12:42 Is this specialization used anywhere?
mgraczyk 2015/07/15 01:12:46 This isn't the specialization, it's a normal templ
aluebs-webrtc 2015/07/15 18:04:05 I meant, I don't think we have any interleaved flo
mgraczyk 2015/07/15 20:03:19 That's true. I removed the definition so now the
56 int num_frames) { 39 T* deinterleaved,
57 for (int i = 0; i < num_frames; ++i) 40 int num_multichannel_frames,
58 out[i] = (left[i] + right[i]) / 2; 41 int num_channels) {
aluebs-webrtc 2015/07/14 23:12:42 Inputs before outputs?
mgraczyk 2015/07/15 01:12:45 Done.
42 return DownmixInterleavedToMonoImpl<T, T>(
aluebs-webrtc 2015/07/14 23:12:42 This return isn't needed, right?
mgraczyk 2015/07/15 01:12:45 Done.
43 interleaved, deinterleaved, num_multichannel_frames, num_channels);
44 }
45
46 template <>
aluebs-webrtc 2015/07/14 23:12:42 Why is this template needed? Just curious.
mgraczyk 2015/07/15 01:12:46 I could write a function called "DownmixInterleave
aluebs-webrtc 2015/07/15 18:04:05 Thanks for the explanation! Makes sense :)
47 void DownmixInterleavedToMono<int16_t>(const int16_t* interleaved,
48 int16_t* deinterleaved,
49 int num_multichannel_frames,
50 int num_channels) {
51 return DownmixInterleavedToMonoImpl<int16_t, int32_t>(
aluebs-webrtc 2015/07/14 23:12:42 This return isn't needed, right?
mgraczyk 2015/07/15 01:12:45 Done.
52 interleaved, deinterleaved, num_multichannel_frames, num_channels);
59 } 53 }
60 54
61 int NumBandsFromSamplesPerChannel(int num_frames) { 55 int NumBandsFromSamplesPerChannel(int num_frames) {
62 int num_bands = 1; 56 int num_bands = 1;
63 if (num_frames == kSamplesPer32kHzChannel || 57 if (num_frames == kSamplesPer32kHzChannel ||
64 num_frames == kSamplesPer48kHzChannel) { 58 num_frames == kSamplesPer48kHzChannel) {
65 num_bands = rtc::CheckedDivExact(num_frames, 59 num_bands = rtc::CheckedDivExact(num_frames,
66 static_cast<int>(kSamplesPer16kHzChannel)); 60 static_cast<int>(kSamplesPer16kHzChannel));
67 } 61 }
68 return num_bands; 62 return num_bands;
(...skipping 15 matching lines...) Expand all
84 num_bands_(NumBandsFromSamplesPerChannel(proc_num_frames_)), 78 num_bands_(NumBandsFromSamplesPerChannel(proc_num_frames_)),
85 num_split_frames_(rtc::CheckedDivExact(proc_num_frames_, num_bands_)), 79 num_split_frames_(rtc::CheckedDivExact(proc_num_frames_, num_bands_)),
86 mixed_low_pass_valid_(false), 80 mixed_low_pass_valid_(false),
87 reference_copied_(false), 81 reference_copied_(false),
88 activity_(AudioFrame::kVadUnknown), 82 activity_(AudioFrame::kVadUnknown),
89 keyboard_data_(NULL), 83 keyboard_data_(NULL),
90 data_(new IFChannelBuffer(proc_num_frames_, num_proc_channels_)) { 84 data_(new IFChannelBuffer(proc_num_frames_, num_proc_channels_)) {
91 assert(input_num_frames_ > 0); 85 assert(input_num_frames_ > 0);
92 assert(proc_num_frames_ > 0); 86 assert(proc_num_frames_ > 0);
93 assert(output_num_frames_ > 0); 87 assert(output_num_frames_ > 0);
94 assert(num_input_channels_ > 0 && num_input_channels_ <= 2); 88 assert(num_input_channels_ > 0);
95 assert(num_proc_channels_ > 0 && num_proc_channels_ <= num_input_channels_); 89 assert(num_proc_channels_ > 0 && num_proc_channels_ <= num_input_channels_);
96 90
97 if (input_num_frames_ != proc_num_frames_ || 91 if (input_num_frames_ != proc_num_frames_ ||
98 output_num_frames_ != proc_num_frames_) { 92 output_num_frames_ != proc_num_frames_) {
99 // Create an intermediate buffer for resampling. 93 // Create an intermediate buffer for resampling.
100 process_buffer_.reset(new ChannelBuffer<float>(proc_num_frames_, 94 process_buffer_.reset(new ChannelBuffer<float>(proc_num_frames_,
101 num_proc_channels_)); 95 num_proc_channels_));
102 96
103 if (input_num_frames_ != proc_num_frames_) { 97 if (input_num_frames_ != proc_num_frames_) {
104 for (int i = 0; i < num_proc_channels_; ++i) { 98 for (int i = 0; i < num_proc_channels_; ++i) {
(...skipping 18 matching lines...) Expand all
123 num_bands_)); 117 num_bands_));
124 splitting_filter_.reset(new SplittingFilter(num_proc_channels_, 118 splitting_filter_.reset(new SplittingFilter(num_proc_channels_,
125 num_bands_, 119 num_bands_,
126 proc_num_frames_)); 120 proc_num_frames_));
127 } 121 }
128 } 122 }
129 123
130 AudioBuffer::~AudioBuffer() {} 124 AudioBuffer::~AudioBuffer() {}
131 125
132 void AudioBuffer::CopyFrom(const float* const* data, 126 void AudioBuffer::CopyFrom(const float* const* data,
133 int num_frames, 127 const StreamConfig& stream_config) {
134 AudioProcessing::ChannelLayout layout) { 128 assert(stream_config.samples_per_channel() == input_num_frames_);
135 assert(num_frames == input_num_frames_); 129 assert(stream_config.num_channels() == num_input_channels_);
136 assert(ChannelsFromLayout(layout) == num_input_channels_);
137 InitForNewData(); 130 InitForNewData();
138 // Initialized lazily because there's a different condition in 131 // Initialized lazily because there's a different condition in
139 // DeinterleaveFrom. 132 // DeinterleaveFrom.
140 if ((num_input_channels_ == 2 && num_proc_channels_ == 1) && !input_buffer_) { 133 const bool need_to_downmix =
134 num_input_channels_ > 1 && num_proc_channels_ == 1;
135 if (need_to_downmix && !input_buffer_) {
141 input_buffer_.reset( 136 input_buffer_.reset(
142 new IFChannelBuffer(input_num_frames_, num_proc_channels_)); 137 new IFChannelBuffer(input_num_frames_, num_proc_channels_));
143 } 138 }
144 139
145 if (HasKeyboardChannel(layout)) { 140 if (stream_config.has_keyboard()) {
146 keyboard_data_ = data[KeyboardChannelIndex(layout)]; 141 keyboard_data_ = data[KeyboardChannelIndex(stream_config)];
147 } 142 }
148 143
149 // Downmix. 144 // Downmix.
150 const float* const* data_ptr = data; 145 const float* const* data_ptr = data;
151 if (num_input_channels_ == 2 && num_proc_channels_ == 1) { 146 if (need_to_downmix) {
152 StereoToMono(data[0], 147 DownmixToMono<float, float>(input_num_frames_,
153 data[1], 148 input_buffer_->fbuf()->channels()[0], data,
154 input_buffer_->fbuf()->channels()[0], 149 num_input_channels_);
155 input_num_frames_);
156 data_ptr = input_buffer_->fbuf_const()->channels(); 150 data_ptr = input_buffer_->fbuf_const()->channels();
157 } 151 }
158 152
159 // Resample. 153 // Resample.
160 if (input_num_frames_ != proc_num_frames_) { 154 if (input_num_frames_ != proc_num_frames_) {
161 for (int i = 0; i < num_proc_channels_; ++i) { 155 for (int i = 0; i < num_proc_channels_; ++i) {
162 input_resamplers_[i]->Resample(data_ptr[i], 156 input_resamplers_[i]->Resample(data_ptr[i],
163 input_num_frames_, 157 input_num_frames_,
164 process_buffer_->channels()[i], 158 process_buffer_->channels()[i],
165 proc_num_frames_); 159 proc_num_frames_);
166 } 160 }
167 data_ptr = process_buffer_->channels(); 161 data_ptr = process_buffer_->channels();
168 } 162 }
169 163
170 // Convert to the S16 range. 164 // Convert to the S16 range.
171 for (int i = 0; i < num_proc_channels_; ++i) { 165 for (int i = 0; i < num_proc_channels_; ++i) {
172 FloatToFloatS16(data_ptr[i], 166 FloatToFloatS16(data_ptr[i],
173 proc_num_frames_, 167 proc_num_frames_,
174 data_->fbuf()->channels()[i]); 168 data_->fbuf()->channels()[i]);
175 } 169 }
176 } 170 }
177 171
178 void AudioBuffer::CopyTo(int num_frames, 172 void AudioBuffer::CopyTo(const StreamConfig& stream_config,
179 AudioProcessing::ChannelLayout layout,
180 float* const* data) { 173 float* const* data) {
181 assert(num_frames == output_num_frames_); 174 assert(stream_config.samples_per_channel() == output_num_frames_);
182 assert(ChannelsFromLayout(layout) == num_channels_); 175 assert(stream_config.num_channels() == num_channels_);
183 176
184 // Convert to the float range. 177 // Convert to the float range.
185 float* const* data_ptr = data; 178 float* const* data_ptr = data;
186 if (output_num_frames_ != proc_num_frames_) { 179 if (output_num_frames_ != proc_num_frames_) {
187 // Convert to an intermediate buffer for subsequent resampling. 180 // Convert to an intermediate buffer for subsequent resampling.
188 data_ptr = process_buffer_->channels(); 181 data_ptr = process_buffer_->channels();
189 } 182 }
190 for (int i = 0; i < num_channels_; ++i) { 183 for (int i = 0; i < num_channels_; ++i) {
191 FloatS16ToFloat(data_->fbuf()->channels()[i], 184 FloatS16ToFloat(data_->fbuf()->channels()[i],
192 proc_num_frames_, 185 proc_num_frames_,
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 325
333 if (num_proc_channels_ == 1) { 326 if (num_proc_channels_ == 1) {
334 return split_bands_const(0)[kBand0To8kHz]; 327 return split_bands_const(0)[kBand0To8kHz];
335 } 328 }
336 329
337 if (!mixed_low_pass_valid_) { 330 if (!mixed_low_pass_valid_) {
338 if (!mixed_low_pass_channels_.get()) { 331 if (!mixed_low_pass_channels_.get()) {
339 mixed_low_pass_channels_.reset( 332 mixed_low_pass_channels_.reset(
340 new ChannelBuffer<int16_t>(num_split_frames_, 1)); 333 new ChannelBuffer<int16_t>(num_split_frames_, 1));
341 } 334 }
342 StereoToMono(split_bands_const(0)[kBand0To8kHz], 335 DownmixStereoToMono<int16_t, int32_t>(
aluebs-webrtc 2015/07/14 23:12:42 Shouldn't this support multiple channels?
mgraczyk 2015/07/15 01:12:46 Done. Does this work?
aluebs-webrtc 2015/07/15 18:04:05 You don't need to do this manually, audio_buffer/c
mgraczyk 2015/07/15 20:03:19 Nice, Done.
343 split_bands_const(1)[kBand0To8kHz], 336 num_split_frames_, mixed_low_pass_channels_->channels()[0],
344 mixed_low_pass_channels_->channels()[0], 337 split_bands_const(0)[kBand0To8kHz], split_bands_const(1)[kBand0To8kHz]);
345 num_split_frames_);
346 mixed_low_pass_valid_ = true; 338 mixed_low_pass_valid_ = true;
347 } 339 }
348 return mixed_low_pass_channels_->channels()[0]; 340 return mixed_low_pass_channels_->channels()[0];
349 } 341 }
350 342
351 const int16_t* AudioBuffer::low_pass_reference(int channel) const { 343 const int16_t* AudioBuffer::low_pass_reference(int channel) const {
352 if (!reference_copied_) { 344 if (!reference_copied_) {
353 return NULL; 345 return NULL;
354 } 346 }
355 347
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 new IFChannelBuffer(input_num_frames_, num_proc_channels_)); 396 new IFChannelBuffer(input_num_frames_, num_proc_channels_));
405 } 397 }
406 activity_ = frame->vad_activity_; 398 activity_ = frame->vad_activity_;
407 399
408 int16_t* const* deinterleaved; 400 int16_t* const* deinterleaved;
409 if (input_num_frames_ == proc_num_frames_) { 401 if (input_num_frames_ == proc_num_frames_) {
410 deinterleaved = data_->ibuf()->channels(); 402 deinterleaved = data_->ibuf()->channels();
411 } else { 403 } else {
412 deinterleaved = input_buffer_->ibuf()->channels(); 404 deinterleaved = input_buffer_->ibuf()->channels();
413 } 405 }
414 if (num_input_channels_ == 2 && num_proc_channels_ == 1) { 406 if (num_proc_channels_ == 1) {
mgraczyk 2015/07/15 01:12:46 This function works for any number of input channe
415 // Downmix directly; no explicit deinterleaving needed. 407 // Downmix and deinterleave simultaneously.
416 for (int i = 0; i < input_num_frames_; ++i) { 408 DownmixInterleavedToMono(frame->data_, deinterleaved[0], input_num_frames_,
417 deinterleaved[0][i] = (frame->data_[i * 2] + frame->data_[i * 2 + 1]) / 2; 409 num_input_channels_);
418 }
419 } else { 410 } else {
420 assert(num_proc_channels_ == num_input_channels_); 411 assert(num_proc_channels_ == num_input_channels_);
421 Deinterleave(frame->data_, 412 Deinterleave(frame->data_,
422 input_num_frames_, 413 input_num_frames_,
423 num_proc_channels_, 414 num_proc_channels_,
424 deinterleaved); 415 deinterleaved);
425 } 416 }
426 417
427 // Resample. 418 // Resample.
428 if (input_num_frames_ != proc_num_frames_) { 419 if (input_num_frames_ != proc_num_frames_) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 461
471 void AudioBuffer::SplitIntoFrequencyBands() { 462 void AudioBuffer::SplitIntoFrequencyBands() {
472 splitting_filter_->Analysis(data_.get(), split_data_.get()); 463 splitting_filter_->Analysis(data_.get(), split_data_.get());
473 } 464 }
474 465
475 void AudioBuffer::MergeFrequencyBands() { 466 void AudioBuffer::MergeFrequencyBands() {
476 splitting_filter_->Synthesis(split_data_.get(), data_.get()); 467 splitting_filter_->Synthesis(split_data_.get(), data_.get());
477 } 468 }
478 469
479 } // namespace webrtc 470 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698