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