1 /*
2 * Copyright (c) 2011 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
11 #include "audio_buffer.h"
12
13 #include "module_common_types.h"
14
15 namespace webrtc {
16 namespace {
17
18 enum {
19 kSamplesPer8kHzChannel = 80,
20 kSamplesPer16kHzChannel = 160,
21 kSamplesPer32kHzChannel = 320
22 };
23
StereoToMono(const WebRtc_Word16 * left,const WebRtc_Word16 * right,WebRtc_Word16 * out,int samples_per_channel)24 void StereoToMono(const WebRtc_Word16* left, const WebRtc_Word16* right,
25 WebRtc_Word16* out, int samples_per_channel) {
26 WebRtc_Word32 data_int32 = 0;
27 for (int i = 0; i < samples_per_channel; i++) {
28 data_int32 = (left[i] + right[i]) >> 1;
29 if (data_int32 > 32767) {
30 data_int32 = 32767;
31 } else if (data_int32 < -32768) {
32 data_int32 = -32768;
33 }
34
35 out[i] = static_cast<WebRtc_Word16>(data_int32);
36 }
37 }
38 } // namespace
39
40 struct AudioChannel {
AudioChannelwebrtc::AudioChannel41 AudioChannel() {
42 memset(data, 0, sizeof(data));
43 }
44
45 WebRtc_Word16 data[kSamplesPer32kHzChannel];
46 };
47
48 struct SplitAudioChannel {
SplitAudioChannelwebrtc::SplitAudioChannel49 SplitAudioChannel() {
50 memset(low_pass_data, 0, sizeof(low_pass_data));
51 memset(high_pass_data, 0, sizeof(high_pass_data));
52 memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1));
53 memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2));
54 memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1));
55 memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2));
56 }
57
58 WebRtc_Word16 low_pass_data[kSamplesPer16kHzChannel];
59 WebRtc_Word16 high_pass_data[kSamplesPer16kHzChannel];
60
61 WebRtc_Word32 analysis_filter_state1[6];
62 WebRtc_Word32 analysis_filter_state2[6];
63 WebRtc_Word32 synthesis_filter_state1[6];
64 WebRtc_Word32 synthesis_filter_state2[6];
65 };
66
67 // TODO(am): check range of input parameters?
AudioBuffer(WebRtc_Word32 max_num_channels,WebRtc_Word32 samples_per_channel)68 AudioBuffer::AudioBuffer(WebRtc_Word32 max_num_channels,
69 WebRtc_Word32 samples_per_channel)
70 : max_num_channels_(max_num_channels),
71 num_channels_(0),
72 num_mixed_channels_(0),
73 num_mixed_low_pass_channels_(0),
74 samples_per_channel_(samples_per_channel),
75 samples_per_split_channel_(samples_per_channel),
76 reference_copied_(false),
77 data_(NULL),
78 channels_(NULL),
79 split_channels_(NULL),
80 mixed_low_pass_channels_(NULL),
81 low_pass_reference_channels_(NULL) {
82 if (max_num_channels_ > 1) {
83 channels_ = new AudioChannel[max_num_channels_];
84 mixed_low_pass_channels_ = new AudioChannel[max_num_channels_];
85 }
86 low_pass_reference_channels_ = new AudioChannel[max_num_channels_];
87
88 if (samples_per_channel_ == kSamplesPer32kHzChannel) {
89 split_channels_ = new SplitAudioChannel[max_num_channels_];
90 samples_per_split_channel_ = kSamplesPer16kHzChannel;
91 }
92 }
93
~AudioBuffer()94 AudioBuffer::~AudioBuffer() {
95 if (channels_ != NULL) {
96 delete [] channels_;
97 }
98
99 if (mixed_low_pass_channels_ != NULL) {
100 delete [] mixed_low_pass_channels_;
101 }
102
103 if (low_pass_reference_channels_ != NULL) {
104 delete [] low_pass_reference_channels_;
105 }
106
107 if (split_channels_ != NULL) {
108 delete [] split_channels_;
109 }
110 }
111
data(WebRtc_Word32 channel) const112 WebRtc_Word16* AudioBuffer::data(WebRtc_Word32 channel) const {
113 assert(channel >= 0 && channel < num_channels_);
114 if (data_ != NULL) {
115 return data_;
116 }
117
118 return channels_[channel].data;
119 }
120
low_pass_split_data(WebRtc_Word32 channel) const121 WebRtc_Word16* AudioBuffer::low_pass_split_data(WebRtc_Word32 channel) const {
122 assert(channel >= 0 && channel < num_channels_);
123 if (split_channels_ == NULL) {
124 return data(channel);
125 }
126
127 return split_channels_[channel].low_pass_data;
128 }
129
high_pass_split_data(WebRtc_Word32 channel) const130 WebRtc_Word16* AudioBuffer::high_pass_split_data(WebRtc_Word32 channel) const {
131 assert(channel >= 0 && channel < num_channels_);
132 if (split_channels_ == NULL) {
133 return NULL;
134 }
135
136 return split_channels_[channel].high_pass_data;
137 }
138
mixed_low_pass_data(WebRtc_Word32 channel) const139 WebRtc_Word16* AudioBuffer::mixed_low_pass_data(WebRtc_Word32 channel) const {
140 assert(channel >= 0 && channel < num_mixed_low_pass_channels_);
141
142 return mixed_low_pass_channels_[channel].data;
143 }
144
low_pass_reference(WebRtc_Word32 channel) const145 WebRtc_Word16* AudioBuffer::low_pass_reference(WebRtc_Word32 channel) const {
146 assert(channel >= 0 && channel < num_channels_);
147 if (!reference_copied_) {
148 return NULL;
149 }
150
151 return low_pass_reference_channels_[channel].data;
152 }
153
analysis_filter_state1(WebRtc_Word32 channel) const154 WebRtc_Word32* AudioBuffer::analysis_filter_state1(WebRtc_Word32 channel) const {
155 assert(channel >= 0 && channel < num_channels_);
156 return split_channels_[channel].analysis_filter_state1;
157 }
158
analysis_filter_state2(WebRtc_Word32 channel) const159 WebRtc_Word32* AudioBuffer::analysis_filter_state2(WebRtc_Word32 channel) const {
160 assert(channel >= 0 && channel < num_channels_);
161 return split_channels_[channel].analysis_filter_state2;
162 }
163
synthesis_filter_state1(WebRtc_Word32 channel) const164 WebRtc_Word32* AudioBuffer::synthesis_filter_state1(WebRtc_Word32 channel) const {
165 assert(channel >= 0 && channel < num_channels_);
166 return split_channels_[channel].synthesis_filter_state1;
167 }
168
synthesis_filter_state2(WebRtc_Word32 channel) const169 WebRtc_Word32* AudioBuffer::synthesis_filter_state2(WebRtc_Word32 channel) const {
170 assert(channel >= 0 && channel < num_channels_);
171 return split_channels_[channel].synthesis_filter_state2;
172 }
173
num_channels() const174 WebRtc_Word32 AudioBuffer::num_channels() const {
175 return num_channels_;
176 }
177
samples_per_channel() const178 WebRtc_Word32 AudioBuffer::samples_per_channel() const {
179 return samples_per_channel_;
180 }
181
samples_per_split_channel() const182 WebRtc_Word32 AudioBuffer::samples_per_split_channel() const {
183 return samples_per_split_channel_;
184 }
185
186 // TODO(ajm): Do deinterleaving and mixing in one step?
DeinterleaveFrom(AudioFrame * audioFrame)187 void AudioBuffer::DeinterleaveFrom(AudioFrame* audioFrame) {
188 assert(audioFrame->_audioChannel <= max_num_channels_);
189 assert(audioFrame->_payloadDataLengthInSamples == samples_per_channel_);
190
191 num_channels_ = audioFrame->_audioChannel;
192 num_mixed_channels_ = 0;
193 num_mixed_low_pass_channels_ = 0;
194 reference_copied_ = false;
195
196 if (num_channels_ == 1) {
197 // We can get away with a pointer assignment in this case.
198 data_ = audioFrame->_payloadData;
199 return;
200 }
201
202 for (int i = 0; i < num_channels_; i++) {
203 WebRtc_Word16* deinterleaved = channels_[i].data;
204 WebRtc_Word16* interleaved = audioFrame->_payloadData;
205 WebRtc_Word32 interleaved_idx = i;
206 for (int j = 0; j < samples_per_channel_; j++) {
207 deinterleaved[j] = interleaved[interleaved_idx];
208 interleaved_idx += num_channels_;
209 }
210 }
211 }
212
InterleaveTo(AudioFrame * audioFrame) const213 void AudioBuffer::InterleaveTo(AudioFrame* audioFrame) const {
214 assert(audioFrame->_audioChannel == num_channels_);
215 assert(audioFrame->_payloadDataLengthInSamples == samples_per_channel_);
216
217 if (num_channels_ == 1) {
218 if (num_mixed_channels_ == 1) {
219 memcpy(audioFrame->_payloadData,
220 channels_[0].data,
221 sizeof(WebRtc_Word16) * samples_per_channel_);
222 } else {
223 // These should point to the same buffer in this case.
224 assert(data_ == audioFrame->_payloadData);
225 }
226
227 return;
228 }
229
230 for (int i = 0; i < num_channels_; i++) {
231 WebRtc_Word16* deinterleaved = channels_[i].data;
232 WebRtc_Word16* interleaved = audioFrame->_payloadData;
233 WebRtc_Word32 interleaved_idx = i;
234 for (int j = 0; j < samples_per_channel_; j++) {
235 interleaved[interleaved_idx] = deinterleaved[j];
236 interleaved_idx += num_channels_;
237 }
238 }
239 }
240
241 // TODO(ajm): would be good to support the no-mix case with pointer assignment.
242 // TODO(ajm): handle mixing to multiple channels?
Mix(WebRtc_Word32 num_mixed_channels)243 void AudioBuffer::Mix(WebRtc_Word32 num_mixed_channels) {
244 // We currently only support the stereo to mono case.
245 assert(num_channels_ == 2);
246 assert(num_mixed_channels == 1);
247
248 StereoToMono(channels_[0].data,
249 channels_[1].data,
250 channels_[0].data,
251 samples_per_channel_);
252
253 num_channels_ = num_mixed_channels;
254 num_mixed_channels_ = num_mixed_channels;
255 }
256
CopyAndMixLowPass(WebRtc_Word32 num_mixed_channels)257 void AudioBuffer::CopyAndMixLowPass(WebRtc_Word32 num_mixed_channels) {
258 // We currently only support the stereo to mono case.
259 assert(num_channels_ == 2);
260 assert(num_mixed_channels == 1);
261
262 StereoToMono(low_pass_split_data(0),
263 low_pass_split_data(1),
264 mixed_low_pass_channels_[0].data,
265 samples_per_split_channel_);
266
267 num_mixed_low_pass_channels_ = num_mixed_channels;
268 }
269
CopyLowPassToReference()270 void AudioBuffer::CopyLowPassToReference() {
271 reference_copied_ = true;
272 for (int i = 0; i < num_channels_; i++) {
273 memcpy(low_pass_reference_channels_[i].data,
274 low_pass_split_data(i),
275 sizeof(WebRtc_Word16) * samples_per_split_channel_);
276 }
277 }
278 } // namespace webrtc
279