• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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