primitives_tests.cpp 31 KB

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