Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_FloatVectorOperations.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. namespace FloatVectorHelpers
  18. {
  19. #define JUCE_INCREMENT_SRC_DEST dest += 4; src += 4;
  20. #define JUCE_INCREMENT_DEST dest += 4;
  21. #if JUCE_USE_SSE_INTRINSICS
  22. static bool sse2Present = false;
  23. static bool isSSE2Available() noexcept
  24. {
  25. if (sse2Present)
  26. return true;
  27. sse2Present = SystemStats::hasSSE2();
  28. return sse2Present;
  29. }
  30. inline static bool isAligned (const void* p) noexcept
  31. {
  32. return (((pointer_sized_int) p) & 15) == 0;
  33. }
  34. static inline float findMinimumOrMaximum (const float* src, int num, const bool isMinimum) noexcept
  35. {
  36. const int numLongOps = num / 4;
  37. if (numLongOps > 1 && FloatVectorHelpers::isSSE2Available())
  38. {
  39. __m128 val;
  40. #define JUCE_MINIMUMMAXIMUM_SSE_LOOP(loadOp, minMaxOp) \
  41. val = loadOp (src); \
  42. src += 4; \
  43. for (int i = 1; i < numLongOps; ++i) \
  44. { \
  45. const __m128 s = loadOp (src); \
  46. val = minMaxOp (val, s); \
  47. src += 4; \
  48. }
  49. if (isMinimum)
  50. {
  51. if (FloatVectorHelpers::isAligned (src)) { JUCE_MINIMUMMAXIMUM_SSE_LOOP (_mm_load_ps, _mm_min_ps) }
  52. else { JUCE_MINIMUMMAXIMUM_SSE_LOOP (_mm_loadu_ps, _mm_min_ps) }
  53. }
  54. else
  55. {
  56. if (FloatVectorHelpers::isAligned (src)) { JUCE_MINIMUMMAXIMUM_SSE_LOOP (_mm_load_ps, _mm_max_ps) }
  57. else { JUCE_MINIMUMMAXIMUM_SSE_LOOP (_mm_loadu_ps,_mm_max_ps) }
  58. }
  59. float localVal;
  60. {
  61. float vals[4];
  62. _mm_storeu_ps (vals, val);
  63. localVal = isMinimum ? jmin (vals[0], vals[1], vals[2], vals[3])
  64. : jmax (vals[0], vals[1], vals[2], vals[3]);
  65. }
  66. num &= 3;
  67. for (int i = 0; i < num; ++i)
  68. localVal = isMinimum ? jmin (localVal, src[i])
  69. : jmax (localVal, src[i]);
  70. return localVal;
  71. }
  72. return isMinimum ? juce::findMinimum (src, num)
  73. : juce::findMaximum (src, num);
  74. }
  75. #define JUCE_BEGIN_SSE_OP \
  76. if (FloatVectorHelpers::isSSE2Available()) \
  77. { \
  78. const int numLongOps = num / 4;
  79. #define JUCE_FINISH_SSE_OP(normalOp) \
  80. num &= 3; \
  81. if (num == 0) return; \
  82. } \
  83. for (int i = 0; i < num; ++i) normalOp;
  84. #define JUCE_SSE_LOOP(sseOp, srcLoad, dstLoad, dstStore, locals, increment) \
  85. for (int i = 0; i < numLongOps; ++i) \
  86. { \
  87. locals (srcLoad, dstLoad); \
  88. dstStore (dest, sseOp); \
  89. increment; \
  90. }
  91. #define JUCE_LOAD_NONE(srcLoad, dstLoad)
  92. #define JUCE_LOAD_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest);
  93. #define JUCE_LOAD_SRC(srcLoad, dstLoad) const __m128 s = srcLoad (src);
  94. #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const __m128 d = dstLoad (dest); const __m128 s = srcLoad (src);
  95. #define JUCE_PERFORM_SSE_OP_DEST(normalOp, sseOp, locals) \
  96. JUCE_BEGIN_SSE_OP \
  97. if (FloatVectorHelpers::isAligned (dest)) JUCE_SSE_LOOP (sseOp, dummy, _mm_load_ps, _mm_store_ps, locals, JUCE_INCREMENT_DEST) \
  98. else JUCE_SSE_LOOP (sseOp, dummy, _mm_loadu_ps, _mm_storeu_ps, locals, JUCE_INCREMENT_DEST) \
  99. JUCE_FINISH_SSE_OP (normalOp)
  100. #define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) \
  101. JUCE_BEGIN_SSE_OP \
  102. if (FloatVectorHelpers::isAligned (dest)) \
  103. { \
  104. if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_load_ps, _mm_store_ps, locals, increment) \
  105. else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_load_ps, _mm_store_ps, locals, increment) \
  106. }\
  107. else \
  108. { \
  109. if (FloatVectorHelpers::isAligned (src)) JUCE_SSE_LOOP (sseOp, _mm_load_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \
  110. else JUCE_SSE_LOOP (sseOp, _mm_loadu_ps, _mm_loadu_ps, _mm_storeu_ps, locals, increment) \
  111. } \
  112. JUCE_FINISH_SSE_OP (normalOp)
  113. //==============================================================================
  114. #elif JUCE_USE_ARM_NEON
  115. static inline float findMinimumOrMaximum (const float* src, int num, const bool isMinimum) noexcept
  116. {
  117. const int numLongOps = num / 4;
  118. if (numLongOps > 1)
  119. {
  120. float32x4_t val;
  121. #define JUCE_MINIMUMMAXIMUM_NEON_LOOP(loadOp, minMaxOp) \
  122. val = loadOp (src); \
  123. src += 4; \
  124. for (int i = 1; i < numLongOps; ++i) \
  125. { \
  126. const float32x4_t s = loadOp (src); \
  127. val = minMaxOp (val, s); \
  128. src += 4; \
  129. }
  130. if (isMinimum) { JUCE_MINIMUMMAXIMUM_NEON_LOOP (vld1q_f32, vminq_f32) }
  131. else { JUCE_MINIMUMMAXIMUM_NEON_LOOP (vld1q_f32, vmaxq_f32) }
  132. float localVal;
  133. {
  134. float vals[4];
  135. vst1q_f32 (vals, val);
  136. localVal = isMinimum ? jmin (vals[0], vals[1], vals[2], vals[3])
  137. : jmax (vals[0], vals[1], vals[2], vals[3]);
  138. }
  139. num &= 3;
  140. for (int i = 0; i < num; ++i)
  141. localVal = isMinimum ? jmin (localVal, src[i])
  142. : jmax (localVal, src[i]);
  143. return localVal;
  144. }
  145. return isMinimum ? juce::findMinimum (src, num)
  146. : juce::findMaximum (src, num);
  147. }
  148. #define JUCE_BEGIN_NEON_OP \
  149. const int numLongOps = num / 4;
  150. #define JUCE_FINISH_NEON_OP(normalOp) \
  151. num &= 3; \
  152. if (num == 0) return; \
  153. for (int i = 0; i < num; ++i) normalOp;
  154. #define JUCE_NEON_LOOP(neonOp, srcLoad, dstLoad, dstStore, locals, increment) \
  155. for (int i = 0; i < numLongOps; ++i) \
  156. { \
  157. locals (srcLoad, dstLoad); \
  158. dstStore (dest, neonOp); \
  159. increment; \
  160. }
  161. #define JUCE_LOAD_NONE(srcLoad, dstLoad)
  162. #define JUCE_LOAD_DEST(srcLoad, dstLoad) const float32x4_t d = dstLoad (dest);
  163. #define JUCE_LOAD_SRC(srcLoad, dstLoad) const float32x4_t s = srcLoad (src);
  164. #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const float32x4_t d = dstLoad (dest); const float32x4_t s = srcLoad (src);
  165. #define JUCE_PERFORM_NEON_OP_DEST(normalOp, neonOp, locals) \
  166. JUCE_BEGIN_NEON_OP \
  167. JUCE_NEON_LOOP (neonOp, dummy, vld1q_f32, vst1q_f32, locals, JUCE_INCREMENT_DEST) \
  168. JUCE_FINISH_NEON_OP (normalOp)
  169. #define JUCE_PERFORM_NEON_OP_SRC_DEST(normalOp, neonOp, locals) \
  170. JUCE_BEGIN_NEON_OP \
  171. JUCE_NEON_LOOP (neonOp, vld1q_f32, vld1q_f32, vst1q_f32, locals, JUCE_INCREMENT_SRC_DEST) \
  172. JUCE_FINISH_NEON_OP (normalOp)
  173. //==============================================================================
  174. #else
  175. #define JUCE_PERFORM_SSE_OP_DEST(normalOp, unused1, unused2) for (int i = 0; i < num; ++i) normalOp;
  176. #define JUCE_PERFORM_SSE_OP_SRC_DEST(normalOp, sseOp, locals, increment) for (int i = 0; i < num; ++i) normalOp;
  177. #endif
  178. }
  179. //==============================================================================
  180. void JUCE_CALLTYPE FloatVectorOperations::clear (float* dest, int num) noexcept
  181. {
  182. #if JUCE_USE_VDSP_FRAMEWORK
  183. vDSP_vclr (dest, 1, (size_t) num);
  184. #else
  185. zeromem (dest, num * sizeof (float));
  186. #endif
  187. }
  188. void JUCE_CALLTYPE FloatVectorOperations::fill (float* dest, float valueToFill, int num) noexcept
  189. {
  190. #if JUCE_USE_VDSP_FRAMEWORK
  191. vDSP_vfill (&valueToFill, dest, 1, (size_t) num);
  192. #elif JUCE_USE_ARM_NEON
  193. const float32x4_t val = vld1q_dup_f32 (&valueToFill);
  194. JUCE_PERFORM_NEON_OP_DEST (dest[i] = valueToFill, val, JUCE_LOAD_NONE)
  195. #else
  196. #if JUCE_USE_SSE_INTRINSICS
  197. const __m128 val = _mm_load1_ps (&valueToFill);
  198. #endif
  199. JUCE_PERFORM_SSE_OP_DEST (dest[i] = valueToFill, val, JUCE_LOAD_NONE)
  200. #endif
  201. }
  202. void JUCE_CALLTYPE FloatVectorOperations::copy (float* dest, const float* src, int num) noexcept
  203. {
  204. memcpy (dest, src, (size_t) num * sizeof (float));
  205. }
  206. void JUCE_CALLTYPE FloatVectorOperations::copyWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
  207. {
  208. #if JUCE_USE_VDSP_FRAMEWORK
  209. vDSP_vsmul (src, 1, &multiplier, dest, 1, num);
  210. #elif JUCE_USE_ARM_NEON
  211. JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] += src[i], vmulq_n_f32(s, multiplier), JUCE_LOAD_SRC)
  212. #else
  213. #if JUCE_USE_SSE_INTRINSICS
  214. const __m128 mult = _mm_load1_ps (&multiplier);
  215. #endif
  216. JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier, _mm_mul_ps (mult, s),
  217. JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST)
  218. #endif
  219. }
  220. void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float amount, int num) noexcept
  221. {
  222. #if JUCE_USE_ARM_NEON
  223. const float32x4_t amountToAdd = vld1q_dup_f32(&amount);
  224. JUCE_PERFORM_NEON_OP_DEST (dest[i] += amount, vaddq_f32 (d, amountToAdd), JUCE_LOAD_DEST)
  225. #else
  226. #if JUCE_USE_SSE_INTRINSICS
  227. const __m128 amountToAdd = _mm_load1_ps (&amount);
  228. #endif
  229. JUCE_PERFORM_SSE_OP_DEST (dest[i] += amount, _mm_add_ps (d, amountToAdd), JUCE_LOAD_DEST)
  230. #endif
  231. }
  232. void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, int num) noexcept
  233. {
  234. #if JUCE_USE_VDSP_FRAMEWORK
  235. vDSP_vadd (src, 1, dest, 1, dest, 1, num);
  236. #elif JUCE_USE_ARM_NEON
  237. JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] += src[i], vaddq_f32 (d, s), JUCE_LOAD_SRC_DEST)
  238. #else
  239. JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i], _mm_add_ps (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
  240. #endif
  241. }
  242. void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src, int num) noexcept
  243. {
  244. #if JUCE_USE_VDSP_FRAMEWORK
  245. vDSP_vsub (src, 1, dest, 1, dest, 1, num);
  246. #elif JUCE_USE_ARM_NEON
  247. JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] -= src[i], vsubq_f32 (d, s), JUCE_LOAD_SRC_DEST)
  248. #else
  249. JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] -= src[i], _mm_sub_ps (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
  250. #endif
  251. }
  252. void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
  253. {
  254. #if JUCE_USE_ARM_NEON
  255. JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] += src[i] * multiplier,
  256. vmlaq_n_f32 (d, s, multiplier),
  257. JUCE_LOAD_SRC_DEST)
  258. #else
  259. #if JUCE_USE_SSE_INTRINSICS
  260. const __m128 mult = _mm_load1_ps (&multiplier);
  261. #endif
  262. JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] += src[i] * multiplier,
  263. _mm_add_ps (d, _mm_mul_ps (mult, s)),
  264. JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
  265. #endif
  266. }
  267. void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, int num) noexcept
  268. {
  269. #if JUCE_USE_VDSP_FRAMEWORK
  270. vDSP_vmul (src, 1, dest, 1, dest, 1, num);
  271. #elif JUCE_USE_ARM_NEON
  272. JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] *= src[i], vmulq_f32 (d, s), JUCE_LOAD_SRC_DEST)
  273. #else
  274. JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] *= src[i], _mm_mul_ps (d, s), JUCE_LOAD_SRC_DEST, JUCE_INCREMENT_SRC_DEST)
  275. #endif
  276. }
  277. void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplier, int num) noexcept
  278. {
  279. #if JUCE_USE_VDSP_FRAMEWORK
  280. vDSP_vsmul (dest, 1, &multiplier, dest, 1, num);
  281. #elif JUCE_USE_ARM_NEON
  282. JUCE_PERFORM_NEON_OP_DEST (dest[i] *= multiplier, vmulq_n_f32 (d, multiplier), JUCE_LOAD_DEST)
  283. #else
  284. #if JUCE_USE_SSE_INTRINSICS
  285. const __m128 mult = _mm_load1_ps (&multiplier);
  286. #endif
  287. JUCE_PERFORM_SSE_OP_DEST (dest[i] *= multiplier, _mm_mul_ps (d, mult), JUCE_LOAD_DEST)
  288. #endif
  289. }
  290. void FloatVectorOperations::negate (float* dest, const float* src, int num) noexcept
  291. {
  292. #if JUCE_USE_VDSP_FRAMEWORK
  293. vDSP_vneg ((float*) src, 1, dest, 1, (vDSP_Length) num);
  294. #else
  295. copyWithMultiply (dest, src, -1.0f, num);
  296. #endif
  297. }
  298. void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept
  299. {
  300. #if JUCE_USE_ARM_NEON
  301. JUCE_PERFORM_NEON_OP_SRC_DEST (dest[i] = src[i] * multiplier,
  302. vmulq_n_f32 (vcvtq_f32_s32 (vld1q_s32 (src)), multiplier),
  303. JUCE_LOAD_NONE)
  304. #else
  305. #if JUCE_USE_SSE_INTRINSICS
  306. const __m128 mult = _mm_load1_ps (&multiplier);
  307. #endif
  308. JUCE_PERFORM_SSE_OP_SRC_DEST (dest[i] = src[i] * multiplier,
  309. _mm_mul_ps (mult, _mm_cvtepi32_ps (_mm_loadu_si128 ((const __m128i*) src))),
  310. JUCE_LOAD_NONE, JUCE_INCREMENT_SRC_DEST)
  311. #endif
  312. }
  313. void JUCE_CALLTYPE FloatVectorOperations::findMinAndMax (const float* src, int num, float& minResult, float& maxResult) noexcept
  314. {
  315. #if JUCE_USE_SSE_INTRINSICS
  316. const int numLongOps = num / 4;
  317. if (numLongOps > 1 && FloatVectorHelpers::isSSE2Available())
  318. {
  319. __m128 mn, mx;
  320. #define JUCE_MINMAX_SSE_LOOP(loadOp) \
  321. mn = loadOp (src); \
  322. mx = mn; \
  323. src += 4; \
  324. for (int i = 1; i < numLongOps; ++i) \
  325. { \
  326. const __m128 s = loadOp (src); \
  327. mn = _mm_min_ps (mn, s); \
  328. mx = _mm_max_ps (mx, s); \
  329. src += 4; \
  330. }
  331. if (FloatVectorHelpers::isAligned (src)) { JUCE_MINMAX_SSE_LOOP (_mm_load_ps) }
  332. else { JUCE_MINMAX_SSE_LOOP (_mm_loadu_ps) }
  333. float localMin, localMax;
  334. {
  335. float mns[4], mxs[4];
  336. _mm_storeu_ps (mns, mn);
  337. _mm_storeu_ps (mxs, mx);
  338. localMin = jmin (mns[0], mns[1], mns[2], mns[3]);
  339. localMax = jmax (mxs[0], mxs[1], mxs[2], mxs[3]);
  340. }
  341. num &= 3;
  342. for (int i = 0; i < num; ++i)
  343. {
  344. const float s = src[i];
  345. localMin = jmin (localMin, s);
  346. localMax = jmax (localMax, s);
  347. }
  348. minResult = localMin;
  349. maxResult = localMax;
  350. return;
  351. }
  352. #elif JUCE_USE_ARM_NEON
  353. const int numLongOps = num / 4;
  354. if (numLongOps > 1)
  355. {
  356. float32x4_t mn, mx;
  357. #define JUCE_MINMAX_NEON_LOOP(loadOp) \
  358. mn = loadOp (src); \
  359. mx = mn; \
  360. src += 4; \
  361. for (int i = 1; i < numLongOps; ++i) \
  362. { \
  363. const float32x4_t s = loadOp (src); \
  364. mn = vminq_f32 (mn, s); \
  365. mx = vmaxq_f32 (mx, s); \
  366. src += 4; \
  367. }
  368. JUCE_MINMAX_NEON_LOOP (vld1q_f32);
  369. float localMin, localMax;
  370. {
  371. float mns[4], mxs[4];
  372. vst1q_f32 (mns, mn);
  373. vst1q_f32 (mxs, mx);
  374. localMin = jmin (mns[0], mns[1], mns[2], mns[3]);
  375. localMax = jmax (mxs[0], mxs[1], mxs[2], mxs[3]);
  376. }
  377. num &= 3;
  378. for (int i = 0; i < num; ++i)
  379. {
  380. const float s = src[i];
  381. localMin = jmin (localMin, s);
  382. localMax = jmax (localMax, s);
  383. }
  384. minResult = localMin;
  385. maxResult = localMax;
  386. return;
  387. }
  388. #endif
  389. juce::findMinAndMax (src, num, minResult, maxResult);
  390. }
  391. float JUCE_CALLTYPE FloatVectorOperations::findMinimum (const float* src, int num) noexcept
  392. {
  393. #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
  394. return FloatVectorHelpers::findMinimumOrMaximum (src, num, true);
  395. #else
  396. return juce::findMinimum (src, num);
  397. #endif
  398. }
  399. float JUCE_CALLTYPE FloatVectorOperations::findMaximum (const float* src, int num) noexcept
  400. {
  401. #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
  402. return FloatVectorHelpers::findMinimumOrMaximum (src, num, false);
  403. #else
  404. return juce::findMaximum (src, num);
  405. #endif
  406. }
  407. void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnable) noexcept
  408. {
  409. #if JUCE_USE_SSE_INTRINSICS
  410. if (FloatVectorHelpers::isSSE2Available())
  411. _MM_SET_FLUSH_ZERO_MODE (shouldEnable ? _MM_FLUSH_ZERO_ON : _MM_FLUSH_ZERO_OFF);
  412. #endif
  413. (void) shouldEnable;
  414. }
  415. //==============================================================================
  416. //==============================================================================
  417. #if JUCE_UNIT_TESTS
  418. class FloatVectorOperationsTests : public UnitTest
  419. {
  420. public:
  421. FloatVectorOperationsTests() : UnitTest ("FloatVectorOperations") {}
  422. void runTest()
  423. {
  424. beginTest ("FloatVectorOperations");
  425. for (int i = 100; --i >= 0;)
  426. {
  427. const int num = getRandom().nextInt (500) + 1;
  428. HeapBlock<float> buffer1 (num + 16), buffer2 (num + 16);
  429. HeapBlock<int> buffer3 (num + 16);
  430. #if JUCE_ARM
  431. float* const data1 = buffer1;
  432. float* const data2 = buffer2;
  433. int* const int1 = buffer3;
  434. #else
  435. float* const data1 = addBytesToPointer (buffer1.getData(), getRandom().nextInt (16));
  436. float* const data2 = addBytesToPointer (buffer2.getData(), getRandom().nextInt (16));
  437. int* const int1 = addBytesToPointer (buffer3.getData(), getRandom().nextInt (16));
  438. #endif
  439. fillRandomly (data1, num);
  440. fillRandomly (data2, num);
  441. float mn1, mx1, mn2, mx2;
  442. FloatVectorOperations::findMinAndMax (data1, num, mn1, mx1);
  443. juce::findMinAndMax (data1, num, mn2, mx2);
  444. expect (mn1 == mn2);
  445. expect (mx1 == mx2);
  446. expect (FloatVectorOperations::findMinimum (data1, num) == juce::findMinimum (data1, num));
  447. expect (FloatVectorOperations::findMaximum (data1, num) == juce::findMaximum (data1, num));
  448. expect (FloatVectorOperations::findMinimum (data2, num) == juce::findMinimum (data2, num));
  449. expect (FloatVectorOperations::findMaximum (data2, num) == juce::findMaximum (data2, num));
  450. FloatVectorOperations::clear (data1, num);
  451. expect (areAllValuesEqual (data1, num, 0));
  452. FloatVectorOperations::fill (data1, 2.0f, num);
  453. expect (areAllValuesEqual (data1, num, 2.0f));
  454. FloatVectorOperations::add (data1, 2.0f, num);
  455. expect (areAllValuesEqual (data1, num, 4.0f));
  456. FloatVectorOperations::copy (data2, data1, num);
  457. expect (areAllValuesEqual (data2, num, 4.0f));
  458. FloatVectorOperations::add (data2, data1, num);
  459. expect (areAllValuesEqual (data2, num, 8.0f));
  460. FloatVectorOperations::copyWithMultiply (data2, data1, 4.0f, num);
  461. expect (areAllValuesEqual (data2, num, 16.0f));
  462. FloatVectorOperations::addWithMultiply (data2, data1, 4.0f, num);
  463. expect (areAllValuesEqual (data2, num, 32.0f));
  464. FloatVectorOperations::multiply (data1, 2.0f, num);
  465. expect (areAllValuesEqual (data1, num, 8.0f));
  466. FloatVectorOperations::multiply (data1, data2, num);
  467. expect (areAllValuesEqual (data1, num, 256.0f));
  468. FloatVectorOperations::negate (data2, data1, num);
  469. expect (areAllValuesEqual (data2, num, -256.0f));
  470. FloatVectorOperations::subtract (data1, data2, num);
  471. expect (areAllValuesEqual (data1, num, 512.0f));
  472. fillRandomly (int1, num);
  473. FloatVectorOperations::convertFixedToFloat (data1, int1, 2.0f, num);
  474. convertFixed (data2, int1, 2.0f, num);
  475. expect (buffersMatch (data1, data2, num));
  476. }
  477. }
  478. void fillRandomly (float* d, int num)
  479. {
  480. while (--num >= 0)
  481. *d++ = getRandom().nextFloat() * 1000.0f;
  482. }
  483. void fillRandomly (int* d, int num)
  484. {
  485. while (--num >= 0)
  486. *d++ = getRandom().nextInt();
  487. }
  488. static void convertFixed (float* d, const int* s, float multiplier, int num)
  489. {
  490. while (--num >= 0)
  491. *d++ = *s++ * multiplier;
  492. }
  493. static bool areAllValuesEqual (const float* d, int num, float target)
  494. {
  495. while (--num >= 0)
  496. if (*d++ != target)
  497. return false;
  498. return true;
  499. }
  500. static bool buffersMatch (const float* d1, const float* d2, int num)
  501. {
  502. while (--num >= 0)
  503. if (std::abs (*d1++ - *d2++) > std::numeric_limits<float>::epsilon())
  504. return false;
  505. return true;
  506. }
  507. };
  508. static FloatVectorOperationsTests vectorOpTests;
  509. #endif