1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <math.h>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <audio_utils/primitives.h>
23 #include <audio_utils/format.h>
24 #include <audio_utils/channels.h>
25
26 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
27
28 static const int32_t lim8pos = 255;
29 static const int32_t lim8neg = 0;
30 static const int32_t lim16pos = (1 << 15) - 1;
31 static const int32_t lim16neg = -(1 << 15);
32 static const int32_t lim24pos = (1 << 23) - 1;
33 static const int32_t lim24neg = -(1 << 23);
34 static const int64_t lim32pos = 0x000000007fffffff;
35 static const int64_t lim32neg = 0xffffffff80000000;
36
37 // Use memset here since it is generally the fastest method of clearing data,
38 // but could be changed to std::fill or assignment should those prove faster.
39 template <typename T>
zeroFill(T & container)40 static void zeroFill(T &container) {
41 memset(container.data(), 0, container.size() * sizeof(container[0]));
42 }
43
testClamp8(float f)44 inline void testClamp8(float f)
45 {
46 // f is in native u8 scaling to test rounding
47 uint8_t uval = clamp8_from_float((f - 128) / (1 << 7));
48
49 // test clamping
50 if (f > lim8pos) {
51 EXPECT_EQ(lim8pos, uval);
52 } else if (f < lim8neg) {
53 EXPECT_EQ(lim8neg, uval);
54 }
55
56 // if in range, make sure round trip clamp and conversion is correct.
57 if (f < lim8pos - 1. && f > lim8neg + 1.) {
58 uint8_t uval2 = clamp8_from_float(float_from_u8(uval));
59 int diff = abs(uval - uval2);
60 EXPECT_LE(diff, 1);
61 }
62 }
63
testClamp16(float f)64 inline void testClamp16(float f)
65 {
66 int16_t ival = clamp16_from_float(f / (1 << 15));
67
68 // test clamping
69 if (f > lim16pos) {
70 EXPECT_EQ(lim16pos, ival);
71 } else if (f < lim16neg) {
72 EXPECT_EQ(lim16neg, ival);
73 }
74
75 // if in range, make sure round trip clamp and conversion is correct.
76 if (f < lim16pos - 1. && f > lim16neg + 1.) {
77 int ival2 = clamp16_from_float(float_from_i16(ival));
78 int diff = abs(ival - ival2);
79 EXPECT_LE(diff, 1);
80 }
81 }
82
testClamp24(float f)83 inline void testClamp24(float f)
84 {
85 int32_t ival = clamp24_from_float(f / (1 << 23));
86
87 // test clamping
88 if (f > lim24pos) {
89 EXPECT_EQ(lim24pos, ival);
90 } else if (f < lim24neg) {
91 EXPECT_EQ(lim24neg, ival);
92 }
93
94 // if in range, make sure round trip clamp and conversion is correct.
95 if (f < lim24pos - 1. && f > lim24neg + 1.) {
96 int ival2 = clamp24_from_float(float_from_q8_23(ival));
97 int diff = abs(ival - ival2);
98 EXPECT_LE(diff, 1);
99 }
100 }
101
102 template<typename T>
checkMonotone(const T * ary,size_t size)103 void checkMonotone(const T *ary, size_t size)
104 {
105 for (size_t i = 1; i < size; ++i) {
106 EXPECT_LT(ary[i-1], ary[i]);
107 }
108 }
109
checkMonotonep24(uint8_t * pary,size_t size)110 void checkMonotonep24(uint8_t * pary, size_t size)
111 {
112 size_t frames = size/3;
113 for (size_t i = 1; i < frames; ++i) {
114 EXPECT_LT(i32_from_p24(pary + 3*(i-1)), i32_from_p24(pary + 3*i));
115 }
116 }
117
TEST(audio_utils_primitives,clamp_to_int)118 TEST(audio_utils_primitives, clamp_to_int) {
119 static const float testArray[] = {
120 -NAN, -INFINITY,
121 -1.e20, -32768., 63.9,
122 -3.5, -3.4, -2.5, 2.4, -1.5, -1.4, -0.5, -0.2, 0., 0.2, 0.5, 0.8,
123 1.4, 1.5, 1.8, 2.4, 2.5, 2.6, 3.4, 3.5,
124 32767., 32768., 1.e20,
125 INFINITY, NAN };
126
127 for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
128 testClamp8(testArray[i]);
129 }
130 for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
131 testClamp16(testArray[i]);
132 }
133 for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
134 testClamp24(testArray[i]);
135 }
136
137 // used for ULP testing (tweaking the lsb of the float)
138 union {
139 int32_t i;
140 float f;
141 } val;
142 int32_t res;
143
144 // check clampq4_27_from_float()
145 val.f = 16.;
146 res = clampq4_27_from_float(val.f);
147 EXPECT_EQ(0x7fffffff, res);
148 val.i--;
149 res = clampq4_27_from_float(val.f);
150 EXPECT_LE(res, 0x7fffffff);
151 EXPECT_GE(res, 0x7fff0000);
152 val.f = -16.;
153 res = clampq4_27_from_float(val.f);
154 EXPECT_EQ((int32_t)0x80000000, res); // negative
155 val.i++;
156 res = clampq4_27_from_float(val.f);
157 EXPECT_GE(res, (int32_t)0x80000000); // negative
158 EXPECT_LE(res, (int32_t)0x80008000); // negative
159
160 // check u4_28_from_float and u4_12_from_float
161 uint32_t ures;
162 uint16_t ures16;
163 val.f = 16.;
164 ures = u4_28_from_float(val.f);
165 EXPECT_EQ(0xffffffff, ures);
166 ures16 = u4_12_from_float(val.f);
167 EXPECT_EQ(0xffff, ures16);
168
169 val.f = -1.;
170 ures = u4_28_from_float(val.f);
171 EXPECT_EQ((uint32_t)0, ures);
172 ures16 = u4_12_from_float(val.f);
173 EXPECT_EQ(0, ures16);
174
175 // check float_from_u4_28 and float_from_u4_12 (roundtrip)
176 for (uint32_t v = 0x100000; v <= 0xff000000; v += 0x100000) {
177 ures = u4_28_from_float(float_from_u4_28(v));
178 EXPECT_EQ(ures, v);
179 }
180 for (uint32_t v = 0; v <= 0xffff; ++v) { // uint32_t prevents overflow
181 ures16 = u4_12_from_float(float_from_u4_12(v));
182 EXPECT_EQ(ures16, v);
183 }
184
185 // check infinity
186 EXPECT_EQ(0, clamp8_from_float(-INFINITY));
187 EXPECT_EQ(255, clamp8_from_float(INFINITY));
188 }
189
TEST(audio_utils_primitives,memcpy)190 TEST(audio_utils_primitives, memcpy) {
191 // test round-trip.
192 constexpr size_t size = 65536;
193 std::vector<int16_t> i16ref(size);
194 std::vector<int16_t> i16ary(size);
195 std::vector<int32_t> i32ary(size);
196 std::vector<float> fary(size);
197 std::vector<uint8_t> pary(size * 3);
198
199
200 // set signed reference monotonic array from -32768 to 32767
201 for (size_t i = 0; i < i16ref.size(); ++i) {
202 i16ref[i] = i16ary[i] = i - 32768;
203 }
204
205 // do round-trip testing i16 and float
206 memcpy_to_float_from_i16(fary.data(), i16ary.data(), fary.size());
207 zeroFill(i16ary);
208 checkMonotone(fary.data(), fary.size());
209
210 memcpy_to_i16_from_float(i16ary.data(), fary.data(), i16ary.size());
211 zeroFill(fary);
212 checkMonotone(i16ary.data(), i16ary.size());
213
214 // TODO make a template case for the following?
215
216 // do round-trip testing p24 to i16 and float
217 memcpy_to_p24_from_i16(pary.data(), i16ary.data(), size /* note pary elem is 3 bytes */);
218 zeroFill(i16ary);
219
220 // check an intermediate format at a position(???)
221 #if 0
222 printf("pary[%d].0 = %u pary[%d].1 = %u pary[%d].2 = %u\n",
223 1025, (unsigned) pary[1025*3],
224 1025, (unsigned) pary[1025*3+1],
225 1025, (unsigned) pary[1025*3+2]
226 );
227 #endif
228
229 memcpy_to_float_from_p24(fary.data(), pary.data(), fary.size());
230 zeroFill(pary);
231 checkMonotone(fary.data(), fary.size());
232
233 memcpy_to_p24_from_float(pary.data(), fary.data(), size /* note pary elem is 3 bytes */);
234 zeroFill(fary);
235 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/);
236
237 memcpy_to_i16_from_p24(i16ary.data(), pary.data(), i16ary.size());
238 zeroFill(pary);
239 checkMonotone(i16ary.data(), i16ary.size());
240
241 // do round-trip testing q8_23 to i16 and float
242 memcpy_to_q8_23_from_i16(i32ary.data(), i16ary.data(), i32ary.size());
243 zeroFill(i16ary);
244 checkMonotone(i32ary.data(), i32ary.size());
245
246 memcpy_to_float_from_q8_23(fary.data(), i32ary.data(), fary.size());
247 zeroFill(i32ary);
248 checkMonotone(fary.data(), fary.size());
249
250 memcpy_to_q8_23_from_float_with_clamp(i32ary.data(), fary.data(), i32ary.size());
251 zeroFill(fary);
252 checkMonotone(i32ary.data(), i32ary.size());
253
254 memcpy_to_i16_from_q8_23(i16ary.data(), i32ary.data(), i16ary.size());
255 zeroFill(i32ary);
256 checkMonotone(i16ary.data(), i16ary.size());
257
258 // do round-trip testing i32 to i16 and float
259 memcpy_to_i32_from_i16(i32ary.data(), i16ary.data(), i32ary.size());
260 zeroFill(i16ary);
261 checkMonotone(i32ary.data(), i32ary.size());
262
263 memcpy_to_float_from_i32(fary.data(), i32ary.data(), fary.size());
264 zeroFill(i32ary);
265 checkMonotone(fary.data(), fary.size());
266
267 memcpy_to_i32_from_float(i32ary.data(), fary.data(), i32ary.size());
268 zeroFill(fary);
269 checkMonotone(i32ary.data(), i32ary.size());
270
271 memcpy_to_i16_from_i32(i16ary.data(), i32ary.data(), i16ary.size());
272 zeroFill(i32ary);
273 checkMonotone(i16ary.data(), i16ary.size());
274
275 // do round-trip test i16 -> p24 -> i32 -> p24 -> q8_23 -> p24 -> i16
276 memcpy_to_p24_from_i16(pary.data(), i16ary.data(), size /* note pary elem is 3 bytes */);
277 zeroFill(i16ary);
278 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/);
279
280 memcpy_to_i32_from_p24(i32ary.data(), pary.data(), i32ary.size());
281 zeroFill(pary);
282 checkMonotone(i32ary.data(), i32ary.size());
283
284 memcpy_to_p24_from_i32(pary.data(), i32ary.data(), size /* note pary elem is 3 bytes */);
285 zeroFill(i32ary);
286 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/);
287
288 memcpy_to_q8_23_from_p24(i32ary.data(), pary.data(), i32ary.size());
289 zeroFill(pary);
290 checkMonotone(i32ary.data(), i32ary.size());
291
292 memcpy_to_p24_from_q8_23(pary.data(), i32ary.data(), size /* note pary elem is 3 bytes */);
293 zeroFill(i32ary);
294 checkMonotonep24(pary.data(), pary.size() /* this is * 3*/);
295
296 memcpy_to_i16_from_p24(i16ary.data(), pary.data(), i16ary.size());
297 zeroFill(pary);
298 checkMonotone(i16ary.data(), i16ary.size());
299
300 // do partial round-trip testing q4_27 to i16 and float
301 memcpy_to_float_from_i16(fary.data(), i16ary.data(), fary.size());
302 zeroFill(i16ary);
303
304 memcpy_to_q4_27_from_float(i32ary.data(), fary.data(), i32ary.size());
305 zeroFill(fary);
306 checkMonotone(i32ary.data(), i32ary.size());
307
308 memcpy_to_i16_from_q4_27(i16ary.data(), i32ary.data(), i16ary.size());
309 checkMonotone(i16ary.data(), i16ary.size());
310 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), i16ary.size() * sizeof(i16ary[0])));
311
312 zeroFill(i16ary);
313
314 // ditherAndClamp() has non-standard parameters - memcpy_to_float_from_q4_27() is preferred
315 ditherAndClamp(reinterpret_cast<int32_t *>(i16ary.data()),
316 i32ary.data(), i16ary.size() / 2);
317 checkMonotone(i16ary.data(), i16ary.size());
318 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), i16ary.size() * sizeof(i16ary[0])));
319
320 memcpy_to_float_from_q4_27(fary.data(), i32ary.data(), fary.size());
321 zeroFill(i32ary);
322 checkMonotone(fary.data(), fary.size());
323
324 // at the end, our i16ary must be the same. (Monotone should be equivalent to this)
325 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), i16ary.size() * sizeof(i16ary[0])));
326
327 // test round-trip for u8 and float.
328 constexpr size_t u8size = 256;
329 std::vector<uint8_t> u8ref(u8size);
330 std::vector<uint8_t> u8ary(u8size);
331
332 for (size_t i = 0; i < u8ref.size(); ++i) {
333 u8ref[i] = i;
334 }
335
336 constexpr size_t testsize = std::min(u8size, size);
337 zeroFill(fary);
338 memcpy_to_float_from_u8(fary.data(), u8ref.data(), testsize);
339 memcpy_to_u8_from_float(u8ary.data(), fary.data(), testsize);
340
341 EXPECT_EQ(0, memcmp(u8ary.data(), u8ref.data(), u8ary.size() * sizeof(u8ary[0])));
342
343 // test conversion from u8 to i32
344 zeroFill(i32ary);
345 memcpy_to_i32_from_u8(i32ary.data(), u8ref.data(), testsize);
346 checkMonotone(i32ary.data(), testsize);
347 }
348
349 template<typename T>
checkMonotoneOrZero(const T * ary,size_t size)350 void checkMonotoneOrZero(const T *ary, size_t size)
351 {
352 T least = 0;
353
354 for (size_t i = 1; i < size; ++i) {
355 if (ary[i]) {
356 EXPECT_LT(least, ary[i]);
357 least = ary[i];
358 }
359 }
360 }
361
TEST(audio_utils_primitives,memcpy_by_channel_mask)362 TEST(audio_utils_primitives, memcpy_by_channel_mask) {
363 uint32_t dst_mask;
364 uint32_t src_mask;
365 uint16_t *u16ref = new uint16_t[65536];
366 uint16_t *u16ary = new uint16_t[65536];
367
368 for (size_t i = 0; i < 65536; ++i) {
369 u16ref[i] = i;
370 }
371
372 // Test when src mask is 0. Everything copied is zero.
373 src_mask = 0;
374 dst_mask = 0x8d;
375 memset(u16ary, 0x99, 65536 * sizeof(u16ref[0]));
376 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
377 65536 / __builtin_popcount(dst_mask));
378 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
379
380 // Test when dst_mask is 0. Nothing should be copied.
381 src_mask = 0;
382 dst_mask = 0;
383 memset(u16ary, 0, 65536 * sizeof(u16ref[0]));
384 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
385 65536);
386 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
387
388 // Test when masks are the same. One to one copy.
389 src_mask = dst_mask = 0x8d;
390 memset(u16ary, 0x99, 65536 * sizeof(u16ref[0]));
391 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 555);
392 EXPECT_EQ(0, memcmp(u16ary, u16ref, 555 * sizeof(u16ref[0]) * __builtin_popcount(dst_mask)));
393
394 // Test with a gap in source:
395 // Input 3 samples, output 4 samples, one zero inserted.
396 src_mask = 0x8c;
397 dst_mask = 0x8d;
398 memset(u16ary, 0x9, 65536 * sizeof(u16ary[0]));
399 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
400 65536 / __builtin_popcount(dst_mask));
401 checkMonotoneOrZero(u16ary, 65536);
402 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
403
404 // Test with a gap in destination:
405 // Input 4 samples, output 3 samples, one deleted
406 src_mask = 0x8d;
407 dst_mask = 0x8c;
408 memset(u16ary, 0x9, 65536 * sizeof(u16ary[0]));
409 memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
410 65536 / __builtin_popcount(src_mask));
411 checkMonotone(u16ary, 65536 * 3 / 4);
412
413 delete[] u16ref;
414 delete[] u16ary;
415 }
416
memcpy_by_channel_mask2(void * dst,uint32_t dst_mask,const void * src,uint32_t src_mask,size_t sample_size,size_t count)417 void memcpy_by_channel_mask2(void *dst, uint32_t dst_mask,
418 const void *src, uint32_t src_mask, size_t sample_size, size_t count)
419 {
420 int8_t idxary[32];
421 uint32_t src_channels = __builtin_popcount(src_mask);
422 uint32_t dst_channels =
423 memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask);
424
425 memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
426 }
427
428 // a modified version of the memcpy_by_channel_mask test
429 // but using 24 bit type and memcpy_by_index_array()
TEST(audio_utils_primitives,memcpy_by_index_array)430 TEST(audio_utils_primitives, memcpy_by_index_array) {
431 uint32_t dst_mask;
432 uint32_t src_mask;
433 typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
434 uint8x3_t *u24ref = new uint8x3_t[65536];
435 uint8x3_t *u24ary = new uint8x3_t[65536];
436 uint16_t *u16ref = new uint16_t[65536];
437 uint16_t *u16ary = new uint16_t[65536];
438
439 EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
440
441 // tests prepare_index_array_from_masks()
442 EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization(NULL, 0, 0x8d, 0x8c));
443 EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization(NULL, 0, 0x8c, 0x8d));
444
445 for (size_t i = 0; i < 65536; ++i) {
446 u16ref[i] = i;
447 }
448 memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
449
450 // Test when src mask is 0. Everything copied is zero.
451 src_mask = 0;
452 dst_mask = 0x8d;
453 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
454 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
455 65536 / __builtin_popcount(dst_mask));
456 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
457 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
458
459 // Test when dst_mask is 0. Nothing should be copied.
460 src_mask = 0;
461 dst_mask = 0;
462 memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
463 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
464 65536);
465 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
466 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
467
468 // Test when masks are the same. One to one copy.
469 src_mask = dst_mask = 0x8d;
470 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
471 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
472 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * __builtin_popcount(dst_mask)));
473
474 // Test with a gap in source:
475 // Input 3 samples, output 4 samples, one zero inserted.
476 src_mask = 0x8c;
477 dst_mask = 0x8d;
478 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
479 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
480 65536 / __builtin_popcount(dst_mask));
481 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
482 checkMonotoneOrZero(u16ary, 65536);
483 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
484
485 // Test with a gap in destination:
486 // Input 4 samples, output 3 samples, one deleted
487 src_mask = 0x8d;
488 dst_mask = 0x8c;
489 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
490 memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
491 65536 / __builtin_popcount(src_mask));
492 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
493 checkMonotone(u16ary, 65536 * 3 / 4);
494
495 delete[] u16ref;
496 delete[] u16ary;
497 delete[] u24ref;
498 delete[] u24ary;
499 }
500
memcpy_by_channel_mask_dst_index(void * dst,uint32_t dst_mask,const void * src,uint32_t src_mask,size_t sample_size,size_t count)501 void memcpy_by_channel_mask_dst_index(void *dst, uint32_t dst_mask,
502 const void *src, uint32_t src_mask, size_t sample_size, size_t count)
503 {
504 int8_t idxary[32];
505 uint32_t src_channels = __builtin_popcount(src_mask);
506 uint32_t dst_channels =
507 memcpy_by_index_array_initialization_dst_index(idxary, 32, dst_mask, src_mask);
508
509 memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
510 }
511
512 // a modified version of the memcpy_by_channel_mask test
513 // but using 24 bit type and memcpy_by_index_array()
TEST(audio_utils_primitives,memcpy_by_index_array_dst_index)514 TEST(audio_utils_primitives, memcpy_by_index_array_dst_index) {
515 uint32_t dst_mask;
516 uint32_t src_mask;
517 typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
518 uint8x3_t *u24ref = new uint8x3_t[65536];
519 uint8x3_t *u24ary = new uint8x3_t[65536];
520 uint16_t *u16ref = new uint16_t[65536];
521 uint16_t *u16ary = new uint16_t[65536];
522
523 EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
524
525 // tests prepare_index_array_from_masks()
526 EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8d, 0x8c));
527 EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8c, 0x8d));
528
529 for (size_t i = 0; i < 65536; ++i) {
530 u16ref[i] = i;
531 }
532 memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
533
534 // Test when src mask is 0. Everything copied is zero.
535 src_mask = 0;
536 dst_mask = 0x8d;
537 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
538 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
539 65536 / __builtin_popcount(dst_mask));
540 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
541 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
542
543 // Test when dst_mask is 0. Nothing should be copied.
544 src_mask = 0;
545 dst_mask = 0;
546 memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
547 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
548 65536);
549 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
550 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
551
552 // Test when dst mask equals source count size. One to one copy.
553 src_mask = 0x8d;
554 dst_mask = 0x0f;
555 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
556 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
557 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * __builtin_popcount(dst_mask)));
558
559 // Test with a gap in source:
560 // Input 3 samples, output 4 samples, one zero inserted.
561 src_mask = 0x8c;
562 dst_mask = 0x0f;
563 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
564 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
565 65536 / __builtin_popcount(dst_mask));
566 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
567 checkMonotoneOrZero(u16ary, 65536);
568 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
569
570 // Test with a gap in destination:
571 // Input 4 samples, output 3 samples, one deleted
572 src_mask = 0x8d;
573 dst_mask = 0x07;
574 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
575 memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
576 65536 / __builtin_popcount(src_mask));
577 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
578 checkMonotone(u16ary, 65536 * 3 / 4);
579
580 delete[] u16ref;
581 delete[] u16ary;
582 delete[] u24ref;
583 delete[] u24ary;
584 }
585
memcpy_by_channel_mask_src_index(void * dst,uint32_t dst_mask,const void * src,uint32_t src_mask,size_t sample_size,size_t count)586 void memcpy_by_channel_mask_src_index(void *dst, uint32_t dst_mask,
587 const void *src, uint32_t src_mask, size_t sample_size, size_t count)
588 {
589 int8_t idxary[32];
590 uint32_t src_channels = __builtin_popcount(src_mask);
591 uint32_t dst_channels =
592 memcpy_by_index_array_initialization_src_index(idxary, 32, dst_mask, src_mask);
593
594 memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
595 }
596
597 // a modified version of the memcpy_by_channel_mask test
598 // but using 24 bit type and memcpy_by_index_array()
TEST(audio_utils_primitives,memcpy_by_index_array_src_index)599 TEST(audio_utils_primitives, memcpy_by_index_array_src_index) {
600 uint32_t dst_mask;
601 uint32_t src_mask;
602 typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
603 uint8x3_t *u24ref = new uint8x3_t[65536];
604 uint8x3_t *u24ary = new uint8x3_t[65536];
605 uint16_t *u16ref = new uint16_t[65536];
606 uint16_t *u16ary = new uint16_t[65536];
607
608 EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
609
610 // tests prepare_index_array_from_masks()
611 EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8d, 0x8c));
612 EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8c, 0x8d));
613
614 for (size_t i = 0; i < 65536; ++i) {
615 u16ref[i] = i;
616 }
617 memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
618
619 // Test when src mask is 0. Everything copied is zero.
620 src_mask = 0;
621 dst_mask = 0x8d;
622 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
623 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
624 65536 / __builtin_popcount(dst_mask));
625 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
626 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
627
628 // Test when dst_mask is 0. Nothing should be copied.
629 src_mask = 0;
630 dst_mask = 0;
631 memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
632 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
633 65536);
634 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
635 EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
636
637 // Test when source mask must copy to dst mask. One to one copy.
638 src_mask = 0xf;
639 dst_mask = 0xf;
640 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
641 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
642 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * __builtin_popcount(dst_mask)));
643
644 // Test when source mask must copy to dst mask. One to one copy.
645 src_mask = 0xf;
646 dst_mask = 0x8d;
647 memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
648 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
649 EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * __builtin_popcount(dst_mask)));
650
651 // Test with a gap in source:
652 // Input 3 samples, output 4 samples, one zero inserted.
653 src_mask = 0x07;
654 dst_mask = 0x8d;
655 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
656 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
657 65536 / __builtin_popcount(dst_mask));
658 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
659 checkMonotoneOrZero(u16ary, 65536);
660 EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
661
662 // Test with a gap in destination:
663 // Input 4 samples, output 3 samples, one deleted
664 src_mask = 0x0f;
665 dst_mask = 0x8c;
666 memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
667 memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
668 65536 / __builtin_popcount(src_mask));
669 memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
670 checkMonotone(u16ary, 65536 * 3 / 4);
671
672 delete[] u16ref;
673 delete[] u16ary;
674 delete[] u24ref;
675 delete[] u24ary;
676 }
677
TEST(audio_utils_primitives,updown_mix)678 TEST(audio_utils_primitives, updown_mix) {
679 const size_t size = 32767;
680 std::vector<int16_t> i16ref(size * 2);
681 std::vector<int16_t> i16ary(size * 2);
682
683 for (size_t i = 0; i < size; ++i) {
684 i16ref[i] = i;
685 }
686 upmix_to_stereo_i16_from_mono_i16(i16ary.data(), i16ref.data(), size);
687 downmix_to_mono_i16_from_stereo_i16(i16ary.data(), i16ary.data(), size);
688
689 EXPECT_EQ(0, memcmp(i16ary.data(), i16ref.data(), sizeof(i16ref[0]) * size));
690 }
691
692 template<typename T, typename TComparison>
checkAddedClamped(T * out,const T * in1,const T * in2,size_t size,TComparison limNeg,TComparison limPos)693 void checkAddedClamped(T *out, const T *in1, const T *in2, size_t size,
694 TComparison limNeg, TComparison limPos)
695 {
696 for (size_t i = 0; i < size; ++i) {
697 TComparison added = (TComparison)in1[i] + in2[i];
698 if (added <= limNeg) {
699 EXPECT_EQ(limNeg, out[i]);
700 } else if (added >= limPos) {
701 EXPECT_EQ(limPos, out[i]);
702 } else {
703 EXPECT_EQ(added, out[i]);
704 }
705 }
706 }
707
checkAddedClampedp24(uint8_t * pary,const uint8_t * in1,const uint8_t * in2,size_t size)708 void checkAddedClampedp24(uint8_t *pary, const uint8_t *in1,
709 const uint8_t *in2, size_t size) {
710 // Convert to q8_23 for comparison.
711 int32_t *outi32ary = new int32_t[size];
712 int32_t *in1i32ary = new int32_t[size];
713 int32_t *in2i32ary = new int32_t[size];
714 memcpy_to_q8_23_from_p24(outi32ary, pary, size);
715 memcpy_to_q8_23_from_p24(in1i32ary, in1, size);
716 memcpy_to_q8_23_from_p24(in2i32ary, in2, size);
717 checkAddedClamped(
718 outi32ary, in1i32ary, in2i32ary, size, lim24neg, lim24pos);
719 delete[] in2i32ary;
720 delete[] in1i32ary;
721 delete[] outi32ary;
722 }
723
checkAddedClampedu8(uint8_t * out,const uint8_t * in1,const uint8_t * in2,size_t size)724 void checkAddedClampedu8(uint8_t *out, const uint8_t *in1,
725 const uint8_t *in2, size_t size) {
726 // uint8_t data is centered around 0x80, not 0, so checkAddedClamped
727 // won't work. Convert to i16 first.
728 int16_t *outi16ary = new int16_t[size];
729 int16_t *in1i16ary = new int16_t[size];
730 int16_t *in2i16ary = new int16_t[size];
731 memcpy_to_i16_from_u8(outi16ary, out, size);
732 memcpy_to_i16_from_u8(in1i16ary, in1, size);
733 memcpy_to_i16_from_u8(in2i16ary, in2, size);
734 // Only the higher order bits are used.
735 checkAddedClamped(outi16ary, in1i16ary, in2i16ary, size,
736 -0x8000, 0x7f00);
737 delete[] in2i16ary;
738 delete[] in1i16ary;
739 delete[] outi16ary;
740 }
741
TEST(audio_utils_primitives,accumulate)742 TEST(audio_utils_primitives, accumulate) {
743 int16_t *i16ref = new int16_t[65536];
744 int16_t *i16add = new int16_t[65536];
745 int16_t *i16ary = new int16_t[65536];
746
747 for (size_t i = 0; i < 65536; ++i) {
748 i16ref[i] = i16ary[i] = i16add[(i+1) % 65536] = i - 32768;
749 }
750
751 // Test i16.
752 accumulate_i16(i16ary, i16add, 65536);
753 checkAddedClamped(i16ary, i16ref, i16add, 65536, lim16neg,
754 lim16pos);
755
756 // Test i32.
757 int32_t *i32ary = new int32_t[65536];
758 int32_t *i32add = new int32_t[65536];
759 int32_t *i32ref = new int32_t[65536];
760 // Convert sample data to i32 to perform accumulate function.
761 memcpy_to_i32_from_i16(i32ary, i16ref, 65536);
762 memcpy_to_i32_from_i16(i32add, i16add, 65536);
763 // Ensure the reference matches the inital output after conversion.
764 memcpy(i32ref, i32ary, 65536 * sizeof(i32ary[0]));
765 // Accumulate and check.
766 accumulate_i32(i32ary, i32add, 65536);
767 checkAddedClamped(
768 i32ary, i32ref, i32add, 65536, lim32neg, lim32pos);
769 // Cleanup
770 delete[] i32ref;
771 delete[] i32add;
772 delete[] i32ary;
773
774 // Test u8.
775 uint8_t *u8ary = new uint8_t[65536];
776 uint8_t *u8add = new uint8_t[65536];
777 uint8_t *u8ref = new uint8_t[65536];
778 // Convert sample data to u8 to perform accumulate function.
779 memcpy_to_u8_from_i16(u8ary, i16ref, 65536);
780 memcpy_to_u8_from_i16(u8add, i16add, 65536);
781 // Ensure the reference matches the inital output after conversion.
782 memcpy(u8ref, u8ary, 65536 * sizeof(u8ary[0]));
783 // Accumulate and check.
784 accumulate_u8(u8ary, u8add, 65536);
785 checkAddedClampedu8(u8ary, u8ref, u8add, 65536);
786 // Cleanup.
787 delete[] u8ref;
788 delete[] u8add;
789 delete[] u8ary;
790
791 // Test 24 bit packed.
792 uint8_t *pary = new uint8_t[65536 * 3];
793 uint8_t *padd = new uint8_t[65536 * 3];
794 uint8_t *pref = new uint8_t[65536 * 3];
795 // Convert sample data to p24 to perform accumulate function.
796 memcpy_to_p24_from_i16(pary, i16ref, 65536);
797 memcpy_to_p24_from_i16(padd, i16add, 65536);
798 // Ensure the reference matches the inital output after conversion.
799 memcpy(pref, pary, 65536 * sizeof(pary[0]) * 3);
800 // Accumulate and check.
801 accumulate_p24(pary, padd, 65536);
802 checkAddedClampedp24(pary, pref, padd, 65536);
803 // Cleanup.
804 delete[] pref;
805 delete[] padd;
806 delete[] pary;
807
808 // Test 24 bit unpacked.
809 int32_t *q8_23ary = new int32_t[65536];
810 int32_t *q8_23add = new int32_t[65536];
811 int32_t *q8_23ref = new int32_t[65536];
812 // Convert sample data to q8_23 to perform accumulate function.
813 memcpy_to_q8_23_from_i16(q8_23ary, i16ref, 65536);
814 memcpy_to_q8_23_from_i16(q8_23add, i16add, 65536);
815 // Ensure the reference matches the inital output after conversion.
816 memcpy(q8_23ref, q8_23ary, 65536 * sizeof(q8_23ary[0]));
817 // Accumulate and check.
818 accumulate_q8_23(q8_23ary, q8_23add, 65536);
819 checkAddedClamped(
820 q8_23ary, q8_23ref, q8_23add, 65536, lim24neg, lim24pos);
821 // Cleanup.
822 delete[] q8_23ref;
823 delete[] q8_23add;
824 delete[] q8_23ary;
825
826 // Test float.
827 float *fary = new float[65536];
828 float *fadd = new float[65536];
829 float *fref = new float[65536];
830 // Convert sample data to float to perform accumulate function.
831 memcpy_to_float_from_i16(fary, i16ref, 65536);
832 memcpy_to_float_from_i16(fadd, i16add, 65536);
833 // Ensure the reference matches the inital output after conversion.
834 memcpy(fref, fary, 65536 * sizeof(fary[0]));
835 // Accumulate and check. Floats aren't clamped by accumulate,
836 // but given the input is in the [-1.0, 1.0) range output should be in
837 // [-2.0, 2.0) range.
838 accumulate_float(fary, fadd, 65536);
839 checkAddedClamped(fary, fref, fadd, 65536, -2.0f, 2.0f);
840 // Cleanup.
841 delete[] fref;
842 delete[] fadd;
843 delete[] fary;
844
845 delete[] i16ary;
846 delete[] i16add;
847 delete[] i16ref;
848 }
849
850
TEST(audio_utils_primitives,MemcpyToFloatFromFloatWithClamping)851 TEST(audio_utils_primitives, MemcpyToFloatFromFloatWithClamping) {
852 std::vector<float> src = {-INFINITY, -2, -1, -0, 0, 0.009, 1.000001, 9999999, INFINITY, NAN};
853 std::vector<float> dst(src.size());
854 float absMax = 1;
855 std::vector<float> expected = {-1, -1, -1, -0, 0, 0.009, 1, 1, 1, 1};
856 ASSERT_EQ(expected.size(), src.size());
857
858 memcpy_to_float_from_float_with_clamping(dst.data(), src.data(), src.size(), absMax);
859
860 ASSERT_EQ(dst, expected) << "src=" << testing::PrintToString(src);
861 }
862