xref: /aosp_15_r20/external/webrtc/common_audio/include/audio_util.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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