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