blob: aee9f68cd2d66a554531fbb74d3971a6f555c9c1 [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
11#include "audio_buffer.h"
12
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000013#include "signal_processing_library.h"
14
niklase@google.com470e71d2011-07-07 08:21:25 +000015namespace webrtc {
16namespace {
17
18enum {
19 kSamplesPer8kHzChannel = 80,
20 kSamplesPer16kHzChannel = 160,
21 kSamplesPer32kHzChannel = 320
22};
23
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000024void 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);
niklase@google.com470e71d2011-07-07 08:21:25 +000027 for (int i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000028 int32_t data32 = (static_cast<int32_t>(left[i]) +
29 static_cast<int32_t>(right[i])) >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +000030
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000031 out[i] = WebRtcSpl_SatW32ToW16(data32);
niklase@google.com470e71d2011-07-07 08:21:25 +000032 }
33}
34} // namespace
35
36struct AudioChannel {
37 AudioChannel() {
38 memset(data, 0, sizeof(data));
39 }
40
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000041 int16_t data[kSamplesPer32kHzChannel];
niklase@google.com470e71d2011-07-07 08:21:25 +000042};
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
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000054 int16_t low_pass_data[kSamplesPer16kHzChannel];
55 int16_t high_pass_data[kSamplesPer16kHzChannel];
niklase@google.com470e71d2011-07-07 08:21:25 +000056
57 WebRtc_Word32 analysis_filter_state1[6];
58 WebRtc_Word32 analysis_filter_state2[6];
59 WebRtc_Word32 synthesis_filter_state1[6];
60 WebRtc_Word32 synthesis_filter_state2[6];
61};
62
andrew@webrtc.orged083d42011-09-19 15:28:51 +000063// 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),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000070 data_was_mixed_(false),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000071 samples_per_channel_(samples_per_channel),
72 samples_per_split_channel_(samples_per_channel),
73 reference_copied_(false),
74 activity_(AudioFrame::kVadUnknown),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000075 is_muted_(false),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000076 data_(NULL),
77 channels_(NULL),
78 split_channels_(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000079 mixed_channels_(NULL),
andrew@webrtc.orged083d42011-09-19 15:28:51 +000080 mixed_low_pass_channels_(NULL),
81 low_pass_reference_channels_(NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +000082 if (max_num_channels_ > 1) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +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_]);
niklase@google.com470e71d2011-07-07 08:21:25 +000086 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000087 low_pass_reference_channels_.reset(new AudioChannel[max_num_channels_]);
niklase@google.com470e71d2011-07-07 08:21:25 +000088
89 if (samples_per_channel_ == kSamplesPer32kHzChannel) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000090 split_channels_.reset(new SplitAudioChannel[max_num_channels_]);
niklase@google.com470e71d2011-07-07 08:21:25 +000091 samples_per_split_channel_ = kSamplesPer16kHzChannel;
92 }
93}
94
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000095AudioBuffer::~AudioBuffer() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000096
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000097int16_t* AudioBuffer::data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +000098 assert(channel >= 0 && channel < num_channels_);
99 if (data_ != NULL) {
100 return data_;
101 }
102
103 return channels_[channel].data;
104}
105
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000106int16_t* AudioBuffer::low_pass_split_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 assert(channel >= 0 && channel < num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000108 if (split_channels_.get() == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000109 return data(channel);
110 }
111
112 return split_channels_[channel].low_pass_data;
113}
114
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000115int16_t* AudioBuffer::high_pass_split_data(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 assert(channel >= 0 && channel < num_channels_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000117 if (split_channels_.get() == NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 return NULL;
119 }
120
121 return split_channels_[channel].high_pass_data;
122}
123
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000124int16_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 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 assert(channel >= 0 && channel < num_mixed_low_pass_channels_);
132
133 return mixed_low_pass_channels_[channel].data;
134}
135
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000136int16_t* AudioBuffer::low_pass_reference(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 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
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000145WebRtc_Word32* AudioBuffer::analysis_filter_state1(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000146 assert(channel >= 0 && channel < num_channels_);
147 return split_channels_[channel].analysis_filter_state1;
148}
149
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000150WebRtc_Word32* AudioBuffer::analysis_filter_state2(int channel) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 assert(channel >= 0 && channel < num_channels_);
152 return split_channels_[channel].analysis_filter_state2;
153}
154
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000155WebRtc_Word32* AudioBuffer::synthesis_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].synthesis_filter_state1;
158}
159
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000160WebRtc_Word32* AudioBuffer::synthesis_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].synthesis_filter_state2;
163}
164
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000165void AudioBuffer::set_activity(AudioFrame::VADActivity activity) {
166 activity_ = activity;
167}
168
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000169AudioFrame::VADActivity AudioBuffer::activity() const {
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000170 return activity_;
171}
172
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000173bool AudioBuffer::is_muted() const {
174 return is_muted_;
175}
176
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000177int AudioBuffer::num_channels() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 return num_channels_;
179}
180
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000181int AudioBuffer::samples_per_channel() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 return samples_per_channel_;
183}
184
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000185int AudioBuffer::samples_per_split_channel() const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000186 return samples_per_split_channel_;
187}
188
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000189// TODO(andrew): Do deinterleaving and mixing in one step?
190void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000191 assert(frame->num_channels_ <= max_num_channels_);
192 assert(frame->samples_per_channel_ == samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000193
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000194 num_channels_ = frame->num_channels_;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000195 data_was_mixed_ = false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 num_mixed_channels_ = 0;
197 num_mixed_low_pass_channels_ = 0;
198 reference_copied_ = false;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000199 activity_ = frame->vad_activity_;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000200 is_muted_ = false;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000201 if (frame->energy_ == 0) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000202 is_muted_ = true;
203 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000204
205 if (num_channels_ == 1) {
206 // We can get away with a pointer assignment in this case.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000207 data_ = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000208 return;
209 }
210
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000211 int16_t* interleaved = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 for (int i = 0; i < num_channels_; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000213 int16_t* deinterleaved = channels_[i].data;
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000214 int interleaved_idx = i;
niklase@google.com470e71d2011-07-07 08:21:25 +0000215 for (int j = 0; j < samples_per_channel_; j++) {
216 deinterleaved[j] = interleaved[interleaved_idx];
217 interleaved_idx += num_channels_;
218 }
219 }
220}
221
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000222void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) const {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000223 assert(frame->num_channels_ == num_channels_);
224 assert(frame->samples_per_channel_ == samples_per_channel_);
225 frame->vad_activity_ = activity_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000227 if (!data_changed) {
228 return;
229 }
230
niklase@google.com470e71d2011-07-07 08:21:25 +0000231 if (num_channels_ == 1) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000232 if (data_was_mixed_) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000233 memcpy(frame->data_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000234 channels_[0].data,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000235 sizeof(int16_t) * samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 } else {
237 // These should point to the same buffer in this case.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000238 assert(data_ == frame->data_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 }
240
241 return;
242 }
243
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000244 int16_t* interleaved = frame->data_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 for (int i = 0; i < num_channels_; i++) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000246 int16_t* deinterleaved = channels_[i].data;
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000247 int interleaved_idx = i;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 for (int j = 0; j < samples_per_channel_; j++) {
249 interleaved[interleaved_idx] = deinterleaved[j];
250 interleaved_idx += num_channels_;
251 }
252 }
253}
254
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000255// 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) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000259 // 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;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000269 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
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 num_mixed_channels_ = num_mixed_channels;
283}
284
andrew@webrtc.orged083d42011-09-19 15:28:51 +0000285void AudioBuffer::CopyAndMixLowPass(int num_mixed_channels) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 // 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),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000303 sizeof(int16_t) * samples_per_split_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000304 }
305}
306} // namespace webrtc