blob: 1a8232b02b3ae4bed9b2dcf21e8c1361eb1cd801 [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>
Yves Gerey988cc082018-10-23 12:03:01 +020015#include <cstdint>
aleloi6321b492016-12-05 01:46:09 -080016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010018#include "rtc_base/numerics/safe_conversions.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019
20namespace webrtc {
aleloi6321b492016-12-05 01:46:09 -080021namespace {
solenberg1c2af8e2016-03-24 10:36:00 -070022
23// 2.7ms @ 48kHz, 4ms @ 32kHz, 8ms @ 16kHz.
24const size_t kMuteFadeFrames = 128;
25const float kMuteFadeInc = 1.0f / kMuteFadeFrames;
26
aleloi6321b492016-12-05 01:46:09 -080027} // namespace
28
29void AudioFrameOperations::Add(const AudioFrame& frame_to_add,
30 AudioFrame* result_frame) {
31 // Sanity check.
32 RTC_DCHECK(result_frame);
33 RTC_DCHECK_GT(result_frame->num_channels_, 0);
34 RTC_DCHECK_EQ(result_frame->num_channels_, frame_to_add.num_channels_);
35
yujo36b1a5f2017-06-12 12:45:32 -070036 bool no_previous_data = result_frame->muted();
aleloi6321b492016-12-05 01:46:09 -080037 if (result_frame->samples_per_channel_ != frame_to_add.samples_per_channel_) {
38 // Special case we have no data to start with.
39 RTC_DCHECK_EQ(result_frame->samples_per_channel_, 0);
40 result_frame->samples_per_channel_ = frame_to_add.samples_per_channel_;
41 no_previous_data = true;
42 }
43
44 if (result_frame->vad_activity_ == AudioFrame::kVadActive ||
45 frame_to_add.vad_activity_ == AudioFrame::kVadActive) {
46 result_frame->vad_activity_ = AudioFrame::kVadActive;
47 } else if (result_frame->vad_activity_ == AudioFrame::kVadUnknown ||
48 frame_to_add.vad_activity_ == AudioFrame::kVadUnknown) {
49 result_frame->vad_activity_ = AudioFrame::kVadUnknown;
50 }
51
52 if (result_frame->speech_type_ != frame_to_add.speech_type_)
53 result_frame->speech_type_ = AudioFrame::kUndefined;
54
yujo36b1a5f2017-06-12 12:45:32 -070055 if (!frame_to_add.muted()) {
56 const int16_t* in_data = frame_to_add.data();
57 int16_t* out_data = result_frame->mutable_data();
58 size_t length =
59 frame_to_add.samples_per_channel_ * frame_to_add.num_channels_;
60 if (no_previous_data) {
61 std::copy(in_data, in_data + length, out_data);
62 } else {
63 for (size_t i = 0; i < length; i++) {
64 const int32_t wrap_guard = static_cast<int32_t>(out_data[i]) +
65 static_cast<int32_t>(in_data[i]);
66 out_data[i] = rtc::saturated_cast<int16_t>(wrap_guard);
67 }
aleloi6321b492016-12-05 01:46:09 -080068 }
69 }
aleloi6321b492016-12-05 01:46:09 -080070}
niklase@google.com470e71d2011-07-07 08:21:25 +000071
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000072void AudioFrameOperations::MonoToStereo(const int16_t* src_audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -070073 size_t samples_per_channel,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000074 int16_t* dst_audio) {
Peter Kastingdce40cf2015-08-24 14:52:23 -070075 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000076 dst_audio[2 * i] = src_audio[i];
77 dst_audio[2 * i + 1] = src_audio[i];
78 }
79}
80
81int AudioFrameOperations::MonoToStereo(AudioFrame* frame) {
82 if (frame->num_channels_ != 1) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +000083 return -1;
84 }
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000085 if ((frame->samples_per_channel_ * 2) >= AudioFrame::kMaxDataSizeSamples) {
86 // Not enough memory to expand from mono to stereo.
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +000087 return -1;
88 }
niklase@google.com470e71d2011-07-07 08:21:25 +000089
yujo36b1a5f2017-06-12 12:45:32 -070090 if (!frame->muted()) {
91 // TODO(yujo): this operation can be done in place.
92 int16_t data_copy[AudioFrame::kMaxDataSizeSamples];
93 memcpy(data_copy, frame->data(),
94 sizeof(int16_t) * frame->samples_per_channel_);
95 MonoToStereo(data_copy, frame->samples_per_channel_, frame->mutable_data());
96 }
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000097 frame->num_channels_ = 2;
niklase@google.com470e71d2011-07-07 08:21:25 +000098
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +000099 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000100}
101
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000102void AudioFrameOperations::StereoToMono(const int16_t* src_audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700103 size_t samples_per_channel,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000104 int16_t* dst_audio) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700105 for (size_t i = 0; i < samples_per_channel; i++) {
jens.nielsen228c2682017-03-01 05:11:22 -0800106 dst_audio[i] =
107 (static_cast<int32_t>(src_audio[2 * i]) + src_audio[2 * i + 1]) >> 1;
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000108 }
109}
110
111int AudioFrameOperations::StereoToMono(AudioFrame* frame) {
112 if (frame->num_channels_ != 2) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000113 return -1;
114 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
jens.nielsen228c2682017-03-01 05:11:22 -0800116 RTC_DCHECK_LE(frame->samples_per_channel_ * 2,
117 AudioFrame::kMaxDataSizeSamples);
118
yujo36b1a5f2017-06-12 12:45:32 -0700119 if (!frame->muted()) {
120 StereoToMono(frame->data(), frame->samples_per_channel_,
121 frame->mutable_data());
122 }
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000123 frame->num_channels_ = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000125 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000126}
127
jens.nielsen228c2682017-03-01 05:11:22 -0800128void AudioFrameOperations::QuadToStereo(const int16_t* src_audio,
129 size_t samples_per_channel,
130 int16_t* dst_audio) {
131 for (size_t i = 0; i < samples_per_channel; i++) {
132 dst_audio[i * 2] =
133 (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1;
134 dst_audio[i * 2 + 1] =
135 (static_cast<int32_t>(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >>
136 1;
137 }
138}
139
140int AudioFrameOperations::QuadToStereo(AudioFrame* frame) {
141 if (frame->num_channels_ != 4) {
142 return -1;
143 }
144
145 RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
146 AudioFrame::kMaxDataSizeSamples);
147
yujo36b1a5f2017-06-12 12:45:32 -0700148 if (!frame->muted()) {
149 QuadToStereo(frame->data(), frame->samples_per_channel_,
150 frame->mutable_data());
151 }
jens.nielsen228c2682017-03-01 05:11:22 -0800152 frame->num_channels_ = 2;
153
154 return 0;
155}
156
157void AudioFrameOperations::QuadToMono(const int16_t* src_audio,
158 size_t samples_per_channel,
159 int16_t* dst_audio) {
160 for (size_t i = 0; i < samples_per_channel; i++) {
161 dst_audio[i] =
162 (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1] +
Yves Gerey665174f2018-06-19 15:03:05 +0200163 src_audio[4 * i + 2] + src_audio[4 * i + 3]) >>
164 2;
jens.nielsen228c2682017-03-01 05:11:22 -0800165 }
166}
167
168int AudioFrameOperations::QuadToMono(AudioFrame* frame) {
169 if (frame->num_channels_ != 4) {
170 return -1;
171 }
172
173 RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
174 AudioFrame::kMaxDataSizeSamples);
175
yujo36b1a5f2017-06-12 12:45:32 -0700176 if (!frame->muted()) {
177 QuadToMono(frame->data(), frame->samples_per_channel_,
178 frame->mutable_data());
179 }
jens.nielsen228c2682017-03-01 05:11:22 -0800180 frame->num_channels_ = 1;
181
182 return 0;
183}
184
185void AudioFrameOperations::DownmixChannels(const int16_t* src_audio,
186 size_t src_channels,
187 size_t samples_per_channel,
188 size_t dst_channels,
189 int16_t* dst_audio) {
190 if (src_channels == 2 && dst_channels == 1) {
191 StereoToMono(src_audio, samples_per_channel, dst_audio);
192 return;
193 } else if (src_channels == 4 && dst_channels == 2) {
194 QuadToStereo(src_audio, samples_per_channel, dst_audio);
195 return;
196 } else if (src_channels == 4 && dst_channels == 1) {
197 QuadToMono(src_audio, samples_per_channel, dst_audio);
198 return;
199 }
200
201 RTC_NOTREACHED() << "src_channels: " << src_channels
202 << ", dst_channels: " << dst_channels;
203}
204
205int AudioFrameOperations::DownmixChannels(size_t dst_channels,
206 AudioFrame* frame) {
207 if (frame->num_channels_ == 2 && dst_channels == 1) {
208 return StereoToMono(frame);
209 } else if (frame->num_channels_ == 4 && dst_channels == 2) {
210 return QuadToStereo(frame);
211 } else if (frame->num_channels_ == 4 && dst_channels == 1) {
212 return QuadToMono(frame);
213 }
214
215 return -1;
216}
217
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000218void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
aleloi6321b492016-12-05 01:46:09 -0800219 RTC_DCHECK(frame);
yujo36b1a5f2017-06-12 12:45:32 -0700220 if (frame->num_channels_ != 2 || frame->muted()) {
aleloi6321b492016-12-05 01:46:09 -0800221 return;
222 }
andrew@webrtc.org1c7bfe02012-04-26 00:20:28 +0000223
yujo36b1a5f2017-06-12 12:45:32 -0700224 int16_t* frame_data = frame->mutable_data();
Peter Kastingdce40cf2015-08-24 14:52:23 -0700225 for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
yujo36b1a5f2017-06-12 12:45:32 -0700226 int16_t temp_data = frame_data[i];
227 frame_data[i] = frame_data[i + 1];
228 frame_data[i + 1] = temp_data;
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000229 }
230}
231
aleloi6321b492016-12-05 01:46:09 -0800232void AudioFrameOperations::Mute(AudioFrame* frame,
233 bool previous_frame_muted,
solenberg1c2af8e2016-03-24 10:36:00 -0700234 bool current_frame_muted) {
235 RTC_DCHECK(frame);
solenberg1c2af8e2016-03-24 10:36:00 -0700236 if (!previous_frame_muted && !current_frame_muted) {
237 // Not muted, don't touch.
238 } else if (previous_frame_muted && current_frame_muted) {
239 // Frame fully muted.
240 size_t total_samples = frame->samples_per_channel_ * frame->num_channels_;
241 RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, total_samples);
yujo36b1a5f2017-06-12 12:45:32 -0700242 frame->Mute();
solenberg1c2af8e2016-03-24 10:36:00 -0700243 } else {
yujo36b1a5f2017-06-12 12:45:32 -0700244 // Fade is a no-op on a muted frame.
245 if (frame->muted()) {
246 return;
247 }
248
solenberg1c2af8e2016-03-24 10:36:00 -0700249 // Limit number of samples to fade, if frame isn't long enough.
250 size_t count = kMuteFadeFrames;
251 float inc = kMuteFadeInc;
252 if (frame->samples_per_channel_ < kMuteFadeFrames) {
253 count = frame->samples_per_channel_;
254 if (count > 0) {
255 inc = 1.0f / count;
256 }
257 }
258
259 size_t start = 0;
260 size_t end = count;
261 float start_g = 0.0f;
262 if (current_frame_muted) {
263 // Fade out the last |count| samples of frame.
264 RTC_DCHECK(!previous_frame_muted);
265 start = frame->samples_per_channel_ - count;
266 end = frame->samples_per_channel_;
267 start_g = 1.0f;
268 inc = -inc;
269 } else {
270 // Fade in the first |count| samples of frame.
271 RTC_DCHECK(previous_frame_muted);
272 }
273
274 // Perform fade.
yujo36b1a5f2017-06-12 12:45:32 -0700275 int16_t* frame_data = frame->mutable_data();
solenberg1c2af8e2016-03-24 10:36:00 -0700276 size_t channels = frame->num_channels_;
277 for (size_t j = 0; j < channels; ++j) {
278 float g = start_g;
279 for (size_t i = start * channels; i < end * channels; i += channels) {
280 g += inc;
yujo36b1a5f2017-06-12 12:45:32 -0700281 frame_data[i + j] *= g;
solenberg1c2af8e2016-03-24 10:36:00 -0700282 }
283 }
284 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000285}
286
aleloi6321b492016-12-05 01:46:09 -0800287void AudioFrameOperations::Mute(AudioFrame* frame) {
288 Mute(frame, true, true);
289}
290
291void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) {
292 RTC_DCHECK(frame);
293 RTC_DCHECK_GT(frame->num_channels_, 0);
yujo36b1a5f2017-06-12 12:45:32 -0700294 if (frame->num_channels_ < 1 || frame->muted()) {
aleloi6321b492016-12-05 01:46:09 -0800295 return;
296 }
297
yujo36b1a5f2017-06-12 12:45:32 -0700298 int16_t* frame_data = frame->mutable_data();
aleloi6321b492016-12-05 01:46:09 -0800299 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
300 i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700301 frame_data[i] = frame_data[i] >> 1;
aleloi6321b492016-12-05 01:46:09 -0800302 }
303}
304
oprypin67fdb802017-03-09 06:25:06 -0800305int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) {
306 if (frame->num_channels_ != 2) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000307 return -1;
yujo36b1a5f2017-06-12 12:45:32 -0700308 } else if (frame->muted()) {
309 return 0;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000310 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000311
yujo36b1a5f2017-06-12 12:45:32 -0700312 int16_t* frame_data = frame->mutable_data();
oprypin67fdb802017-03-09 06:25:06 -0800313 for (size_t i = 0; i < frame->samples_per_channel_; i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700314 frame_data[2 * i] = static_cast<int16_t>(left * frame_data[2 * i]);
315 frame_data[2 * i + 1] = static_cast<int16_t>(right * frame_data[2 * i + 1]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000316 }
317 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000318}
319
oprypin67fdb802017-03-09 06:25:06 -0800320int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) {
yujo36b1a5f2017-06-12 12:45:32 -0700321 if (frame->muted()) {
322 return 0;
323 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000324
yujo36b1a5f2017-06-12 12:45:32 -0700325 int16_t* frame_data = frame->mutable_data();
oprypin67fdb802017-03-09 06:25:06 -0800326 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000327 i++) {
yujo36b1a5f2017-06-12 12:45:32 -0700328 frame_data[i] = rtc::saturated_cast<int16_t>(scale * frame_data[i]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000329 }
330 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000331}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000332} // namespace webrtc