blob: 0338b46db0b6d5e10b826e0f9bffb2d15429d3d4 [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
aleloi6321b492016-12-05 01:46:09 -080011#include "webrtc/audio/utility/audio_frame_operations.h"
12
13#include <algorithm>
14
solenberg1c2af8e2016-03-24 10:36:00 -070015#include "webrtc/base/checks.h"
aleloi6321b492016-12-05 01:46:09 -080016#include "webrtc/base/safe_conversions.h"
17#include "webrtc/modules/include/module_common_types.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
35 bool no_previous_data = false;
36 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
54 if (no_previous_data) {
55 std::copy(frame_to_add.data_, frame_to_add.data_ +
56 frame_to_add.samples_per_channel_ *
57 result_frame->num_channels_,
58 result_frame->data_);
59 } else {
60 for (size_t i = 0;
61 i < result_frame->samples_per_channel_ * result_frame->num_channels_;
62 i++) {
63 const int32_t wrap_guard = static_cast<int32_t>(result_frame->data_[i]) +
64 static_cast<int32_t>(frame_to_add.data_[i]);
65 result_frame->data_[i] = rtc::saturated_cast<int16_t>(wrap_guard);
66 }
67 }
68 return;
69}
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
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000089 int16_t data_copy[AudioFrame::kMaxDataSizeSamples];
90 memcpy(data_copy, frame->data_,
91 sizeof(int16_t) * frame->samples_per_channel_);
92 MonoToStereo(data_copy, frame->samples_per_channel_, frame->data_);
93 frame->num_channels_ = 2;
niklase@google.com470e71d2011-07-07 08:21:25 +000094
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +000095 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000096}
97
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +000098void AudioFrameOperations::StereoToMono(const int16_t* src_audio,
Peter Kastingdce40cf2015-08-24 14:52:23 -070099 size_t samples_per_channel,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000100 int16_t* dst_audio) {
Peter Kastingdce40cf2015-08-24 14:52:23 -0700101 for (size_t i = 0; i < samples_per_channel; i++) {
jens.nielsen228c2682017-03-01 05:11:22 -0800102 dst_audio[i] =
103 (static_cast<int32_t>(src_audio[2 * i]) + src_audio[2 * i + 1]) >> 1;
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000104 }
105}
106
107int AudioFrameOperations::StereoToMono(AudioFrame* frame) {
108 if (frame->num_channels_ != 2) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000109 return -1;
110 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
jens.nielsen228c2682017-03-01 05:11:22 -0800112 RTC_DCHECK_LE(frame->samples_per_channel_ * 2,
113 AudioFrame::kMaxDataSizeSamples);
114
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000115 StereoToMono(frame->data_, frame->samples_per_channel_, frame->data_);
116 frame->num_channels_ = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000117
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000118 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000119}
120
jens.nielsen228c2682017-03-01 05:11:22 -0800121void AudioFrameOperations::QuadToStereo(const int16_t* src_audio,
122 size_t samples_per_channel,
123 int16_t* dst_audio) {
124 for (size_t i = 0; i < samples_per_channel; i++) {
125 dst_audio[i * 2] =
126 (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1]) >> 1;
127 dst_audio[i * 2 + 1] =
128 (static_cast<int32_t>(src_audio[4 * i + 2]) + src_audio[4 * i + 3]) >>
129 1;
130 }
131}
132
133int AudioFrameOperations::QuadToStereo(AudioFrame* frame) {
134 if (frame->num_channels_ != 4) {
135 return -1;
136 }
137
138 RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
139 AudioFrame::kMaxDataSizeSamples);
140
141 QuadToStereo(frame->data_, frame->samples_per_channel_, frame->data_);
142 frame->num_channels_ = 2;
143
144 return 0;
145}
146
147void AudioFrameOperations::QuadToMono(const int16_t* src_audio,
148 size_t samples_per_channel,
149 int16_t* dst_audio) {
150 for (size_t i = 0; i < samples_per_channel; i++) {
151 dst_audio[i] =
152 (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1] +
153 src_audio[4 * i + 2] + src_audio[4 * i + 3]) >> 2;
154 }
155}
156
157int AudioFrameOperations::QuadToMono(AudioFrame* frame) {
158 if (frame->num_channels_ != 4) {
159 return -1;
160 }
161
162 RTC_DCHECK_LE(frame->samples_per_channel_ * 4,
163 AudioFrame::kMaxDataSizeSamples);
164
165 QuadToMono(frame->data_, frame->samples_per_channel_, frame->data_);
166 frame->num_channels_ = 1;
167
168 return 0;
169}
170
171void AudioFrameOperations::DownmixChannels(const int16_t* src_audio,
172 size_t src_channels,
173 size_t samples_per_channel,
174 size_t dst_channels,
175 int16_t* dst_audio) {
176 if (src_channels == 2 && dst_channels == 1) {
177 StereoToMono(src_audio, samples_per_channel, dst_audio);
178 return;
179 } else if (src_channels == 4 && dst_channels == 2) {
180 QuadToStereo(src_audio, samples_per_channel, dst_audio);
181 return;
182 } else if (src_channels == 4 && dst_channels == 1) {
183 QuadToMono(src_audio, samples_per_channel, dst_audio);
184 return;
185 }
186
187 RTC_NOTREACHED() << "src_channels: " << src_channels
188 << ", dst_channels: " << dst_channels;
189}
190
191int AudioFrameOperations::DownmixChannels(size_t dst_channels,
192 AudioFrame* frame) {
193 if (frame->num_channels_ == 2 && dst_channels == 1) {
194 return StereoToMono(frame);
195 } else if (frame->num_channels_ == 4 && dst_channels == 2) {
196 return QuadToStereo(frame);
197 } else if (frame->num_channels_ == 4 && dst_channels == 1) {
198 return QuadToMono(frame);
199 }
200
201 return -1;
202}
203
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000204void AudioFrameOperations::SwapStereoChannels(AudioFrame* frame) {
aleloi6321b492016-12-05 01:46:09 -0800205 RTC_DCHECK(frame);
206 if (frame->num_channels_ != 2) {
207 return;
208 }
andrew@webrtc.org1c7bfe02012-04-26 00:20:28 +0000209
Peter Kastingdce40cf2015-08-24 14:52:23 -0700210 for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000211 int16_t temp_data = frame->data_[i];
212 frame->data_[i] = frame->data_[i + 1];
213 frame->data_[i + 1] = temp_data;
andrew@webrtc.org02d71742012-04-24 19:47:00 +0000214 }
215}
216
aleloi6321b492016-12-05 01:46:09 -0800217void AudioFrameOperations::Mute(AudioFrame* frame,
218 bool previous_frame_muted,
solenberg1c2af8e2016-03-24 10:36:00 -0700219 bool current_frame_muted) {
220 RTC_DCHECK(frame);
solenberg1c2af8e2016-03-24 10:36:00 -0700221 if (!previous_frame_muted && !current_frame_muted) {
222 // Not muted, don't touch.
223 } else if (previous_frame_muted && current_frame_muted) {
224 // Frame fully muted.
225 size_t total_samples = frame->samples_per_channel_ * frame->num_channels_;
226 RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, total_samples);
227 memset(frame->data_, 0, sizeof(frame->data_[0]) * total_samples);
228 } else {
229 // Limit number of samples to fade, if frame isn't long enough.
230 size_t count = kMuteFadeFrames;
231 float inc = kMuteFadeInc;
232 if (frame->samples_per_channel_ < kMuteFadeFrames) {
233 count = frame->samples_per_channel_;
234 if (count > 0) {
235 inc = 1.0f / count;
236 }
237 }
238
239 size_t start = 0;
240 size_t end = count;
241 float start_g = 0.0f;
242 if (current_frame_muted) {
243 // Fade out the last |count| samples of frame.
244 RTC_DCHECK(!previous_frame_muted);
245 start = frame->samples_per_channel_ - count;
246 end = frame->samples_per_channel_;
247 start_g = 1.0f;
248 inc = -inc;
249 } else {
250 // Fade in the first |count| samples of frame.
251 RTC_DCHECK(previous_frame_muted);
252 }
253
254 // Perform fade.
255 size_t channels = frame->num_channels_;
256 for (size_t j = 0; j < channels; ++j) {
257 float g = start_g;
258 for (size_t i = start * channels; i < end * channels; i += channels) {
259 g += inc;
260 frame->data_[i + j] *= g;
261 }
262 }
263 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000264}
265
aleloi6321b492016-12-05 01:46:09 -0800266void AudioFrameOperations::Mute(AudioFrame* frame) {
267 Mute(frame, true, true);
268}
269
270void AudioFrameOperations::ApplyHalfGain(AudioFrame* frame) {
271 RTC_DCHECK(frame);
272 RTC_DCHECK_GT(frame->num_channels_, 0);
273 if (frame->num_channels_ < 1) {
274 return;
275 }
276
277 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
278 i++) {
279 frame->data_[i] = frame->data_[i] >> 1;
280 }
281}
282
oprypin67fdb802017-03-09 06:25:06 -0800283int AudioFrameOperations::Scale(float left, float right, AudioFrame* frame) {
284 if (frame->num_channels_ != 2) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000285 return -1;
286 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000287
oprypin67fdb802017-03-09 06:25:06 -0800288 for (size_t i = 0; i < frame->samples_per_channel_; i++) {
289 frame->data_[2 * i] = static_cast<int16_t>(left * frame->data_[2 * i]);
290 frame->data_[2 * i + 1] =
291 static_cast<int16_t>(right * frame->data_[2 * i + 1]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000292 }
293 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000294}
295
oprypin67fdb802017-03-09 06:25:06 -0800296int AudioFrameOperations::ScaleWithSat(float scale, AudioFrame* frame) {
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000297 int32_t temp_data = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000299 // Ensure that the output result is saturated [-32768, +32767].
oprypin67fdb802017-03-09 06:25:06 -0800300 for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000301 i++) {
oprypin67fdb802017-03-09 06:25:06 -0800302 temp_data = static_cast<int32_t>(scale * frame->data_[i]);
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000303 if (temp_data < -32768) {
oprypin67fdb802017-03-09 06:25:06 -0800304 frame->data_[i] = -32768;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000305 } else if (temp_data > 32767) {
oprypin67fdb802017-03-09 06:25:06 -0800306 frame->data_[i] = 32767;
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000307 } else {
oprypin67fdb802017-03-09 06:25:06 -0800308 frame->data_[i] = static_cast<int16_t>(temp_data);
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 }
andrew@webrtc.org9c4f6a52012-04-26 22:32:03 +0000310 }
311 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000312}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000313} // namespace webrtc