blob: 8d26f52495e572d10e6f96d525ebf4db4546d248 [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);
kwiberg@webrtc.orgd2f366f2014-04-17 12:17:39 +000028 for (int i = 0; i < samples_per_channel; i++)
29 out[i] = (static_cast<int32_t>(left[i]) +
30 static_cast<int32_t>(right[i])) >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +000031}
32} // namespace
33
34struct AudioChannel {
35 AudioChannel() {
36 memset(data, 0, sizeof(data));
37 }
38
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000039 int16_t data[kSamplesPer32kHzChannel];
niklase@google.com470e71d2011-07-07 08:21:25 +000040};
41
42struct SplitAudioChannel {
43 SplitAudioChannel() {
44 memset(low_pass_data, 0, sizeof(low_pass_data));
45 memset(high_pass_data, 0, sizeof(high_pass_data));
46 memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1));
47 memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2));
48 memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1));
49 memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2));
50 }
51
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000052 int16_t low_pass_data[kSamplesPer16kHzChannel];
53 int16_t high_pass_data[kSamplesPer16kHzChannel];
niklase@google.com470e71d2011-07-07 08:21:25 +000054
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +000055 int32_t analysis_filter_state1[6];
56 int32_t analysis_filter_state2[6];
57 int32_t synthesis_filter_state1[6];
58 int32_t synthesis_filter_state2[6];
niklase@google.com470e71d2011-07-07 08:21:25 +000059};
60
andrew@webrtc.orged083d42011-09-19 15:28:51 +000061// TODO(andrew): check range of input parameters?
62AudioBuffer::AudioBuffer(int max_num_channels,
63 int samples_per_channel)
64 : max_num_channels_(max_num_channels),
65 num_channels_(0),
66 num_mixed_channels_(0),
67 num_mixed_low_pass_channels_(0),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000068 data_was_mixed_(false),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000069 samples_per_channel_(samples_per_channel),
70 samples_per_split_channel_(samples_per_channel),
71 reference_copied_(false),
72 activity_(AudioFrame::kVadUnknown),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000073 is_muted_(false),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000074 data_(NULL),
75 channels_(NULL),
76 split_channels_(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000077 mixed_channels_(NULL),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000078 mixed_low_pass_channels_(NULL),
79 low_pass_reference_channels_(NULL) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +000080 channels_.reset(new AudioChannel[max_num_channels_]);
81 mixed_channels_.reset(new AudioChannel[max_num_channels_]);
82 mixed_low_pass_channels_.reset(new AudioChannel[max_num_channels_]);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000083 low_pass_reference_channels_.reset(new AudioChannel[max_num_channels_]);
niklase@google.com470e71d2011-07-07 08:21:25 +000084
85 if (samples_per_channel_ == kSamplesPer32kHzChannel) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000086 split_channels_.reset(new SplitAudioChannel[max_num_channels_]);
niklase@google.com470e71d2011-07-07 08:21:25 +000087 samples_per_split_channel_ = kSamplesPer16kHzChannel;
88 }
89}
90
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000091AudioBuffer::~AudioBuffer() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000092
andrew@webrtc.org17e40642014-03-04 20:58:13 +000093void AudioBuffer::InitForNewData(int num_channels) {
94 num_channels_ = num_channels;
95 data_ = NULL;
96 data_was_mixed_ = false;
97 num_mixed_channels_ = 0;
98 num_mixed_low_pass_channels_ = 0;
99 reference_copied_ = false;
100 activity_ = AudioFrame::kVadUnknown;
101 is_muted_ = false;
102}
103
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000104int16_t* AudioBuffer::data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000105 assert(channel >= 0 && channel < num_channels_);
106 if (data_ != NULL) {
107 return data_;
108 }
109
110 return channels_[channel].data;
111}
112
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000113int16_t* AudioBuffer::low_pass_split_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000114 assert(channel >= 0 && channel < num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000115 if (split_channels_.get() == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 return data(channel);
117 }
118
119 return split_channels_[channel].low_pass_data;
120}
121
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000122int16_t* AudioBuffer::high_pass_split_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000123 assert(channel >= 0 && channel < num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000124 if (split_channels_.get() == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000125 return NULL;
126 }
127
128 return split_channels_[channel].high_pass_data;
129}
130
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000131int16_t* AudioBuffer::mixed_data(int channel) const {
132 assert(channel >= 0 && channel < num_mixed_channels_);
133
134 return mixed_channels_[channel].data;
135}
136
137int16_t* AudioBuffer::mixed_low_pass_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 assert(channel >= 0 && channel < num_mixed_low_pass_channels_);
139
140 return mixed_low_pass_channels_[channel].data;
141}
142
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000143int16_t* AudioBuffer::low_pass_reference(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000144 assert(channel >= 0 && channel < num_channels_);
145 if (!reference_copied_) {
146 return NULL;
147 }
148
149 return low_pass_reference_channels_[channel].data;
150}
151
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000152int32_t* AudioBuffer::analysis_filter_state1(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 assert(channel >= 0 && channel < num_channels_);
154 return split_channels_[channel].analysis_filter_state1;
155}
156
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000157int32_t* AudioBuffer::analysis_filter_state2(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 assert(channel >= 0 && channel < num_channels_);
159 return split_channels_[channel].analysis_filter_state2;
160}
161
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000162int32_t* AudioBuffer::synthesis_filter_state1(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000163 assert(channel >= 0 && channel < num_channels_);
164 return split_channels_[channel].synthesis_filter_state1;
165}
166
pbos@webrtc.orgb7192b82013-04-10 07:50:54 +0000167int32_t* AudioBuffer::synthesis_filter_state2(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 assert(channel >= 0 && channel < num_channels_);
169 return split_channels_[channel].synthesis_filter_state2;
170}
171
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000172void AudioBuffer::set_activity(AudioFrame::VADActivity activity) {
173 activity_ = activity;
174}
175
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000176AudioFrame::VADActivity AudioBuffer::activity() const {
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000177 return activity_;
178}
179
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000180bool AudioBuffer::is_muted() const {
181 return is_muted_;
182}
183
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000184int AudioBuffer::num_channels() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 return num_channels_;
186}
187
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000188int AudioBuffer::samples_per_channel() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 return samples_per_channel_;
190}
191
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000192int AudioBuffer::samples_per_split_channel() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 return samples_per_split_channel_;
194}
195
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000196// TODO(andrew): Do deinterleaving and mixing in one step?
197void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000198 assert(frame->num_channels_ <= max_num_channels_);
199 assert(frame->samples_per_channel_ == samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000200
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000201 InitForNewData(frame->num_channels_);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000202 activity_ = frame->vad_activity_;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000203 if (frame->energy_ == 0) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000204 is_muted_ = true;
205 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000206
207 if (num_channels_ == 1) {
208 // We can get away with a pointer assignment in this case.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000209 data_ = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000210 return;
211 }
212
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000213 int16_t* interleaved = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 for (int i = 0; i < num_channels_; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000215 int16_t* deinterleaved = channels_[i].data;
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000216 int interleaved_idx = i;
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 for (int j = 0; j < samples_per_channel_; j++) {
218 deinterleaved[j] = interleaved[interleaved_idx];
219 interleaved_idx += num_channels_;
220 }
221 }
222}
223
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000224void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) const {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000225 assert(frame->num_channels_ == num_channels_);
226 assert(frame->samples_per_channel_ == samples_per_channel_);
227 frame->vad_activity_ = activity_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000229 if (!data_changed) {
230 return;
231 }
232
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 if (num_channels_ == 1) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000234 if (data_was_mixed_) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000235 memcpy(frame->data_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 channels_[0].data,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000237 sizeof(int16_t) * samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000238 } else {
239 // These should point to the same buffer in this case.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000240 assert(data_ == frame->data_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000241 }
242
243 return;
244 }
245
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000246 int16_t* interleaved = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 for (int i = 0; i < num_channels_; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000248 int16_t* deinterleaved = channels_[i].data;
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000249 int interleaved_idx = i;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 for (int j = 0; j < samples_per_channel_; j++) {
251 interleaved[interleaved_idx] = deinterleaved[j];
252 interleaved_idx += num_channels_;
253 }
254 }
255}
256
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000257void AudioBuffer::CopyFrom(const float* const* data, int samples_per_channel,
258 int num_channels) {
259 assert(num_channels <= max_num_channels_);
260 assert(samples_per_channel == samples_per_channel_);
261
262 InitForNewData(num_channels);
263 for (int i = 0; i < num_channels_; ++i) {
264 ScaleAndRoundToInt16(data[i], samples_per_channel, channels_[i].data);
265 }
266}
267
268void AudioBuffer::CopyTo(int samples_per_channel, int num_channels,
269 float* const* data) const {
270 assert(num_channels == num_channels_);
271 assert(samples_per_channel == samples_per_channel_);
272 for (int i = 0; i < num_channels_; ++i) {
273 ScaleToFloat(channels_[i].data, samples_per_channel, data[i]);
274 }
275}
276
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000277// TODO(andrew): would be good to support the no-mix case with pointer
278// assignment.
279// TODO(andrew): handle mixing to multiple channels?
280void AudioBuffer::Mix(int num_mixed_channels) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 // We currently only support the stereo to mono case.
282 assert(num_channels_ == 2);
283 assert(num_mixed_channels == 1);
284
285 StereoToMono(channels_[0].data,
286 channels_[1].data,
287 channels_[0].data,
288 samples_per_channel_);
289
290 num_channels_ = num_mixed_channels;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000291 data_was_mixed_ = true;
292}
293
294void AudioBuffer::CopyAndMix(int num_mixed_channels) {
295 // We currently only support the stereo to mono case.
296 assert(num_channels_ == 2);
297 assert(num_mixed_channels == 1);
298
299 StereoToMono(channels_[0].data,
300 channels_[1].data,
301 mixed_channels_[0].data,
302 samples_per_channel_);
303
niklase@google.com470e71d2011-07-07 08:21:25 +0000304 num_mixed_channels_ = num_mixed_channels;
305}
306
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000307void AudioBuffer::CopyAndMixLowPass(int num_mixed_channels) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000308 // We currently only support the stereo to mono case.
309 assert(num_channels_ == 2);
310 assert(num_mixed_channels == 1);
311
312 StereoToMono(low_pass_split_data(0),
313 low_pass_split_data(1),
314 mixed_low_pass_channels_[0].data,
315 samples_per_split_channel_);
316
317 num_mixed_low_pass_channels_ = num_mixed_channels;
318}
319
320void AudioBuffer::CopyLowPassToReference() {
321 reference_copied_ = true;
322 for (int i = 0; i < num_channels_; i++) {
323 memcpy(low_pass_reference_channels_[i].data,
324 low_pass_split_data(i),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000325 sizeof(int16_t) * samples_per_split_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 }
327}
328} // namespace webrtc