blob: fb1f3b07711b79dd4bc059bc1921df28fea26bed [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
Raphael Kubo da Costa7ce30912018-04-16 11:17:10 +020013#include <string.h>
aleloi6321b492016-12-05 01:46:09 -080014#include <algorithm>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010017#include "rtc_base/numerics/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] +
Yves Gerey665174f2018-06-19 15:03:05 +0200162 src_audio[4 * i + 2] + src_audio[4 * i + 3]) >>
163 2;
jens.nielsen228c2682017-03-01 05:11:22 -0800164 }
165}
166
167int AudioFrameOperations::QuadToMono(AudioFrame* frame) {
168 if (frame->num_channels_ != 4) {
169 return -1;
170 }
171
172 RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
173 AudioFrame::kMaxDataSizeSamples);
174
yujo36b1a5f2017-06-12 12:45:32 -0700175 if (!frame->muted()) {
176 QuadToMono(frame->data(), frame->samples_per_channel_,
177 frame->mutable_data());
178 }
jens.nielsen228c2682017-03-01 05:11:22 -0800179 frame->num_channels_ = 1;
180
181 return 0;
182}
183
184void AudioFrameOperations::DownmixChannels(const int16_t* src_audio,
185 size_t src_channels,
186 size_t samples_per_channel,
187 size_t dst_channels,
188 int16_t* dst_audio) {
189 if (src_channels == 2 && dst_channels == 1) {
190 StereoToMono(src_audio, samples_per_channel, dst_audio);
191 return;
192 } else if (src_channels == 4 && dst_channels == 2) {
193 QuadToStereo(src_audio, samples_per_channel, dst_audio);
194 return;
195 } else if (src_channels == 4 && dst_channels == 1) {
196 QuadToMono(src_audio, samples_per_channel, dst_audio);
197 return;
198 }
199
200 RTC_NOTREACHED() << "src_channels: " << src_channels
201 << ", dst_channels: " << dst_channels;
202}
203
204int AudioFrameOperations::DownmixChannels(size_t dst_channels,
205 AudioFrame* frame) {
206 if (frame->num_channels_ == 2 && dst_channels == 1) {
207 return StereoToMono(frame);
208 } else if (frame->num_channels_ == 4 && dst_channels == 2) {
209 return QuadToStereo(frame);
210 } else if (frame->num_channels_ == 4 && dst_channels == 1) {
211 return QuadToMono(frame);
212 }
213
214 return -1;
215}
216
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000217void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
aleloi6321b492016-12-05 01:46:09 -0800218 RTC_DCHECK(frame);
yujo36b1a5f2017-06-12 12:45:32 -0700219 if (frame->num_channels_ != 2 || frame->muted()) {
aleloi6321b492016-12-05 01:46:09 -0800220 return;
221 }
andrew@webrtc.org1c7bfe02012-04-26 00:20:28 +0000222
yujo36b1a5f2017-06-12 12:45:32 -0700223 int16_t* frame_data = frame->mutable_data();
Peter Kastingdce40cf2015-08-24 14:52:23 -0700224 for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
yujo36b1a5f2017-06-12 12:45:32 -0700225 int16_t temp_data = frame_data[i];
226 frame_data[i] = frame_data[i + 1];
227 frame_data[i + 1] = temp_data;
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000228 }
229}
230
aleloi6321b492016-12-05 01:46:09 -0800231void AudioFrameOperations::Mute(AudioFrame* frame,
232 bool previous_frame_muted,
solenberg1c2af8e2016-03-24 10:36:00 -0700233 bool current_frame_muted) {
234 RTC_DCHECK(frame);
solenberg1c2af8e2016-03-24 10:36:00 -0700235 if (!previous_frame_muted && !current_frame_muted) {
236 // Not muted, don't touch.
237 } else if (previous_frame_muted && current_frame_muted) {
238 // Frame fully muted.
239 size_t total_samples = frame->samples_per_channel_ * frame->num_channels_;
240 RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, total_samples);
yujo36b1a5f2017-06-12 12:45:32 -0700241 frame->Mute();
solenberg1c2af8e2016-03-24 10:36:00 -0700242 } else {
yujo36b1a5f2017-06-12 12:45:32 -0700243 // Fade is a no-op on a muted frame.
244 if (frame->muted()) {
245 return;
246 }
247
solenberg1c2af8e2016-03-24 10:36:00 -0700248 // Limit number of samples to fade, if frame isn't long enough.
249 size_t count = kMuteFadeFrames;
250 float inc = kMuteFadeInc;
251 if (frame->samples_per_channel_ < kMuteFadeFrames) {
252 count = frame->samples_per_channel_;
253 if (count > 0) {
254 inc = 1.0f / count;
255 }
256 }
257
258 size_t start = 0;
259 size_t end = count;
260 float start_g = 0.0f;
261 if (current_frame_muted) {
262 // Fade out the last |count| samples of frame.
263 RTC_DCHECK(!previous_frame_muted);
264 start = frame->samples_per_channel_ - count;
265 end = frame->samples_per_channel_;
266 start_g = 1.0f;
267 inc = -inc;
268 } else {
269 // Fade in the first |count| samples of frame.
270 RTC_DCHECK(previous_frame_muted);
271 }
272
273 // Perform fade.
yujo36b1a5f2017-06-12 12:45:32 -0700274 int16_t* frame_data = frame->mutable_data();
solenberg1c2af8e2016-03-24 10:36:00 -0700275 size_t channels = frame->num_channels_;
276 for (size_t j = 0; j < channels; ++j) {
277 float g = start_g;
278 for (size_t i = start * channels; i < end * channels; i += channels) {
279 g += inc;
yujo36b1a5f2017-06-12 12:45:32 -0700280 frame_data[i + j] *= g;
solenberg1c2af8e2016-03-24 10:36:00 -0700281 }
282 }
283 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000284}
285
aleloi6321b492016-12-05 01:46:09 -0800286void AudioFrameOperations::Mute(AudioFrame* frame) {
287 Mute(frame, true, true);
288}
289
290void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) {
291 RTC_DCHECK(frame);
292 RTC_DCHECK_GT(frame->num_channels_, 0);
yujo36b1a5f2017-06-12 12:45:32 -0700293 if (frame->num_channels_ < 1 || frame->muted()) {
aleloi6321b492016-12-05 01:46:09 -0800294 return;
295 }
296
yujo36b1a5f2017-06-12 12:45:32 -0700297 int16_t* frame_data = frame->mutable_data();
aleloi6321b492016-12-05 01:46:09 -0800298 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
299 i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700300 frame_data[i] = frame_data[i] >> 1;
aleloi6321b492016-12-05 01:46:09 -0800301 }
302}
303
oprypin67fdb802017-03-09 06:25:06 -0800304int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) {
305 if (frame->num_channels_ != 2) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000306 return -1;
yujo36b1a5f2017-06-12 12:45:32 -0700307 } else if (frame->muted()) {
308 return 0;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000309 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000310
yujo36b1a5f2017-06-12 12:45:32 -0700311 int16_t* frame_data = frame->mutable_data();
oprypin67fdb802017-03-09 06:25:06 -0800312 for (size_t i = 0; i < frame->samples_per_channel_; i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700313 frame_data[2 * i] = static_cast<int16_t>(left * frame_data[2 * i]);
314 frame_data[2 * i + 1] = static_cast<int16_t>(right * frame_data[2 * i + 1]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000315 }
316 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000317}
318
oprypin67fdb802017-03-09 06:25:06 -0800319int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) {
yujo36b1a5f2017-06-12 12:45:32 -0700320 if (frame->muted()) {
321 return 0;
322 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000323
yujo36b1a5f2017-06-12 12:45:32 -0700324 int16_t* frame_data = frame->mutable_data();
oprypin67fdb802017-03-09 06:25:06 -0800325 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000326 i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700327 frame_data[i] = rtc::saturated_cast<int16_t>(scale * frame_data[i]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000328 }
329 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000330}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000331} // namespace webrtc