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 #include "common_audio/include/audio_util.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/arraysize.h"
14*d9f75844SAndroid Build Coastguard Worker #include "test/gmock.h"
15*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
16*d9f75844SAndroid Build Coastguard Worker
17*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
18*d9f75844SAndroid Build Coastguard Worker namespace {
19*d9f75844SAndroid Build Coastguard Worker
20*d9f75844SAndroid Build Coastguard Worker using ::testing::ElementsAreArray;
21*d9f75844SAndroid Build Coastguard Worker
ExpectArraysEq(const int16_t * ref,const int16_t * test,size_t length)22*d9f75844SAndroid Build Coastguard Worker void ExpectArraysEq(const int16_t* ref, const int16_t* test, size_t length) {
23*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < length; ++i) {
24*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(ref[i], test[i]);
25*d9f75844SAndroid Build Coastguard Worker }
26*d9f75844SAndroid Build Coastguard Worker }
27*d9f75844SAndroid Build Coastguard Worker
ExpectArraysEq(const float * ref,const float * test,size_t length)28*d9f75844SAndroid Build Coastguard Worker void ExpectArraysEq(const float* ref, const float* test, size_t length) {
29*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < length; ++i) {
30*d9f75844SAndroid Build Coastguard Worker EXPECT_NEAR(ref[i], test[i], 0.01f);
31*d9f75844SAndroid Build Coastguard Worker }
32*d9f75844SAndroid Build Coastguard Worker }
33*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,S16ToFloat)34*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, S16ToFloat) {
35*d9f75844SAndroid Build Coastguard Worker static constexpr int16_t kInput[] = {0, 1, -1, 16384, -16384, 32767, -32768};
36*d9f75844SAndroid Build Coastguard Worker static constexpr float kReference[] = {
37*d9f75844SAndroid Build Coastguard Worker 0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f};
38*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kSize = arraysize(kInput);
39*d9f75844SAndroid Build Coastguard Worker static_assert(arraysize(kReference) == kSize, "");
40*d9f75844SAndroid Build Coastguard Worker float output[kSize];
41*d9f75844SAndroid Build Coastguard Worker S16ToFloat(kInput, kSize, output);
42*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kReference, output, kSize);
43*d9f75844SAndroid Build Coastguard Worker }
44*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,FloatS16ToS16)45*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, FloatS16ToS16) {
46*d9f75844SAndroid Build Coastguard Worker static constexpr float kInput[] = {0.f, 0.4f, 0.5f, -0.4f,
47*d9f75844SAndroid Build Coastguard Worker -0.5f, 32768.f, -32769.f};
48*d9f75844SAndroid Build Coastguard Worker static constexpr int16_t kReference[] = {0, 0, 1, 0, -1, 32767, -32768};
49*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kSize = arraysize(kInput);
50*d9f75844SAndroid Build Coastguard Worker static_assert(arraysize(kReference) == kSize, "");
51*d9f75844SAndroid Build Coastguard Worker int16_t output[kSize];
52*d9f75844SAndroid Build Coastguard Worker FloatS16ToS16(kInput, kSize, output);
53*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kReference, output, kSize);
54*d9f75844SAndroid Build Coastguard Worker }
55*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,FloatToFloatS16)56*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, FloatToFloatS16) {
57*d9f75844SAndroid Build Coastguard Worker static constexpr float kInput[] = {0.f,
58*d9f75844SAndroid Build Coastguard Worker 0.4f / 32768.f,
59*d9f75844SAndroid Build Coastguard Worker 0.6f / 32768.f,
60*d9f75844SAndroid Build Coastguard Worker -0.4f / 32768.f,
61*d9f75844SAndroid Build Coastguard Worker -0.6f / 32768.f,
62*d9f75844SAndroid Build Coastguard Worker 1.f,
63*d9f75844SAndroid Build Coastguard Worker -1.f,
64*d9f75844SAndroid Build Coastguard Worker 1.f,
65*d9f75844SAndroid Build Coastguard Worker -1.f};
66*d9f75844SAndroid Build Coastguard Worker static constexpr float kReference[] = {
67*d9f75844SAndroid Build Coastguard Worker 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32768.f, -32768.f, 32768.f, -32768.f};
68*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kSize = arraysize(kInput);
69*d9f75844SAndroid Build Coastguard Worker static_assert(arraysize(kReference) == kSize, "");
70*d9f75844SAndroid Build Coastguard Worker float output[kSize];
71*d9f75844SAndroid Build Coastguard Worker FloatToFloatS16(kInput, kSize, output);
72*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kReference, output, kSize);
73*d9f75844SAndroid Build Coastguard Worker }
74*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,FloatS16ToFloat)75*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, FloatS16ToFloat) {
76*d9f75844SAndroid Build Coastguard Worker static constexpr float kInput[] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f,
77*d9f75844SAndroid Build Coastguard Worker 32767.f, -32768.f, 32767.f, -32768.f};
78*d9f75844SAndroid Build Coastguard Worker static constexpr float kReference[] = {0.f,
79*d9f75844SAndroid Build Coastguard Worker 0.4f / 32768.f,
80*d9f75844SAndroid Build Coastguard Worker 0.6f / 32768.f,
81*d9f75844SAndroid Build Coastguard Worker -0.4f / 32768.f,
82*d9f75844SAndroid Build Coastguard Worker -0.6f / 32768.f,
83*d9f75844SAndroid Build Coastguard Worker 1.f,
84*d9f75844SAndroid Build Coastguard Worker -1.f,
85*d9f75844SAndroid Build Coastguard Worker 1.f,
86*d9f75844SAndroid Build Coastguard Worker -1.f};
87*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kSize = arraysize(kInput);
88*d9f75844SAndroid Build Coastguard Worker static_assert(arraysize(kReference) == kSize, "");
89*d9f75844SAndroid Build Coastguard Worker float output[kSize];
90*d9f75844SAndroid Build Coastguard Worker FloatS16ToFloat(kInput, kSize, output);
91*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kReference, output, kSize);
92*d9f75844SAndroid Build Coastguard Worker }
93*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,DbfsToFloatS16)94*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, DbfsToFloatS16) {
95*d9f75844SAndroid Build Coastguard Worker static constexpr float kInput[] = {-90.f, -70.f, -30.f, -20.f, -10.f,
96*d9f75844SAndroid Build Coastguard Worker -5.f, -1.f, 0.f, 1.f};
97*d9f75844SAndroid Build Coastguard Worker static constexpr float kReference[] = {
98*d9f75844SAndroid Build Coastguard Worker 1.036215186f, 10.36215115f, 1036.215088f, 3276.800049f, 10362.15137f,
99*d9f75844SAndroid Build Coastguard Worker 18426.80078f, 29204.51172f, 32768.f, 36766.30078f};
100*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kSize = arraysize(kInput);
101*d9f75844SAndroid Build Coastguard Worker static_assert(arraysize(kReference) == kSize, "");
102*d9f75844SAndroid Build Coastguard Worker float output[kSize];
103*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < kSize; ++i) {
104*d9f75844SAndroid Build Coastguard Worker output[i] = DbfsToFloatS16(kInput[i]);
105*d9f75844SAndroid Build Coastguard Worker }
106*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kReference, output, kSize);
107*d9f75844SAndroid Build Coastguard Worker }
108*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,FloatS16ToDbfs)109*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, FloatS16ToDbfs) {
110*d9f75844SAndroid Build Coastguard Worker static constexpr float kInput[] = {1.036215143f, 10.36215143f, 1036.215143f,
111*d9f75844SAndroid Build Coastguard Worker 3276.8f, 10362.151436f, 18426.800543f,
112*d9f75844SAndroid Build Coastguard Worker 29204.51074f, 32768.0f, 36766.30071f};
113*d9f75844SAndroid Build Coastguard Worker
114*d9f75844SAndroid Build Coastguard Worker static constexpr float kReference[] = {
115*d9f75844SAndroid Build Coastguard Worker -90.f, -70.f, -30.f, -20.f, -10.f, -5.f, -1.f, 0.f, 0.9999923706f};
116*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kSize = arraysize(kInput);
117*d9f75844SAndroid Build Coastguard Worker static_assert(arraysize(kReference) == kSize, "");
118*d9f75844SAndroid Build Coastguard Worker
119*d9f75844SAndroid Build Coastguard Worker float output[kSize];
120*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < kSize; ++i) {
121*d9f75844SAndroid Build Coastguard Worker output[i] = FloatS16ToDbfs(kInput[i]);
122*d9f75844SAndroid Build Coastguard Worker }
123*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kReference, output, kSize);
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,InterleavingStereo)126*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, InterleavingStereo) {
127*d9f75844SAndroid Build Coastguard Worker const int16_t kInterleaved[] = {2, 3, 4, 9, 8, 27, 16, 81};
128*d9f75844SAndroid Build Coastguard Worker const size_t kSamplesPerChannel = 4;
129*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 2;
130*d9f75844SAndroid Build Coastguard Worker const size_t kLength = kSamplesPerChannel * kNumChannels;
131*d9f75844SAndroid Build Coastguard Worker int16_t left[kSamplesPerChannel], right[kSamplesPerChannel];
132*d9f75844SAndroid Build Coastguard Worker int16_t* deinterleaved[] = {left, right};
133*d9f75844SAndroid Build Coastguard Worker Deinterleave(kInterleaved, kSamplesPerChannel, kNumChannels, deinterleaved);
134*d9f75844SAndroid Build Coastguard Worker const int16_t kRefLeft[] = {2, 4, 8, 16};
135*d9f75844SAndroid Build Coastguard Worker const int16_t kRefRight[] = {3, 9, 27, 81};
136*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kRefLeft, left, kSamplesPerChannel);
137*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kRefRight, right, kSamplesPerChannel);
138*d9f75844SAndroid Build Coastguard Worker
139*d9f75844SAndroid Build Coastguard Worker int16_t interleaved[kLength];
140*d9f75844SAndroid Build Coastguard Worker Interleave(deinterleaved, kSamplesPerChannel, kNumChannels, interleaved);
141*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kInterleaved, interleaved, kLength);
142*d9f75844SAndroid Build Coastguard Worker }
143*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,InterleavingMonoIsIdentical)144*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, InterleavingMonoIsIdentical) {
145*d9f75844SAndroid Build Coastguard Worker const int16_t kInterleaved[] = {1, 2, 3, 4, 5};
146*d9f75844SAndroid Build Coastguard Worker const size_t kSamplesPerChannel = 5;
147*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 1;
148*d9f75844SAndroid Build Coastguard Worker int16_t mono[kSamplesPerChannel];
149*d9f75844SAndroid Build Coastguard Worker int16_t* deinterleaved[] = {mono};
150*d9f75844SAndroid Build Coastguard Worker Deinterleave(kInterleaved, kSamplesPerChannel, kNumChannels, deinterleaved);
151*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(kInterleaved, mono, kSamplesPerChannel);
152*d9f75844SAndroid Build Coastguard Worker
153*d9f75844SAndroid Build Coastguard Worker int16_t interleaved[kSamplesPerChannel];
154*d9f75844SAndroid Build Coastguard Worker Interleave(deinterleaved, kSamplesPerChannel, kNumChannels, interleaved);
155*d9f75844SAndroid Build Coastguard Worker ExpectArraysEq(mono, interleaved, kSamplesPerChannel);
156*d9f75844SAndroid Build Coastguard Worker }
157*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,DownmixInterleavedToMono)158*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, DownmixInterleavedToMono) {
159*d9f75844SAndroid Build Coastguard Worker {
160*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 4;
161*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 1;
162*d9f75844SAndroid Build Coastguard Worker const int16_t interleaved[kNumChannels * kNumFrames] = {1, 2, -1, -3};
163*d9f75844SAndroid Build Coastguard Worker int16_t deinterleaved[kNumFrames];
164*d9f75844SAndroid Build Coastguard Worker
165*d9f75844SAndroid Build Coastguard Worker DownmixInterleavedToMono(interleaved, kNumFrames, kNumChannels,
166*d9f75844SAndroid Build Coastguard Worker deinterleaved);
167*d9f75844SAndroid Build Coastguard Worker
168*d9f75844SAndroid Build Coastguard Worker EXPECT_THAT(deinterleaved, ElementsAreArray(interleaved));
169*d9f75844SAndroid Build Coastguard Worker }
170*d9f75844SAndroid Build Coastguard Worker {
171*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 2;
172*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 2;
173*d9f75844SAndroid Build Coastguard Worker const int16_t interleaved[kNumChannels * kNumFrames] = {10, 20, -10, -30};
174*d9f75844SAndroid Build Coastguard Worker int16_t deinterleaved[kNumFrames];
175*d9f75844SAndroid Build Coastguard Worker
176*d9f75844SAndroid Build Coastguard Worker DownmixInterleavedToMono(interleaved, kNumFrames, kNumChannels,
177*d9f75844SAndroid Build Coastguard Worker deinterleaved);
178*d9f75844SAndroid Build Coastguard Worker const int16_t expected[kNumFrames] = {15, -20};
179*d9f75844SAndroid Build Coastguard Worker
180*d9f75844SAndroid Build Coastguard Worker EXPECT_THAT(deinterleaved, ElementsAreArray(expected));
181*d9f75844SAndroid Build Coastguard Worker }
182*d9f75844SAndroid Build Coastguard Worker {
183*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 3;
184*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 3;
185*d9f75844SAndroid Build Coastguard Worker const int16_t interleaved[kNumChannels * kNumFrames] = {
186*d9f75844SAndroid Build Coastguard Worker 30000, 30000, 24001, -5, -10, -20, -30000, -30999, -30000};
187*d9f75844SAndroid Build Coastguard Worker int16_t deinterleaved[kNumFrames];
188*d9f75844SAndroid Build Coastguard Worker
189*d9f75844SAndroid Build Coastguard Worker DownmixInterleavedToMono(interleaved, kNumFrames, kNumChannels,
190*d9f75844SAndroid Build Coastguard Worker deinterleaved);
191*d9f75844SAndroid Build Coastguard Worker const int16_t expected[kNumFrames] = {28000, -11, -30333};
192*d9f75844SAndroid Build Coastguard Worker
193*d9f75844SAndroid Build Coastguard Worker EXPECT_THAT(deinterleaved, ElementsAreArray(expected));
194*d9f75844SAndroid Build Coastguard Worker }
195*d9f75844SAndroid Build Coastguard Worker }
196*d9f75844SAndroid Build Coastguard Worker
TEST(AudioUtilTest,DownmixToMonoTest)197*d9f75844SAndroid Build Coastguard Worker TEST(AudioUtilTest, DownmixToMonoTest) {
198*d9f75844SAndroid Build Coastguard Worker {
199*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 4;
200*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 1;
201*d9f75844SAndroid Build Coastguard Worker const float input_data[kNumChannels][kNumFrames] = {{1.f, 2.f, -1.f, -3.f}};
202*d9f75844SAndroid Build Coastguard Worker const float* input[kNumChannels];
203*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kNumChannels; ++i) {
204*d9f75844SAndroid Build Coastguard Worker input[i] = input_data[i];
205*d9f75844SAndroid Build Coastguard Worker }
206*d9f75844SAndroid Build Coastguard Worker
207*d9f75844SAndroid Build Coastguard Worker float downmixed[kNumFrames];
208*d9f75844SAndroid Build Coastguard Worker
209*d9f75844SAndroid Build Coastguard Worker DownmixToMono<float, float>(input, kNumFrames, kNumChannels, downmixed);
210*d9f75844SAndroid Build Coastguard Worker
211*d9f75844SAndroid Build Coastguard Worker EXPECT_THAT(downmixed, ElementsAreArray(input_data[0]));
212*d9f75844SAndroid Build Coastguard Worker }
213*d9f75844SAndroid Build Coastguard Worker {
214*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 3;
215*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 2;
216*d9f75844SAndroid Build Coastguard Worker const float input_data[kNumChannels][kNumFrames] = {{1.f, 2.f, -1.f},
217*d9f75844SAndroid Build Coastguard Worker {3.f, 0.f, 1.f}};
218*d9f75844SAndroid Build Coastguard Worker const float* input[kNumChannels];
219*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kNumChannels; ++i) {
220*d9f75844SAndroid Build Coastguard Worker input[i] = input_data[i];
221*d9f75844SAndroid Build Coastguard Worker }
222*d9f75844SAndroid Build Coastguard Worker
223*d9f75844SAndroid Build Coastguard Worker float downmixed[kNumFrames];
224*d9f75844SAndroid Build Coastguard Worker const float expected[kNumFrames] = {2.f, 1.f, 0.f};
225*d9f75844SAndroid Build Coastguard Worker
226*d9f75844SAndroid Build Coastguard Worker DownmixToMono<float, float>(input, kNumFrames, kNumChannels, downmixed);
227*d9f75844SAndroid Build Coastguard Worker
228*d9f75844SAndroid Build Coastguard Worker EXPECT_THAT(downmixed, ElementsAreArray(expected));
229*d9f75844SAndroid Build Coastguard Worker }
230*d9f75844SAndroid Build Coastguard Worker {
231*d9f75844SAndroid Build Coastguard Worker const size_t kNumFrames = 3;
232*d9f75844SAndroid Build Coastguard Worker const int kNumChannels = 3;
233*d9f75844SAndroid Build Coastguard Worker const int16_t input_data[kNumChannels][kNumFrames] = {
234*d9f75844SAndroid Build Coastguard Worker {30000, -5, -30000}, {30000, -10, -30999}, {24001, -20, -30000}};
235*d9f75844SAndroid Build Coastguard Worker const int16_t* input[kNumChannels];
236*d9f75844SAndroid Build Coastguard Worker for (int i = 0; i < kNumChannels; ++i) {
237*d9f75844SAndroid Build Coastguard Worker input[i] = input_data[i];
238*d9f75844SAndroid Build Coastguard Worker }
239*d9f75844SAndroid Build Coastguard Worker
240*d9f75844SAndroid Build Coastguard Worker int16_t downmixed[kNumFrames];
241*d9f75844SAndroid Build Coastguard Worker const int16_t expected[kNumFrames] = {28000, -11, -30333};
242*d9f75844SAndroid Build Coastguard Worker
243*d9f75844SAndroid Build Coastguard Worker DownmixToMono<int16_t, int32_t>(input, kNumFrames, kNumChannels, downmixed);
244*d9f75844SAndroid Build Coastguard Worker
245*d9f75844SAndroid Build Coastguard Worker EXPECT_THAT(downmixed, ElementsAreArray(expected));
246*d9f75844SAndroid Build Coastguard Worker }
247*d9f75844SAndroid Build Coastguard Worker }
248*d9f75844SAndroid Build Coastguard Worker
249*d9f75844SAndroid Build Coastguard Worker } // namespace
250*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
251