blob: 90824770b77a58def1fdc37a2e5eda3c01c441c6 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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.org7fad4b82013-05-28 08:11:59 +000011#include "webrtc/modules/audio_processing/audio_buffer.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
andrew@webrtc.org17e40642014-03-04 20:58:13 +000013#include "webrtc/common_audio/include/audio_util.h"
pbos@webrtc.org7fad4b82013-05-28 08:11:59 +000014#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000015
niklase@google.com470e71d2011-07-07 08:21:25 +000016namespace webrtc {
17namespace {
18
19enum {
20 kSamplesPer8kHzChannel = 80,
21 kSamplesPer16kHzChannel = 160,
22 kSamplesPer32kHzChannel = 320
23};
24
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000025void StereoToMono(const int16_t* left, const int16_t* right,
26 int16_t* out, int samples_per_channel) {
27 assert(left != NULL && right != NULL && out != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000028 for (int i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000029 int32_t data32 = (static_cast<int32_t>(left[i]) +
30 static_cast<int32_t>(right[i])) >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +000031
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000032 out[i] = WebRtcSpl_SatW32ToW16(data32);
niklase@google.com470e71d2011-07-07 08:21:25 +000033 }
34}
35} // namespace
36
37struct AudioChannel {
38 AudioChannel() {
39 memset(data, 0, sizeof(data));
40 }
41
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000042 int16_t data[kSamplesPer32kHzChannel];
niklase@google.com470e71d2011-07-07 08:21:25 +000043};
44
45struct SplitAudioChannel {
46 SplitAudioChannel() {
47 memset(low_pass_data, 0, sizeof(low_pass_data));
48 memset(high_pass_data, 0, sizeof(high_pass_data));
49 memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1));
50 memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2));
51 memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1));
52 memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2));
53 }
54
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000055 int16_t low_pass_data[kSamplesPer16kHzChannel];
56 int16_t high_pass_data[kSamplesPer16kHzChannel];
niklase@google.com470e71d2011-07-07 08:21:25 +000057
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000058 int32_t analysis_filter_state1[6];
59 int32_t analysis_filter_state2[6];
60 int32_t synthesis_filter_state1[6];
61 int32_t synthesis_filter_state2[6];
niklase@google.com470e71d2011-07-07 08:21:25 +000062};
63
andrew@webrtc.orged083d42011-09-19 15:28:51 +000064// TODO(andrew): check range of input parameters?
65AudioBuffer::AudioBuffer(int max_num_channels,
66 int samples_per_channel)
67 : max_num_channels_(max_num_channels),
68 num_channels_(0),
69 num_mixed_channels_(0),
70 num_mixed_low_pass_channels_(0),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000071 data_was_mixed_(false),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000072 samples_per_channel_(samples_per_channel),
73 samples_per_split_channel_(samples_per_channel),
74 reference_copied_(false),
75 activity_(AudioFrame::kVadUnknown),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000076 is_muted_(false),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000077 data_(NULL),
78 channels_(NULL),
79 split_channels_(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000080 mixed_channels_(NULL),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000081 mixed_low_pass_channels_(NULL),
82 low_pass_reference_channels_(NULL) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +000083 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_]);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000086 low_pass_reference_channels_.reset(new AudioChannel[max_num_channels_]);
niklase@google.com470e71d2011-07-07 08:21:25 +000087
88 if (samples_per_channel_ == kSamplesPer32kHzChannel) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000089 split_channels_.reset(new SplitAudioChannel[max_num_channels_]);
niklase@google.com470e71d2011-07-07 08:21:25 +000090 samples_per_split_channel_ = kSamplesPer16kHzChannel;
91 }
92}
93
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000094AudioBuffer::~AudioBuffer() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000095
andrew@webrtc.org17e40642014-03-04 20:58:13 +000096void AudioBuffer::InitForNewData(int num_channels) {
97 num_channels_ = num_channels;
98 data_ = NULL;
99 data_was_mixed_ = false;
100 num_mixed_channels_ = 0;
101 num_mixed_low_pass_channels_ = 0;
102 reference_copied_ = false;
103 activity_ = AudioFrame::kVadUnknown;
104 is_muted_ = false;
105}
106
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000107int16_t* AudioBuffer::data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 assert(channel >= 0 && channel < num_channels_);
109 if (data_ != NULL) {
110 return data_;
111 }
112
113 return channels_[channel].data;
114}
115
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000116int16_t* AudioBuffer::low_pass_split_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 assert(channel >= 0 && channel < num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000118 if (split_channels_.get() == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000119 return data(channel);
120 }
121
122 return split_channels_[channel].low_pass_data;
123}
124
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000125int16_t* AudioBuffer::high_pass_split_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000126 assert(channel >= 0 && channel < num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000127 if (split_channels_.get() == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000128 return NULL;
129 }
130
131 return split_channels_[channel].high_pass_data;
132}
133
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000134int16_t* AudioBuffer::mixed_data(int channel) const {
135 assert(channel >= 0 && channel < num_mixed_channels_);
136
137 return mixed_channels_[channel].data;
138}
139
140int16_t* AudioBuffer::mixed_low_pass_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 assert(channel >= 0 && channel < num_mixed_low_pass_channels_);
142
143 return mixed_low_pass_channels_[channel].data;
144}
145
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000146int16_t* AudioBuffer::low_pass_reference(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000147 assert(channel >= 0 && channel < num_channels_);
148 if (!reference_copied_) {
149 return NULL;
150 }
151
152 return low_pass_reference_channels_[channel].data;
153}
154
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000155int32_t* AudioBuffer::analysis_filter_state1(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 assert(channel >= 0 && channel < num_channels_);
157 return split_channels_[channel].analysis_filter_state1;
158}
159
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000160int32_t* AudioBuffer::analysis_filter_state2(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000161 assert(channel >= 0 && channel < num_channels_);
162 return split_channels_[channel].analysis_filter_state2;
163}
164
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000165int32_t* AudioBuffer::synthesis_filter_state1(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 assert(channel >= 0 && channel < num_channels_);
167 return split_channels_[channel].synthesis_filter_state1;
168}
169
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000170int32_t* AudioBuffer::synthesis_filter_state2(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 assert(channel >= 0 && channel < num_channels_);
172 return split_channels_[channel].synthesis_filter_state2;
173}
174
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000175void AudioBuffer::set_activity(AudioFrame::VADActivity activity) {
176 activity_ = activity;
177}
178
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000179AudioFrame::VADActivity AudioBuffer::activity() const {
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000180 return activity_;
181}
182
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000183bool AudioBuffer::is_muted() const {
184 return is_muted_;
185}
186
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000187int AudioBuffer::num_channels() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 return num_channels_;
189}
190
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000191int AudioBuffer::samples_per_channel() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 return samples_per_channel_;
193}
194
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000195int AudioBuffer::samples_per_split_channel() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 return samples_per_split_channel_;
197}
198
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000199// TODO(andrew): Do deinterleaving and mixing in one step?
200void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000201 assert(frame->num_channels_ <= max_num_channels_);
202 assert(frame->samples_per_channel_ == samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000203
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000204 InitForNewData(frame->num_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000205 activity_ = frame->vad_activity_;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000206 if (frame->energy_ == 0) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000207 is_muted_ = true;
208 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000209
210 if (num_channels_ == 1) {
211 // We can get away with a pointer assignment in this case.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000212 data_ = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 return;
214 }
215
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000216 int16_t* interleaved = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 for (int i = 0; i < num_channels_; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000218 int16_t* deinterleaved = channels_[i].data;
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000219 int interleaved_idx = i;
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 for (int j = 0; j < samples_per_channel_; j++) {
221 deinterleaved[j] = interleaved[interleaved_idx];
222 interleaved_idx += num_channels_;
223 }
224 }
225}
226
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000227void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) const {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000228 assert(frame->num_channels_ == num_channels_);
229 assert(frame->samples_per_channel_ == samples_per_channel_);
230 frame->vad_activity_ = activity_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000231
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000232 if (!data_changed) {
233 return;
234 }
235
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 if (num_channels_ == 1) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000237 if (data_was_mixed_) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000238 memcpy(frame->data_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 channels_[0].data,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000240 sizeof(int16_t) * samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000241 } else {
242 // These should point to the same buffer in this case.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000243 assert(data_ == frame->data_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000244 }
245
246 return;
247 }
248
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000249 int16_t* interleaved = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 for (int i = 0; i < num_channels_; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000251 int16_t* deinterleaved = channels_[i].data;
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000252 int interleaved_idx = i;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 for (int j = 0; j < samples_per_channel_; j++) {
254 interleaved[interleaved_idx] = deinterleaved[j];
255 interleaved_idx += num_channels_;
256 }
257 }
258}
259
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000260void AudioBuffer::CopyFrom(const float* const* data, int samples_per_channel,
261 int num_channels) {
262 assert(num_channels <= max_num_channels_);
263 assert(samples_per_channel == samples_per_channel_);
264
265 InitForNewData(num_channels);
266 for (int i = 0; i < num_channels_; ++i) {
267 ScaleAndRoundToInt16(data[i], samples_per_channel, channels_[i].data);
268 }
269}
270
271void AudioBuffer::CopyTo(int samples_per_channel, int num_channels,
272 float* const* data) const {
273 assert(num_channels == num_channels_);
274 assert(samples_per_channel == samples_per_channel_);
275 for (int i = 0; i < num_channels_; ++i) {
276 ScaleToFloat(channels_[i].data, samples_per_channel, data[i]);
277 }
278}
279
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000280// TODO(andrew): would be good to support the no-mix case with pointer
281// assignment.
282// TODO(andrew): handle mixing to multiple channels?
283void AudioBuffer::Mix(int num_mixed_channels) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 // We currently only support the stereo to mono case.
285 assert(num_channels_ == 2);
286 assert(num_mixed_channels == 1);
287
288 StereoToMono(channels_[0].data,
289 channels_[1].data,
290 channels_[0].data,
291 samples_per_channel_);
292
293 num_channels_ = num_mixed_channels;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000294 data_was_mixed_ = true;
295}
296
297void AudioBuffer::CopyAndMix(int num_mixed_channels) {
298 // We currently only support the stereo to mono case.
299 assert(num_channels_ == 2);
300 assert(num_mixed_channels == 1);
301
302 StereoToMono(channels_[0].data,
303 channels_[1].data,
304 mixed_channels_[0].data,
305 samples_per_channel_);
306
niklase@google.com470e71d2011-07-07 08:21:25 +0000307 num_mixed_channels_ = num_mixed_channels;
308}
309
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000310void AudioBuffer::CopyAndMixLowPass(int num_mixed_channels) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000311 // We currently only support the stereo to mono case.
312 assert(num_channels_ == 2);
313 assert(num_mixed_channels == 1);
314
315 StereoToMono(low_pass_split_data(0),
316 low_pass_split_data(1),
317 mixed_low_pass_channels_[0].data,
318 samples_per_split_channel_);
319
320 num_mixed_low_pass_channels_ = num_mixed_channels;
321}
322
323void AudioBuffer::CopyLowPassToReference() {
324 reference_copied_ = true;
325 for (int i = 0; i < num_channels_; i++) {
326 memcpy(low_pass_reference_channels_[i].data,
327 low_pass_split_data(i),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000328 sizeof(int16_t) * samples_per_split_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000329 }
330}
331} // namespace webrtc