blob: 24ccfb386431bc8c2e1a581e71141418a5212125 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org02d71742012-04-24 19:47:00 +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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "audio/utility/audio_frame_operations.h"
aleloi6321b492016-12-05 01:46:09 -080012
13#include <algorithm>
14
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "modules/include/module_common_types.h"
16#include "rtc_base/checks.h"
17#include "rtc_base/safe_conversions.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018
19namespace webrtc {
aleloi6321b492016-12-05 01:46:09 -080020namespace {
solenberg1c2af8e2016-03-24 10:36:00 -070021
22// 2.7ms @ 48kHz, 4ms @ 32kHz, 8ms @ 16kHz.
23const size_t kMuteFadeFrames = 128;
24const float kMuteFadeInc = 1.0f / kMuteFadeFrames;
25
aleloi6321b492016-12-05 01:46:09 -080026} // namespace
27
28void AudioFrameOperations::Add(const AudioFrame& frame_to_add,
29 AudioFrame* result_frame) {
30 // Sanity check.
31 RTC_DCHECK(result_frame);
32 RTC_DCHECK_GT(result_frame->num_channels_, 0);
33 RTC_DCHECK_EQ(result_frame->num_channels_, frame_to_add.num_channels_);
34
yujo36b1a5f2017-06-12 12:45:32 -070035 bool no_previous_data = result_frame->muted();
aleloi6321b492016-12-05 01:46:09 -080036 if (result_frame->samples_per_channel_ != frame_to_add.samples_per_channel_) {
37 // Special case we have no data to start with.
38 RTC_DCHECK_EQ(result_frame->samples_per_channel_, 0);
39 result_frame->samples_per_channel_ = frame_to_add.samples_per_channel_;
40 no_previous_data = true;
41 }
42
43 if (result_frame->vad_activity_ == AudioFrame::kVadActive ||
44 frame_to_add.vad_activity_ == AudioFrame::kVadActive) {
45 result_frame->vad_activity_ = AudioFrame::kVadActive;
46 } else if (result_frame->vad_activity_ == AudioFrame::kVadUnknown ||
47 frame_to_add.vad_activity_ == AudioFrame::kVadUnknown) {
48 result_frame->vad_activity_ = AudioFrame::kVadUnknown;
49 }
50
51 if (result_frame->speech_type_ != frame_to_add.speech_type_)
52 result_frame->speech_type_ = AudioFrame::kUndefined;
53
yujo36b1a5f2017-06-12 12:45:32 -070054 if (!frame_to_add.muted()) {
55 const int16_t* in_data = frame_to_add.data();
56 int16_t* out_data = result_frame->mutable_data();
57 size_t length =
58 frame_to_add.samples_per_channel_ * frame_to_add.num_channels_;
59 if (no_previous_data) {
60 std::copy(in_data, in_data + length, out_data);
61 } else {
62 for (size_t i = 0; i < length; i++) {
63 const int32_t wrap_guard = static_cast<int32_t>(out_data[i]) +
64 static_cast<int32_t>(in_data[i]);
65 out_data[i] = rtc::saturated_cast<int16_t>(wrap_guard);
66 }
aleloi6321b492016-12-05 01:46:09 -080067 }
68 }
aleloi6321b492016-12-05 01:46:09 -080069}
niklase@google.com470e71d2011-07-07 08:21:25 +000070
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000071void AudioFrameOperations::MonoToStereo(const int16_t* src_audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -070072 size_t samples_per_channel,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000073 int16_t* dst_audio) {
Peter Kastingdce40cf2015-08-24 14:52:23 -070074 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000075 dst_audio[2 * i] = src_audio[i];
76 dst_audio[2 * i + 1] = src_audio[i];
77 }
78}
79
80int AudioFrameOperations::MonoToStereo(AudioFrame* frame) {
81 if (frame->num_channels_ != 1) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +000082 return -1;
83 }
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000084 if ((frame->samples_per_channel_ * 2) >= AudioFrame::kMaxDataSizeSamples) {
85 // Not enough memory to expand from mono to stereo.
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +000086 return -1;
87 }
niklase@google.com470e71d2011-07-07 08:21:25 +000088
yujo36b1a5f2017-06-12 12:45:32 -070089 if (!frame->muted()) {
90 // TODO(yujo): this operation can be done in place.
91 int16_t data_copy[AudioFrame::kMaxDataSizeSamples];
92 memcpy(data_copy, frame->data(),
93 sizeof(int16_t) * frame->samples_per_channel_);
94 MonoToStereo(data_copy, frame->samples_per_channel_, frame->mutable_data());
95 }
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000096 frame->num_channels_ = 2;
niklase@google.com470e71d2011-07-07 08:21:25 +000097
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +000098 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000099}
100
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000101void AudioFrameOperations::StereoToMono(const int16_t* src_audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700102 size_t samples_per_channel,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000103 int16_t* dst_audio) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700104 for (size_t i = 0; i < samples_per_channel; i++) {
jens.nielsen228c2682017-03-01 05:11:22 -0800105 dst_audio[i] =
106 (static_cast<int32_t>(src_audio[2 * i]) + src_audio[2 * i + 1]) >> 1;
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000107 }
108}
109
110int AudioFrameOperations::StereoToMono(AudioFrame* frame) {
111 if (frame->num_channels_ != 2) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000112 return -1;
113 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000114
jens.nielsen228c2682017-03-01 05:11:22 -0800115 RTC_DCHECK_LE(frame->samples_per_channel_ * 2,
116 AudioFrame::kMaxDataSizeSamples);
117
yujo36b1a5f2017-06-12 12:45:32 -0700118 if (!frame->muted()) {
119 StereoToMono(frame->data(), frame->samples_per_channel_,
120 frame->mutable_data());
121 }
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000122 frame->num_channels_ = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000123
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000124 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000125}
126
jens.nielsen228c2682017-03-01 05:11:22 -0800127void AudioFrameOperations::QuadToStereo(const int16_t* src_audio,
128 size_t samples_per_channel,
129 int16_t* dst_audio) {
130 for (size_t i = 0; i < samples_per_channel; i++) {
131 dst_audio[i * 2] =
132 (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1;
133 dst_audio[i * 2 + 1] =
134 (static_cast<int32_t>(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >>
135 1;
136 }
137}
138
139int AudioFrameOperations::QuadToStereo(AudioFrame* frame) {
140 if (frame->num_channels_ != 4) {
141 return -1;
142 }
143
144 RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
145 AudioFrame::kMaxDataSizeSamples);
146
yujo36b1a5f2017-06-12 12:45:32 -0700147 if (!frame->muted()) {
148 QuadToStereo(frame->data(), frame->samples_per_channel_,
149 frame->mutable_data());
150 }
jens.nielsen228c2682017-03-01 05:11:22 -0800151 frame->num_channels_ = 2;
152
153 return 0;
154}
155
156void AudioFrameOperations::QuadToMono(const int16_t* src_audio,
157 size_t samples_per_channel,
158 int16_t* dst_audio) {
159 for (size_t i = 0; i < samples_per_channel; i++) {
160 dst_audio[i] =
161 (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1] +
162 src_audio[4 * i + 2] + src_audio[4 * i + 3]) >> 2;
163 }
164}
165
166int AudioFrameOperations::QuadToMono(AudioFrame* frame) {
167 if (frame->num_channels_ != 4) {
168 return -1;
169 }
170
171 RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
172 AudioFrame::kMaxDataSizeSamples);
173
yujo36b1a5f2017-06-12 12:45:32 -0700174 if (!frame->muted()) {
175 QuadToMono(frame->data(), frame->samples_per_channel_,
176 frame->mutable_data());
177 }
jens.nielsen228c2682017-03-01 05:11:22 -0800178 frame->num_channels_ = 1;
179
180 return 0;
181}
182
183void AudioFrameOperations::DownmixChannels(const int16_t* src_audio,
184 size_t src_channels,
185 size_t samples_per_channel,
186 size_t dst_channels,
187 int16_t* dst_audio) {
188 if (src_channels == 2 && dst_channels == 1) {
189 StereoToMono(src_audio, samples_per_channel, dst_audio);
190 return;
191 } else if (src_channels == 4 && dst_channels == 2) {
192 QuadToStereo(src_audio, samples_per_channel, dst_audio);
193 return;
194 } else if (src_channels == 4 && dst_channels == 1) {
195 QuadToMono(src_audio, samples_per_channel, dst_audio);
196 return;
197 }
198
199 RTC_NOTREACHED() << "src_channels: " << src_channels
200 << ", dst_channels: " << dst_channels;
201}
202
203int AudioFrameOperations::DownmixChannels(size_t dst_channels,
204 AudioFrame* frame) {
205 if (frame->num_channels_ == 2 && dst_channels == 1) {
206 return StereoToMono(frame);
207 } else if (frame->num_channels_ == 4 && dst_channels == 2) {
208 return QuadToStereo(frame);
209 } else if (frame->num_channels_ == 4 && dst_channels == 1) {
210 return QuadToMono(frame);
211 }
212
213 return -1;
214}
215
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000216void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
aleloi6321b492016-12-05 01:46:09 -0800217 RTC_DCHECK(frame);
yujo36b1a5f2017-06-12 12:45:32 -0700218 if (frame->num_channels_ != 2 || frame->muted()) {
aleloi6321b492016-12-05 01:46:09 -0800219 return;
220 }
andrew@webrtc.org1c7bfe02012-04-26 00:20:28 +0000221
yujo36b1a5f2017-06-12 12:45:32 -0700222 int16_t* frame_data = frame->mutable_data();
Peter Kastingdce40cf2015-08-24 14:52:23 -0700223 for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
yujo36b1a5f2017-06-12 12:45:32 -0700224 int16_t temp_data = frame_data[i];
225 frame_data[i] = frame_data[i + 1];
226 frame_data[i + 1] = temp_data;
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000227 }
228}
229
aleloi6321b492016-12-05 01:46:09 -0800230void AudioFrameOperations::Mute(AudioFrame* frame,
231 bool previous_frame_muted,
solenberg1c2af8e2016-03-24 10:36:00 -0700232 bool current_frame_muted) {
233 RTC_DCHECK(frame);
solenberg1c2af8e2016-03-24 10:36:00 -0700234 if (!previous_frame_muted && !current_frame_muted) {
235 // Not muted, don't touch.
236 } else if (previous_frame_muted && current_frame_muted) {
237 // Frame fully muted.
238 size_t total_samples = frame->samples_per_channel_ * frame->num_channels_;
239 RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, total_samples);
yujo36b1a5f2017-06-12 12:45:32 -0700240 frame->Mute();
solenberg1c2af8e2016-03-24 10:36:00 -0700241 } else {
yujo36b1a5f2017-06-12 12:45:32 -0700242 // Fade is a no-op on a muted frame.
243 if (frame->muted()) {
244 return;
245 }
246
solenberg1c2af8e2016-03-24 10:36:00 -0700247 // Limit number of samples to fade, if frame isn't long enough.
248 size_t count = kMuteFadeFrames;
249 float inc = kMuteFadeInc;
250 if (frame->samples_per_channel_ < kMuteFadeFrames) {
251 count = frame->samples_per_channel_;
252 if (count > 0) {
253 inc = 1.0f / count;
254 }
255 }
256
257 size_t start = 0;
258 size_t end = count;
259 float start_g = 0.0f;
260 if (current_frame_muted) {
261 // Fade out the last |count| samples of frame.
262 RTC_DCHECK(!previous_frame_muted);
263 start = frame->samples_per_channel_ - count;
264 end = frame->samples_per_channel_;
265 start_g = 1.0f;
266 inc = -inc;
267 } else {
268 // Fade in the first |count| samples of frame.
269 RTC_DCHECK(previous_frame_muted);
270 }
271
272 // Perform fade.
yujo36b1a5f2017-06-12 12:45:32 -0700273 int16_t* frame_data = frame->mutable_data();
solenberg1c2af8e2016-03-24 10:36:00 -0700274 size_t channels = frame->num_channels_;
275 for (size_t j = 0; j < channels; ++j) {
276 float g = start_g;
277 for (size_t i = start * channels; i < end * channels; i += channels) {
278 g += inc;
yujo36b1a5f2017-06-12 12:45:32 -0700279 frame_data[i + j] *= g;
solenberg1c2af8e2016-03-24 10:36:00 -0700280 }
281 }
282 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000283}
284
aleloi6321b492016-12-05 01:46:09 -0800285void AudioFrameOperations::Mute(AudioFrame* frame) {
286 Mute(frame, true, true);
287}
288
289void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) {
290 RTC_DCHECK(frame);
291 RTC_DCHECK_GT(frame->num_channels_, 0);
yujo36b1a5f2017-06-12 12:45:32 -0700292 if (frame->num_channels_ < 1 || frame->muted()) {
aleloi6321b492016-12-05 01:46:09 -0800293 return;
294 }
295
yujo36b1a5f2017-06-12 12:45:32 -0700296 int16_t* frame_data = frame->mutable_data();
aleloi6321b492016-12-05 01:46:09 -0800297 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
298 i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700299 frame_data[i] = frame_data[i] >> 1;
aleloi6321b492016-12-05 01:46:09 -0800300 }
301}
302
oprypin67fdb802017-03-09 06:25:06 -0800303int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) {
304 if (frame->num_channels_ != 2) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000305 return -1;
yujo36b1a5f2017-06-12 12:45:32 -0700306 } else if (frame->muted()) {
307 return 0;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000308 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000309
yujo36b1a5f2017-06-12 12:45:32 -0700310 int16_t* frame_data = frame->mutable_data();
oprypin67fdb802017-03-09 06:25:06 -0800311 for (size_t i = 0; i < frame->samples_per_channel_; i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700312 frame_data[2 * i] = static_cast<int16_t>(left * frame_data[2 * i]);
313 frame_data[2 * i + 1] = static_cast<int16_t>(right * frame_data[2 * i + 1]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000314 }
315 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000316}
317
oprypin67fdb802017-03-09 06:25:06 -0800318int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) {
yujo36b1a5f2017-06-12 12:45:32 -0700319 if (frame->muted()) {
320 return 0;
321 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000322
yujo36b1a5f2017-06-12 12:45:32 -0700323 int16_t* frame_data = frame->mutable_data();
oprypin67fdb802017-03-09 06:25:06 -0800324 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000325 i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700326 frame_data[i] = rtc::saturated_cast<int16_t>(scale * frame_data[i]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000327 }
328 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000329}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000330} // namespace webrtc