1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #ifndef COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
12*d9f75844SAndroid Build Coastguard Worker #define COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
13*d9f75844SAndroid Build Coastguard Worker
14*d9f75844SAndroid Build Coastguard Worker #include <stdint.h>
15*d9f75844SAndroid Build Coastguard Worker
16*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
17*d9f75844SAndroid Build Coastguard Worker #include <cmath>
18*d9f75844SAndroid Build Coastguard Worker #include <cstring>
19*d9f75844SAndroid Build Coastguard Worker #include <limits>
20*d9f75844SAndroid Build Coastguard Worker
21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
22*d9f75844SAndroid Build Coastguard Worker
23*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
24*d9f75844SAndroid Build Coastguard Worker
25*d9f75844SAndroid Build Coastguard Worker typedef std::numeric_limits<int16_t> limits_int16;
26*d9f75844SAndroid Build Coastguard Worker
27*d9f75844SAndroid Build Coastguard Worker // The conversion functions use the following naming convention:
28*d9f75844SAndroid Build Coastguard Worker // S16: int16_t [-32768, 32767]
29*d9f75844SAndroid Build Coastguard Worker // Float: float [-1.0, 1.0]
30*d9f75844SAndroid Build Coastguard Worker // FloatS16: float [-32768.0, 32768.0]
31*d9f75844SAndroid Build Coastguard Worker // Dbfs: float [-20.0*log(10, 32768), 0] = [-90.3, 0]
32*d9f75844SAndroid Build Coastguard Worker // The ratio conversion functions use this naming convention:
33*d9f75844SAndroid Build Coastguard Worker // Ratio: float (0, +inf)
34*d9f75844SAndroid Build Coastguard Worker // Db: float (-inf, +inf)
S16ToFloat(int16_t v)35*d9f75844SAndroid Build Coastguard Worker static inline float S16ToFloat(int16_t v) {
36*d9f75844SAndroid Build Coastguard Worker constexpr float kScaling = 1.f / 32768.f;
37*d9f75844SAndroid Build Coastguard Worker return v * kScaling;
38*d9f75844SAndroid Build Coastguard Worker }
39*d9f75844SAndroid Build Coastguard Worker
FloatS16ToS16(float v)40*d9f75844SAndroid Build Coastguard Worker static inline int16_t FloatS16ToS16(float v) {
41*d9f75844SAndroid Build Coastguard Worker v = std::min(v, 32767.f);
42*d9f75844SAndroid Build Coastguard Worker v = std::max(v, -32768.f);
43*d9f75844SAndroid Build Coastguard Worker return static_cast<int16_t>(v + std::copysign(0.5f, v));
44*d9f75844SAndroid Build Coastguard Worker }
45*d9f75844SAndroid Build Coastguard Worker
FloatToS16(float v)46*d9f75844SAndroid Build Coastguard Worker static inline int16_t FloatToS16(float v) {
47*d9f75844SAndroid Build Coastguard Worker v *= 32768.f;
48*d9f75844SAndroid Build Coastguard Worker v = std::min(v, 32767.f);
49*d9f75844SAndroid Build Coastguard Worker v = std::max(v, -32768.f);
50*d9f75844SAndroid Build Coastguard Worker return static_cast<int16_t>(v + std::copysign(0.5f, v));
51*d9f75844SAndroid Build Coastguard Worker }
52*d9f75844SAndroid Build Coastguard Worker
FloatToFloatS16(float v)53*d9f75844SAndroid Build Coastguard Worker static inline float FloatToFloatS16(float v) {
54*d9f75844SAndroid Build Coastguard Worker v = std::min(v, 1.f);
55*d9f75844SAndroid Build Coastguard Worker v = std::max(v, -1.f);
56*d9f75844SAndroid Build Coastguard Worker return v * 32768.f;
57*d9f75844SAndroid Build Coastguard Worker }
58*d9f75844SAndroid Build Coastguard Worker
FloatS16ToFloat(float v)59*d9f75844SAndroid Build Coastguard Worker static inline float FloatS16ToFloat(float v) {
60*d9f75844SAndroid Build Coastguard Worker v = std::min(v, 32768.f);
61*d9f75844SAndroid Build Coastguard Worker v = std::max(v, -32768.f);
62*d9f75844SAndroid Build Coastguard Worker constexpr float kScaling = 1.f / 32768.f;
63*d9f75844SAndroid Build Coastguard Worker return v * kScaling;
64*d9f75844SAndroid Build Coastguard Worker }
65*d9f75844SAndroid Build Coastguard Worker
66*d9f75844SAndroid Build Coastguard Worker void FloatToS16(const float* src, size_t size, int16_t* dest);
67*d9f75844SAndroid Build Coastguard Worker void S16ToFloat(const int16_t* src, size_t size, float* dest);
68*d9f75844SAndroid Build Coastguard Worker void S16ToFloatS16(const int16_t* src, size_t size, float* dest);
69*d9f75844SAndroid Build Coastguard Worker void FloatS16ToS16(const float* src, size_t size, int16_t* dest);
70*d9f75844SAndroid Build Coastguard Worker void FloatToFloatS16(const float* src, size_t size, float* dest);
71*d9f75844SAndroid Build Coastguard Worker void FloatS16ToFloat(const float* src, size_t size, float* dest);
72*d9f75844SAndroid Build Coastguard Worker
DbToRatio(float v)73*d9f75844SAndroid Build Coastguard Worker inline float DbToRatio(float v) {
74*d9f75844SAndroid Build Coastguard Worker return std::pow(10.0f, v / 20.0f);
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker
DbfsToFloatS16(float v)77*d9f75844SAndroid Build Coastguard Worker inline float DbfsToFloatS16(float v) {
78*d9f75844SAndroid Build Coastguard Worker static constexpr float kMaximumAbsFloatS16 = -limits_int16::min();
79*d9f75844SAndroid Build Coastguard Worker return DbToRatio(v) * kMaximumAbsFloatS16;
80*d9f75844SAndroid Build Coastguard Worker }
81*d9f75844SAndroid Build Coastguard Worker
FloatS16ToDbfs(float v)82*d9f75844SAndroid Build Coastguard Worker inline float FloatS16ToDbfs(float v) {
83*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(v, 0);
84*d9f75844SAndroid Build Coastguard Worker
85*d9f75844SAndroid Build Coastguard Worker // kMinDbfs is equal to -20.0 * log10(-limits_int16::min())
86*d9f75844SAndroid Build Coastguard Worker static constexpr float kMinDbfs = -90.30899869919436f;
87*d9f75844SAndroid Build Coastguard Worker if (v <= 1.0f) {
88*d9f75844SAndroid Build Coastguard Worker return kMinDbfs;
89*d9f75844SAndroid Build Coastguard Worker }
90*d9f75844SAndroid Build Coastguard Worker // Equal to 20 * log10(v / (-limits_int16::min()))
91*d9f75844SAndroid Build Coastguard Worker return 20.0f * std::log10(v) + kMinDbfs;
92*d9f75844SAndroid Build Coastguard Worker }
93*d9f75844SAndroid Build Coastguard Worker
94*d9f75844SAndroid Build Coastguard Worker // Copy audio from `src` channels to `dest` channels unless `src` and `dest`
95*d9f75844SAndroid Build Coastguard Worker // point to the same address. `src` and `dest` must have the same number of
96*d9f75844SAndroid Build Coastguard Worker // channels, and there must be sufficient space allocated in `dest`.
97*d9f75844SAndroid Build Coastguard Worker template <typename T>
CopyAudioIfNeeded(const T * const * src,int num_frames,int num_channels,T * const * dest)98*d9f75844SAndroid Build Coastguard Worker void CopyAudioIfNeeded(const T* const* src,
99*d9f75844SAndroid Build Coastguard Worker int num_frames,
100*d9f75844SAndroid Build Coastguard Worker int num_channels,
101*d9f75844SAndroid Build Coastguard Worker T* const* dest) {
102*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < num_channels; ++i) {
103*d9f75844SAndroid Build Coastguard Worker if (src[i] != dest[i]) {
104*d9f75844SAndroid Build Coastguard Worker std::copy(src[i], src[i] + num_frames, dest[i]);
105*d9f75844SAndroid Build Coastguard Worker }
106*d9f75844SAndroid Build Coastguard Worker }
107*d9f75844SAndroid Build Coastguard Worker }
108*d9f75844SAndroid Build Coastguard Worker
109*d9f75844SAndroid Build Coastguard Worker // Deinterleave audio from `interleaved` to the channel buffers pointed to
110*d9f75844SAndroid Build Coastguard Worker // by `deinterleaved`. There must be sufficient space allocated in the
111*d9f75844SAndroid Build Coastguard Worker // `deinterleaved` buffers (`num_channel` buffers with `samples_per_channel`
112*d9f75844SAndroid Build Coastguard Worker // per buffer).
113*d9f75844SAndroid Build Coastguard Worker template <typename T>
Deinterleave(const T * interleaved,size_t samples_per_channel,size_t num_channels,T * const * deinterleaved)114*d9f75844SAndroid Build Coastguard Worker void Deinterleave(const T* interleaved,
115*d9f75844SAndroid Build Coastguard Worker size_t samples_per_channel,
116*d9f75844SAndroid Build Coastguard Worker size_t num_channels,
117*d9f75844SAndroid Build Coastguard Worker T* const* deinterleaved) {
118*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < num_channels; ++i) {
119*d9f75844SAndroid Build Coastguard Worker T* channel = deinterleaved[i];
120*d9f75844SAndroid Build Coastguard Worker size_t interleaved_idx = i;
121*d9f75844SAndroid Build Coastguard Worker for (size_t j = 0; j < samples_per_channel; ++j) {
122*d9f75844SAndroid Build Coastguard Worker channel[j] = interleaved[interleaved_idx];
123*d9f75844SAndroid Build Coastguard Worker interleaved_idx += num_channels;
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker }
126*d9f75844SAndroid Build Coastguard Worker }
127*d9f75844SAndroid Build Coastguard Worker
128*d9f75844SAndroid Build Coastguard Worker // Interleave audio from the channel buffers pointed to by `deinterleaved` to
129*d9f75844SAndroid Build Coastguard Worker // `interleaved`. There must be sufficient space allocated in `interleaved`
130*d9f75844SAndroid Build Coastguard Worker // (`samples_per_channel` * `num_channels`).
131*d9f75844SAndroid Build Coastguard Worker template <typename T>
Interleave(const T * const * deinterleaved,size_t samples_per_channel,size_t num_channels,T * interleaved)132*d9f75844SAndroid Build Coastguard Worker void Interleave(const T* const* deinterleaved,
133*d9f75844SAndroid Build Coastguard Worker size_t samples_per_channel,
134*d9f75844SAndroid Build Coastguard Worker size_t num_channels,
135*d9f75844SAndroid Build Coastguard Worker T* interleaved) {
136*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < num_channels; ++i) {
137*d9f75844SAndroid Build Coastguard Worker const T* channel = deinterleaved[i];
138*d9f75844SAndroid Build Coastguard Worker size_t interleaved_idx = i;
139*d9f75844SAndroid Build Coastguard Worker for (size_t j = 0; j < samples_per_channel; ++j) {
140*d9f75844SAndroid Build Coastguard Worker interleaved[interleaved_idx] = channel[j];
141*d9f75844SAndroid Build Coastguard Worker interleaved_idx += num_channels;
142*d9f75844SAndroid Build Coastguard Worker }
143*d9f75844SAndroid Build Coastguard Worker }
144*d9f75844SAndroid Build Coastguard Worker }
145*d9f75844SAndroid Build Coastguard Worker
146*d9f75844SAndroid Build Coastguard Worker // Copies audio from a single channel buffer pointed to by `mono` to each
147*d9f75844SAndroid Build Coastguard Worker // channel of `interleaved`. There must be sufficient space allocated in
148*d9f75844SAndroid Build Coastguard Worker // `interleaved` (`samples_per_channel` * `num_channels`).
149*d9f75844SAndroid Build Coastguard Worker template <typename T>
UpmixMonoToInterleaved(const T * mono,int num_frames,int num_channels,T * interleaved)150*d9f75844SAndroid Build Coastguard Worker void UpmixMonoToInterleaved(const T* mono,
151*d9f75844SAndroid Build Coastguard Worker int num_frames,
152*d9f75844SAndroid Build Coastguard Worker int num_channels,
153*d9f75844SAndroid Build Coastguard Worker T* interleaved) {
154*d9f75844SAndroid Build Coastguard Worker int interleaved_idx = 0;
155*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < num_frames; ++i) {
156*d9f75844SAndroid Build Coastguard Worker for (int j = 0; j < num_channels; ++j) {
157*d9f75844SAndroid Build Coastguard Worker interleaved[interleaved_idx++] = mono[i];
158*d9f75844SAndroid Build Coastguard Worker }
159*d9f75844SAndroid Build Coastguard Worker }
160*d9f75844SAndroid Build Coastguard Worker }
161*d9f75844SAndroid Build Coastguard Worker
162*d9f75844SAndroid Build Coastguard Worker template <typename T, typename Intermediate>
DownmixToMono(const T * const * input_channels,size_t num_frames,int num_channels,T * out)163*d9f75844SAndroid Build Coastguard Worker void DownmixToMono(const T* const* input_channels,
164*d9f75844SAndroid Build Coastguard Worker size_t num_frames,
165*d9f75844SAndroid Build Coastguard Worker int num_channels,
166*d9f75844SAndroid Build Coastguard Worker T* out) {
167*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < num_frames; ++i) {
168*d9f75844SAndroid Build Coastguard Worker Intermediate value = input_channels[0][i];
169*d9f75844SAndroid Build Coastguard Worker for (int j = 1; j < num_channels; ++j) {
170*d9f75844SAndroid Build Coastguard Worker value += input_channels[j][i];
171*d9f75844SAndroid Build Coastguard Worker }
172*d9f75844SAndroid Build Coastguard Worker out[i] = value / num_channels;
173*d9f75844SAndroid Build Coastguard Worker }
174*d9f75844SAndroid Build Coastguard Worker }
175*d9f75844SAndroid Build Coastguard Worker
176*d9f75844SAndroid Build Coastguard Worker // Downmixes an interleaved multichannel signal to a single channel by averaging
177*d9f75844SAndroid Build Coastguard Worker // all channels.
178*d9f75844SAndroid Build Coastguard Worker template <typename T, typename Intermediate>
DownmixInterleavedToMonoImpl(const T * interleaved,size_t num_frames,int num_channels,T * deinterleaved)179*d9f75844SAndroid Build Coastguard Worker void DownmixInterleavedToMonoImpl(const T* interleaved,
180*d9f75844SAndroid Build Coastguard Worker size_t num_frames,
181*d9f75844SAndroid Build Coastguard Worker int num_channels,
182*d9f75844SAndroid Build Coastguard Worker T* deinterleaved) {
183*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(num_channels, 0);
184*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(num_frames, 0);
185*d9f75844SAndroid Build Coastguard Worker
186*d9f75844SAndroid Build Coastguard Worker const T* const end = interleaved + num_frames * num_channels;
187*d9f75844SAndroid Build Coastguard Worker
188*d9f75844SAndroid Build Coastguard Worker while (interleaved < end) {
189*d9f75844SAndroid Build Coastguard Worker const T* const frame_end = interleaved + num_channels;
190*d9f75844SAndroid Build Coastguard Worker
191*d9f75844SAndroid Build Coastguard Worker Intermediate value = *interleaved++;
192*d9f75844SAndroid Build Coastguard Worker while (interleaved < frame_end) {
193*d9f75844SAndroid Build Coastguard Worker value += *interleaved++;
194*d9f75844SAndroid Build Coastguard Worker }
195*d9f75844SAndroid Build Coastguard Worker
196*d9f75844SAndroid Build Coastguard Worker *deinterleaved++ = value / num_channels;
197*d9f75844SAndroid Build Coastguard Worker }
198*d9f75844SAndroid Build Coastguard Worker }
199*d9f75844SAndroid Build Coastguard Worker
200*d9f75844SAndroid Build Coastguard Worker template <typename T>
201*d9f75844SAndroid Build Coastguard Worker void DownmixInterleavedToMono(const T* interleaved,
202*d9f75844SAndroid Build Coastguard Worker size_t num_frames,
203*d9f75844SAndroid Build Coastguard Worker int num_channels,
204*d9f75844SAndroid Build Coastguard Worker T* deinterleaved);
205*d9f75844SAndroid Build Coastguard Worker
206*d9f75844SAndroid Build Coastguard Worker template <>
207*d9f75844SAndroid Build Coastguard Worker void DownmixInterleavedToMono<int16_t>(const int16_t* interleaved,
208*d9f75844SAndroid Build Coastguard Worker size_t num_frames,
209*d9f75844SAndroid Build Coastguard Worker int num_channels,
210*d9f75844SAndroid Build Coastguard Worker int16_t* deinterleaved);
211*d9f75844SAndroid Build Coastguard Worker
212*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
213*d9f75844SAndroid Build Coastguard Worker
214*d9f75844SAndroid Build Coastguard Worker #endif // COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
215