blob: 048d048723e2d525f66954b309f5f07424c738b4 [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.org9fb16132013-05-28 08:11:59 +000011#include "webrtc/modules/audio_processing/audio_buffer.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
pbos@webrtc.org9fb16132013-05-28 08:11:59 +000013#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000014
15namespace webrtc {
16namespace {
17
18enum {
19 kSamplesPer8kHzChannel = 80,
20 kSamplesPer16kHzChannel = 160,
21 kSamplesPer32kHzChannel = 320
22};
23
24void StereoToMono(const int16_t* left, const int16_t* right,
25 int16_t* out, int samples_per_channel) {
26 assert(left != NULL && right != NULL && out != NULL);
27 for (int i = 0; i < samples_per_channel; i++) {
28 int32_t data32 = (static_cast<int32_t>(left[i]) +
29 static_cast<int32_t>(right[i])) >> 1;
30
31 out[i] = WebRtcSpl_SatW32ToW16(data32);
32 }
33}
34} // namespace
35
36struct AudioChannel {
37 AudioChannel() {
38 memset(data, 0, sizeof(data));
39 }
40
41 int16_t data[kSamplesPer32kHzChannel];
42};
43
44struct SplitAudioChannel {
45 SplitAudioChannel() {
46 memset(low_pass_data, 0, sizeof(low_pass_data));
47 memset(high_pass_data, 0, sizeof(high_pass_data));
48 memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1));
49 memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2));
50 memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1));
51 memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2));
52 }
53
54 int16_t low_pass_data[kSamplesPer16kHzChannel];
55 int16_t high_pass_data[kSamplesPer16kHzChannel];
56
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +000057 int32_t analysis_filter_state1[6];
58 int32_t analysis_filter_state2[6];
59 int32_t synthesis_filter_state1[6];
60 int32_t synthesis_filter_state2[6];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000061};
62
63// TODO(andrew): check range of input parameters?
64AudioBuffer::AudioBuffer(int max_num_channels,
65 int samples_per_channel)
66 : max_num_channels_(max_num_channels),
67 num_channels_(0),
68 num_mixed_channels_(0),
69 num_mixed_low_pass_channels_(0),
70 data_was_mixed_(false),
71 samples_per_channel_(samples_per_channel),
72 samples_per_split_channel_(samples_per_channel),
73 reference_copied_(false),
74 activity_(AudioFrame::kVadUnknown),
75 is_muted_(false),
76 data_(NULL),
77 channels_(NULL),
78 split_channels_(NULL),
79 mixed_channels_(NULL),
80 mixed_low_pass_channels_(NULL),
81 low_pass_reference_channels_(NULL) {
82 if (max_num_channels_ > 1) {
83 channels_.reset(new AudioChannel[max_num_channels_]);
84 mixed_channels_.reset(new AudioChannel[max_num_channels_]);
85 mixed_low_pass_channels_.reset(new AudioChannel[max_num_channels_]);
86 }
87 low_pass_reference_channels_.reset(new AudioChannel[max_num_channels_]);
88
89 if (samples_per_channel_ == kSamplesPer32kHzChannel) {
90 split_channels_.reset(new SplitAudioChannel[max_num_channels_]);
91 samples_per_split_channel_ = kSamplesPer16kHzChannel;
92 }
93}
94
95AudioBuffer::~AudioBuffer() {}
96
97int16_t* AudioBuffer::data(int channel) const {
98 assert(channel >= 0 && channel < num_channels_);
99 if (data_ != NULL) {
100 return data_;
101 }
102
103 return channels_[channel].data;
104}
105
106int16_t* AudioBuffer::low_pass_split_data(int channel) const {
107 assert(channel >= 0 && channel < num_channels_);
108 if (split_channels_.get() == NULL) {
109 return data(channel);
110 }
111
112 return split_channels_[channel].low_pass_data;
113}
114
115int16_t* AudioBuffer::high_pass_split_data(int channel) const {
116 assert(channel >= 0 && channel < num_channels_);
117 if (split_channels_.get() == NULL) {
118 return NULL;
119 }
120
121 return split_channels_[channel].high_pass_data;
122}
123
124int16_t* AudioBuffer::mixed_data(int channel) const {
125 assert(channel >= 0 && channel < num_mixed_channels_);
126
127 return mixed_channels_[channel].data;
128}
129
130int16_t* AudioBuffer::mixed_low_pass_data(int channel) const {
131 assert(channel >= 0 && channel < num_mixed_low_pass_channels_);
132
133 return mixed_low_pass_channels_[channel].data;
134}
135
136int16_t* AudioBuffer::low_pass_reference(int channel) const {
137 assert(channel >= 0 && channel < num_channels_);
138 if (!reference_copied_) {
139 return NULL;
140 }
141
142 return low_pass_reference_channels_[channel].data;
143}
144
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000145int32_t* AudioBuffer::analysis_filter_state1(int channel) const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000146 assert(channel >= 0 && channel < num_channels_);
147 return split_channels_[channel].analysis_filter_state1;
148}
149
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000150int32_t* AudioBuffer::analysis_filter_state2(int channel) const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000151 assert(channel >= 0 && channel < num_channels_);
152 return split_channels_[channel].analysis_filter_state2;
153}
154
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000155int32_t* AudioBuffer::synthesis_filter_state1(int channel) const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000156 assert(channel >= 0 && channel < num_channels_);
157 return split_channels_[channel].synthesis_filter_state1;
158}
159
pbos@webrtc.org3f6d5e02013-04-10 07:50:54 +0000160int32_t* AudioBuffer::synthesis_filter_state2(int channel) const {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000161 assert(channel >= 0 && channel < num_channels_);
162 return split_channels_[channel].synthesis_filter_state2;
163}
164
165void AudioBuffer::set_activity(AudioFrame::VADActivity activity) {
166 activity_ = activity;
167}
168
169AudioFrame::VADActivity AudioBuffer::activity() const {
170 return activity_;
171}
172
173bool AudioBuffer::is_muted() const {
174 return is_muted_;
175}
176
177int AudioBuffer::num_channels() const {
178 return num_channels_;
179}
180
181int AudioBuffer::samples_per_channel() const {
182 return samples_per_channel_;
183}
184
185int AudioBuffer::samples_per_split_channel() const {
186 return samples_per_split_channel_;
187}
188
189// TODO(andrew): Do deinterleaving and mixing in one step?
190void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) {
191 assert(frame->num_channels_ <= max_num_channels_);
192 assert(frame->samples_per_channel_ == samples_per_channel_);
193
194 num_channels_ = frame->num_channels_;
195 data_was_mixed_ = false;
196 num_mixed_channels_ = 0;
197 num_mixed_low_pass_channels_ = 0;
198 reference_copied_ = false;
199 activity_ = frame->vad_activity_;
200 is_muted_ = false;
201 if (frame->energy_ == 0) {
202 is_muted_ = true;
203 }
204
205 if (num_channels_ == 1) {
206 // We can get away with a pointer assignment in this case.
207 data_ = frame->data_;
208 return;
209 }
210
211 int16_t* interleaved = frame->data_;
212 for (int i = 0; i < num_channels_; i++) {
213 int16_t* deinterleaved = channels_[i].data;
214 int interleaved_idx = i;
215 for (int j = 0; j < samples_per_channel_; j++) {
216 deinterleaved[j] = interleaved[interleaved_idx];
217 interleaved_idx += num_channels_;
218 }
219 }
220}
221
222void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) const {
223 assert(frame->num_channels_ == num_channels_);
224 assert(frame->samples_per_channel_ == samples_per_channel_);
225 frame->vad_activity_ = activity_;
226
227 if (!data_changed) {
228 return;
229 }
230
231 if (num_channels_ == 1) {
232 if (data_was_mixed_) {
233 memcpy(frame->data_,
234 channels_[0].data,
235 sizeof(int16_t) * samples_per_channel_);
236 } else {
237 // These should point to the same buffer in this case.
238 assert(data_ == frame->data_);
239 }
240
241 return;
242 }
243
244 int16_t* interleaved = frame->data_;
245 for (int i = 0; i < num_channels_; i++) {
246 int16_t* deinterleaved = channels_[i].data;
247 int interleaved_idx = i;
248 for (int j = 0; j < samples_per_channel_; j++) {
249 interleaved[interleaved_idx] = deinterleaved[j];
250 interleaved_idx += num_channels_;
251 }
252 }
253}
254
255// TODO(andrew): would be good to support the no-mix case with pointer
256// assignment.
257// TODO(andrew): handle mixing to multiple channels?
258void AudioBuffer::Mix(int num_mixed_channels) {
259 // We currently only support the stereo to mono case.
260 assert(num_channels_ == 2);
261 assert(num_mixed_channels == 1);
262
263 StereoToMono(channels_[0].data,
264 channels_[1].data,
265 channels_[0].data,
266 samples_per_channel_);
267
268 num_channels_ = num_mixed_channels;
269 data_was_mixed_ = true;
270}
271
272void AudioBuffer::CopyAndMix(int num_mixed_channels) {
273 // We currently only support the stereo to mono case.
274 assert(num_channels_ == 2);
275 assert(num_mixed_channels == 1);
276
277 StereoToMono(channels_[0].data,
278 channels_[1].data,
279 mixed_channels_[0].data,
280 samples_per_channel_);
281
282 num_mixed_channels_ = num_mixed_channels;
283}
284
285void AudioBuffer::CopyAndMixLowPass(int num_mixed_channels) {
286 // We currently only support the stereo to mono case.
287 assert(num_channels_ == 2);
288 assert(num_mixed_channels == 1);
289
290 StereoToMono(low_pass_split_data(0),
291 low_pass_split_data(1),
292 mixed_low_pass_channels_[0].data,
293 samples_per_split_channel_);
294
295 num_mixed_low_pass_channels_ = num_mixed_channels;
296}
297
298void AudioBuffer::CopyLowPassToReference() {
299 reference_copied_ = true;
300 for (int i = 0; i < num_channels_; i++) {
301 memcpy(low_pass_reference_channels_[i].data,
302 low_pass_split_data(i),
303 sizeof(int16_t) * samples_per_split_channel_);
304 }
305}
306} // namespace webrtc