OpenShot Audio Library | OpenShotAudio 0.4.0
Loading...
Searching...
No Matches
juce_FloatVectorOperations.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26namespace FloatVectorHelpers
27{
28 #define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest));
29 #define JUCE_INCREMENT_SRC1_SRC2_DEST dest += (16 / sizeof (*dest)); src1 += (16 / sizeof (*dest)); src2 += (16 / sizeof (*dest));
30 #define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest));
31
32 #if JUCE_USE_SSE_INTRINSICS
33 static bool isAligned (const void* p) noexcept
34 {
35 return (((pointer_sized_int) p) & 15) == 0;
36 }
37
38 struct BasicOps32
39 {
40 using Type = float;
41 using ParallelType = __m128;
42 using IntegerType = __m128;
43 enum { numParallel = 4 };
44
45 // Integer and parallel types are the same for SSE. On neon they have different types
46 static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
47 static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
48
49 static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_ps (&v); }
50 static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_ps (v); }
51 static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_ps (v); }
52 static forcedinline void storeA (Type* dest, ParallelType a) noexcept { _mm_store_ps (dest, a); }
53 static forcedinline void storeU (Type* dest, ParallelType a) noexcept { _mm_storeu_ps (dest, a); }
54
55 static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return _mm_add_ps (a, b); }
56 static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return _mm_sub_ps (a, b); }
57 static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return _mm_mul_ps (a, b); }
58 static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_ps (a, b); }
59 static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_ps (a, b); }
60
61 static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_ps (a, b); }
62 static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_ps (a, b); }
63 static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_ps (a, b); }
64 static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_ps (a, b); }
65
66 static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
67 static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
68 };
69
70 struct BasicOps64
71 {
72 using Type = double;
73 using ParallelType = __m128d;
74 using IntegerType = __m128d;
75 enum { numParallel = 2 };
76
77 // Integer and parallel types are the same for SSE. On neon they have different types
78 static forcedinline IntegerType toint (ParallelType v) noexcept { return v; }
79 static forcedinline ParallelType toflt (IntegerType v) noexcept { return v; }
80
81 static forcedinline ParallelType load1 (Type v) noexcept { return _mm_load1_pd (&v); }
82 static forcedinline ParallelType loadA (const Type* v) noexcept { return _mm_load_pd (v); }
83 static forcedinline ParallelType loadU (const Type* v) noexcept { return _mm_loadu_pd (v); }
84 static forcedinline void storeA (Type* dest, ParallelType a) noexcept { _mm_store_pd (dest, a); }
85 static forcedinline void storeU (Type* dest, ParallelType a) noexcept { _mm_storeu_pd (dest, a); }
86
87 static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return _mm_add_pd (a, b); }
88 static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return _mm_sub_pd (a, b); }
89 static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return _mm_mul_pd (a, b); }
90 static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return _mm_max_pd (a, b); }
91 static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return _mm_min_pd (a, b); }
92
93 static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return _mm_and_pd (a, b); }
94 static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return _mm_andnot_pd (a, b); }
95 static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return _mm_or_pd (a, b); }
96 static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return _mm_xor_pd (a, b); }
97
98 static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1]); }
99 static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1]); }
100 };
101
102
103
104 #define JUCE_BEGIN_VEC_OP \
105 using Mode = FloatVectorHelpers::ModeType<sizeof(*dest)>::Mode; \
106 { \
107 const auto numLongOps = num / Mode::numParallel;
108
109 #define JUCE_FINISH_VEC_OP(normalOp) \
110 num &= (Mode::numParallel - 1); \
111 if (num == 0) return; \
112 } \
113 for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
114
115 #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
116 JUCE_BEGIN_VEC_OP \
117 setupOp \
118 if (FloatVectorHelpers::isAligned (dest)) JUCE_VEC_LOOP (vecOp, dummy, Mode::loadA, Mode::storeA, locals, JUCE_INCREMENT_DEST) \
119 else JUCE_VEC_LOOP (vecOp, dummy, Mode::loadU, Mode::storeU, locals, JUCE_INCREMENT_DEST) \
120 JUCE_FINISH_VEC_OP (normalOp)
121
122 #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
123 JUCE_BEGIN_VEC_OP \
124 setupOp \
125 if (FloatVectorHelpers::isAligned (dest)) \
126 { \
127 if (FloatVectorHelpers::isAligned (src)) JUCE_VEC_LOOP (vecOp, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
128 else JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
129 }\
130 else \
131 { \
132 if (FloatVectorHelpers::isAligned (src)) JUCE_VEC_LOOP (vecOp, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
133 else JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
134 } \
135 JUCE_FINISH_VEC_OP (normalOp)
136
137 #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
138 JUCE_BEGIN_VEC_OP \
139 setupOp \
140 if (FloatVectorHelpers::isAligned (dest)) \
141 { \
142 if (FloatVectorHelpers::isAligned (src1)) \
143 { \
144 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
145 else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeA, locals, increment) \
146 } \
147 else \
148 { \
149 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
150 else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeA, locals, increment) \
151 } \
152 } \
153 else \
154 { \
155 if (FloatVectorHelpers::isAligned (src1)) \
156 { \
157 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadA, Mode::storeU, locals, increment) \
158 else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
159 } \
160 else \
161 { \
162 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadA, Mode::storeU, locals, increment) \
163 else JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
164 } \
165 } \
166 JUCE_FINISH_VEC_OP (normalOp)
167
168 #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
169 JUCE_BEGIN_VEC_OP \
170 setupOp \
171 if (FloatVectorHelpers::isAligned (dest)) \
172 { \
173 if (FloatVectorHelpers::isAligned (src1)) \
174 { \
175 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
176 else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
177 } \
178 else \
179 { \
180 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadA, Mode::storeA, locals, increment) \
181 else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadA, Mode::storeA, locals, increment) \
182 } \
183 } \
184 else \
185 { \
186 if (FloatVectorHelpers::isAligned (src1)) \
187 { \
188 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
189 else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadA, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
190 } \
191 else \
192 { \
193 if (FloatVectorHelpers::isAligned (src2)) JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadA, Mode::loadU, Mode::storeU, locals, increment) \
194 else JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
195 } \
196 } \
197 JUCE_FINISH_VEC_OP (normalOp)
198
199
200 //==============================================================================
201 #elif JUCE_USE_ARM_NEON
202
203 struct BasicOps32
204 {
205 using Type = float;
206 using ParallelType = float32x4_t;
207 using IntegerType = uint32x4_t;
208 union signMaskUnion { ParallelType f; IntegerType i; };
209 enum { numParallel = 4 };
210
211 static forcedinline IntegerType toint (ParallelType v) noexcept { signMaskUnion u; u.f = v; return u.i; }
212 static forcedinline ParallelType toflt (IntegerType v) noexcept { signMaskUnion u; u.i = v; return u.f; }
213
214 static forcedinline ParallelType load1 (Type v) noexcept { return vld1q_dup_f32 (&v); }
215 static forcedinline ParallelType loadA (const Type* v) noexcept { return vld1q_f32 (v); }
216 static forcedinline ParallelType loadU (const Type* v) noexcept { return vld1q_f32 (v); }
217 static forcedinline void storeA (Type* dest, ParallelType a) noexcept { vst1q_f32 (dest, a); }
218 static forcedinline void storeU (Type* dest, ParallelType a) noexcept { vst1q_f32 (dest, a); }
219
220 static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return vaddq_f32 (a, b); }
221 static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return vsubq_f32 (a, b); }
222 static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return vmulq_f32 (a, b); }
223 static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return vmaxq_f32 (a, b); }
224 static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return vminq_f32 (a, b); }
225
226 static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (vandq_u32 (toint (a), toint (b))); }
227 static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt (vbicq_u32 (toint (a), toint (b))); }
228 static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (vorrq_u32 (toint (a), toint (b))); }
229 static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (veorq_u32 (toint (a), toint (b))); }
230
231 static forcedinline Type max (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmax (v[0], v[1], v[2], v[3]); }
232 static forcedinline Type min (ParallelType a) noexcept { Type v[numParallel]; storeU (v, a); return jmin (v[0], v[1], v[2], v[3]); }
233 };
234
235 struct BasicOps64
236 {
237 using Type = double;
238 using ParallelType = double;
239 using IntegerType = uint64;
240 union signMaskUnion { ParallelType f; IntegerType i; };
241 enum { numParallel = 1 };
242
243 static forcedinline IntegerType toint (ParallelType v) noexcept { signMaskUnion u; u.f = v; return u.i; }
244 static forcedinline ParallelType toflt (IntegerType v) noexcept { signMaskUnion u; u.i = v; return u.f; }
245
246 static forcedinline ParallelType load1 (Type v) noexcept { return v; }
247 static forcedinline ParallelType loadA (const Type* v) noexcept { return *v; }
248 static forcedinline ParallelType loadU (const Type* v) noexcept { return *v; }
249 static forcedinline void storeA (Type* dest, ParallelType a) noexcept { *dest = a; }
250 static forcedinline void storeU (Type* dest, ParallelType a) noexcept { *dest = a; }
251
252 static forcedinline ParallelType add (ParallelType a, ParallelType b) noexcept { return a + b; }
253 static forcedinline ParallelType sub (ParallelType a, ParallelType b) noexcept { return a - b; }
254 static forcedinline ParallelType mul (ParallelType a, ParallelType b) noexcept { return a * b; }
255 static forcedinline ParallelType max (ParallelType a, ParallelType b) noexcept { return jmax (a, b); }
256 static forcedinline ParallelType min (ParallelType a, ParallelType b) noexcept { return jmin (a, b); }
257
258 static forcedinline ParallelType bit_and (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) & toint (b)); }
259 static forcedinline ParallelType bit_not (ParallelType a, ParallelType b) noexcept { return toflt ((~toint (a)) & toint (b)); }
260 static forcedinline ParallelType bit_or (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) | toint (b)); }
261 static forcedinline ParallelType bit_xor (ParallelType a, ParallelType b) noexcept { return toflt (toint (a) ^ toint (b)); }
262
263 static forcedinline Type max (ParallelType a) noexcept { return a; }
264 static forcedinline Type min (ParallelType a) noexcept { return a; }
265 };
266
267 #define JUCE_BEGIN_VEC_OP \
268 using Mode = FloatVectorHelpers::ModeType<sizeof(*dest)>::Mode; \
269 if (Mode::numParallel > 1) \
270 { \
271 const auto numLongOps = num / Mode::numParallel;
272
273 #define JUCE_FINISH_VEC_OP(normalOp) \
274 num &= (Mode::numParallel - 1); \
275 if (num == 0) return; \
276 } \
277 for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
278
279 #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
280 JUCE_BEGIN_VEC_OP \
281 setupOp \
282 JUCE_VEC_LOOP (vecOp, dummy, Mode::loadU, Mode::storeU, locals, JUCE_INCREMENT_DEST) \
283 JUCE_FINISH_VEC_OP (normalOp)
284
285 #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
286 JUCE_BEGIN_VEC_OP \
287 setupOp \
288 JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
289 JUCE_FINISH_VEC_OP (normalOp)
290
291 #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
292 JUCE_BEGIN_VEC_OP \
293 setupOp \
294 JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
295 JUCE_FINISH_VEC_OP (normalOp)
296
297 #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
298 JUCE_BEGIN_VEC_OP \
299 setupOp \
300 JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD (vecOp, Mode::loadU, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
301 JUCE_FINISH_VEC_OP (normalOp)
302
303
304 //==============================================================================
305 #else
306 #define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
307 for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
308
309 #define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
310 for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
311
312 #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
313 for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
314
315 #define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST(normalOp, vecOp, locals, increment, setupOp) \
316 for (auto i = (decltype (num)) 0; i < num; ++i) normalOp;
317
318 #endif
319
320 //==============================================================================
321 #define JUCE_VEC_LOOP(vecOp, srcLoad, dstLoad, dstStore, locals, increment) \
322 for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \
323 { \
324 locals (srcLoad, dstLoad); \
325 dstStore (dest, vecOp); \
326 increment; \
327 }
328
329 #define JUCE_VEC_LOOP_TWO_SOURCES(vecOp, src1Load, src2Load, dstStore, locals, increment) \
330 for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \
331 { \
332 locals (src1Load, src2Load); \
333 dstStore (dest, vecOp); \
334 increment; \
335 }
336
337 #define JUCE_VEC_LOOP_TWO_SOURCES_WITH_DEST_LOAD(vecOp, src1Load, src2Load, dstLoad, dstStore, locals, increment) \
338 for (auto i = (decltype (numLongOps)) 0; i < numLongOps; ++i) \
339 { \
340 locals (src1Load, src2Load, dstLoad); \
341 dstStore (dest, vecOp); \
342 increment; \
343 }
344
345 #define JUCE_LOAD_NONE(srcLoad, dstLoad)
346 #define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
347 #define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
348 #define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2);
349 #define JUCE_LOAD_SRC1_SRC2_DEST(src1Load, src2Load, dstLoad) const Mode::ParallelType d = dstLoad (dest), s1 = src1Load (src1), s2 = src2Load (src2);
350 #define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
351
352 union signMask32 { float f; uint32 i; };
353 union signMask64 { double d; uint64 i; };
354
355 #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
356 template <int typeSize> struct ModeType { using Mode = BasicOps32; };
357 template <> struct ModeType<8> { using Mode = BasicOps64; };
358
359 template <typename Mode>
360 struct MinMax
361 {
362 using Type = typename Mode::Type;
363 using ParallelType = typename Mode::ParallelType;
364
365 template <typename Size>
366 static Type findMinOrMax (const Type* src, Size num, const bool isMinimum) noexcept
367 {
368 auto numLongOps = num / Mode::numParallel;
369
370 if (numLongOps > 1)
371 {
372 ParallelType val;
373
374 #if ! JUCE_USE_ARM_NEON
375 if (isAligned (src))
376 {
377 val = Mode::loadA (src);
378
379 if (isMinimum)
380 {
381 while (--numLongOps > 0)
382 {
383 src += Mode::numParallel;
384 val = Mode::min (val, Mode::loadA (src));
385 }
386 }
387 else
388 {
389 while (--numLongOps > 0)
390 {
391 src += Mode::numParallel;
392 val = Mode::max (val, Mode::loadA (src));
393 }
394 }
395 }
396 else
397 #endif
398 {
399 val = Mode::loadU (src);
400
401 if (isMinimum)
402 {
403 while (--numLongOps > 0)
404 {
405 src += Mode::numParallel;
406 val = Mode::min (val, Mode::loadU (src));
407 }
408 }
409 else
410 {
411 while (--numLongOps > 0)
412 {
413 src += Mode::numParallel;
414 val = Mode::max (val, Mode::loadU (src));
415 }
416 }
417 }
418
419 Type result = isMinimum ? Mode::min (val)
420 : Mode::max (val);
421
422 num &= (Mode::numParallel - 1);
423 src += Mode::numParallel;
424
425 for (auto i = (decltype (num)) 0; i < num; ++i)
426 result = isMinimum ? jmin (result, src[i])
427 : jmax (result, src[i]);
428
429 return result;
430 }
431
432 if (num <= 0)
433 return 0;
434
435 return isMinimum ? *std::min_element (src, src + num)
436 : *std::max_element (src, src + num);
437 }
438
439 template <typename Size>
440 static Range<Type> findMinAndMax (const Type* src, Size num) noexcept
441 {
442 auto numLongOps = num / Mode::numParallel;
443
444 if (numLongOps > 1)
445 {
446 ParallelType mn, mx;
447
448 #if ! JUCE_USE_ARM_NEON
449 if (isAligned (src))
450 {
451 mn = Mode::loadA (src);
452 mx = mn;
453
454 while (--numLongOps > 0)
455 {
456 src += Mode::numParallel;
457 const ParallelType v = Mode::loadA (src);
458 mn = Mode::min (mn, v);
459 mx = Mode::max (mx, v);
460 }
461 }
462 else
463 #endif
464 {
465 mn = Mode::loadU (src);
466 mx = mn;
467
468 while (--numLongOps > 0)
469 {
470 src += Mode::numParallel;
471 const ParallelType v = Mode::loadU (src);
472 mn = Mode::min (mn, v);
473 mx = Mode::max (mx, v);
474 }
475 }
476
477 Range<Type> result (Mode::min (mn),
478 Mode::max (mx));
479
480 num &= (Mode::numParallel - 1);
481 src += Mode::numParallel;
482
483 for (auto i = (decltype (num)) 0; i < num; ++i)
484 result = result.getUnionWith (src[i]);
485
486 return result;
487 }
488
489 return Range<Type>::findMinAndMax (src, num);
490 }
491 };
492 #endif
493
494//==============================================================================
495namespace
496{
497 template <typename Size>
498 void clear (float* dest, Size num) noexcept
499 {
500 #if JUCE_USE_VDSP_FRAMEWORK
501 vDSP_vclr (dest, 1, (vDSP_Length) num);
502 #else
503 zeromem (dest, (size_t) num * sizeof (float));
504 #endif
505 }
506
507 template <typename Size>
508 void clear (double* dest, Size num) noexcept
509 {
510 #if JUCE_USE_VDSP_FRAMEWORK
511 vDSP_vclrD (dest, 1, (vDSP_Length) num);
512 #else
513 zeromem (dest, (size_t) num * sizeof (double));
514 #endif
515 }
516
517 template <typename Size>
518 void fill (float* dest, float valueToFill, Size num) noexcept
519 {
520 #if JUCE_USE_VDSP_FRAMEWORK
521 vDSP_vfill (&valueToFill, dest, 1, (vDSP_Length) num);
522 #else
523 JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill,
524 val,
525 JUCE_LOAD_NONE,
526 const Mode::ParallelType val = Mode::load1 (valueToFill);)
527 #endif
528 }
529
530 template <typename Size>
531 void fill (double* dest, double valueToFill, Size num) noexcept
532 {
533 #if JUCE_USE_VDSP_FRAMEWORK
534 vDSP_vfillD (&valueToFill, dest, 1, (vDSP_Length) num);
535 #else
536 JUCE_PERFORM_VEC_OP_DEST (dest[i] = valueToFill,
537 val,
538 JUCE_LOAD_NONE,
539 const Mode::ParallelType val = Mode::load1 (valueToFill);)
540 #endif
541 }
542
543 template <typename Size>
544 void copyWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept
545 {
546 #if JUCE_USE_VDSP_FRAMEWORK
547 vDSP_vsmul (src, 1, &multiplier, dest, 1, (vDSP_Length) num);
548 #else
549 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
550 Mode::mul (mult, s),
551 JUCE_LOAD_SRC,
552 JUCE_INCREMENT_SRC_DEST,
553 const Mode::ParallelType mult = Mode::load1 (multiplier);)
554 #endif
555 }
556
557 template <typename Size>
558 void copyWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept
559 {
560 #if JUCE_USE_VDSP_FRAMEWORK
561 vDSP_vsmulD (src, 1, &multiplier, dest, 1, (vDSP_Length) num);
562 #else
563 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
564 Mode::mul (mult, s),
565 JUCE_LOAD_SRC,
566 JUCE_INCREMENT_SRC_DEST,
567 const Mode::ParallelType mult = Mode::load1 (multiplier);)
568 #endif
569 }
570
571 template <typename Size>
572 void add (float* dest, float amount, Size num) noexcept
573 {
574 #if JUCE_USE_VDSP_FRAMEWORK
575 vDSP_vsadd (dest, 1, &amount, dest, 1, (vDSP_Length) num);
576 #else
577 JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount,
578 Mode::add (d, amountToAdd),
579 JUCE_LOAD_DEST,
580 const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
581 #endif
582 }
583
584 template <typename Size>
585 void add (double* dest, double amount, Size num) noexcept
586 {
587 JUCE_PERFORM_VEC_OP_DEST (dest[i] += amount,
588 Mode::add (d, amountToAdd),
589 JUCE_LOAD_DEST,
590 const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
591 }
592
593 template <typename Size>
594 void add (float* dest, const float* src, float amount, Size num) noexcept
595 {
596 #if JUCE_USE_VDSP_FRAMEWORK
597 vDSP_vsadd (src, 1, &amount, dest, 1, (vDSP_Length) num);
598 #else
599 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount,
600 Mode::add (am, s),
601 JUCE_LOAD_SRC,
602 JUCE_INCREMENT_SRC_DEST,
603 const Mode::ParallelType am = Mode::load1 (amount);)
604 #endif
605 }
606
607 template <typename Size>
608 void add (double* dest, const double* src, double amount, Size num) noexcept
609 {
610 #if JUCE_USE_VDSP_FRAMEWORK
611 vDSP_vsaddD (src, 1, &amount, dest, 1, (vDSP_Length) num);
612 #else
613 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount,
614 Mode::add (am, s),
615 JUCE_LOAD_SRC,
616 JUCE_INCREMENT_SRC_DEST,
617 const Mode::ParallelType am = Mode::load1 (amount);)
618 #endif
619 }
620
621 template <typename Size>
622 void add (float* dest, const float* src, Size num) noexcept
623 {
624 #if JUCE_USE_VDSP_FRAMEWORK
625 vDSP_vadd (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
626 #else
627 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i],
628 Mode::add (d, s),
629 JUCE_LOAD_SRC_DEST,
630 JUCE_INCREMENT_SRC_DEST, )
631 #endif
632 }
633
634 template <typename Size>
635 void add (double* dest, const double* src, Size num) noexcept
636 {
637 #if JUCE_USE_VDSP_FRAMEWORK
638 vDSP_vaddD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
639 #else
640 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i],
641 Mode::add (d, s),
642 JUCE_LOAD_SRC_DEST,
643 JUCE_INCREMENT_SRC_DEST, )
644 #endif
645 }
646
647 template <typename Size>
648 void add (float* dest, const float* src1, const float* src2, Size num) noexcept
649 {
650 #if JUCE_USE_VDSP_FRAMEWORK
651 vDSP_vadd (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
652 #else
653 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i],
654 Mode::add (s1, s2),
655 JUCE_LOAD_SRC1_SRC2,
656 JUCE_INCREMENT_SRC1_SRC2_DEST, )
657 #endif
658 }
659
660 template <typename Size>
661 void add (double* dest, const double* src1, const double* src2, Size num) noexcept
662 {
663 #if JUCE_USE_VDSP_FRAMEWORK
664 vDSP_vaddD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
665 #else
666 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i],
667 Mode::add (s1, s2),
668 JUCE_LOAD_SRC1_SRC2,
669 JUCE_INCREMENT_SRC1_SRC2_DEST, )
670 #endif
671 }
672
673 template <typename Size>
674 void subtract (float* dest, const float* src, Size num) noexcept
675 {
676 #if JUCE_USE_VDSP_FRAMEWORK
677 vDSP_vsub (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
678 #else
679 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i],
680 Mode::sub (d, s),
681 JUCE_LOAD_SRC_DEST,
682 JUCE_INCREMENT_SRC_DEST, )
683 #endif
684 }
685
686 template <typename Size>
687 void subtract (double* dest, const double* src, Size num) noexcept
688 {
689 #if JUCE_USE_VDSP_FRAMEWORK
690 vDSP_vsubD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
691 #else
692 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i],
693 Mode::sub (d, s),
694 JUCE_LOAD_SRC_DEST,
695 JUCE_INCREMENT_SRC_DEST, )
696 #endif
697 }
698
699 template <typename Size>
700 void subtract (float* dest, const float* src1, const float* src2, Size num) noexcept
701 {
702 #if JUCE_USE_VDSP_FRAMEWORK
703 vDSP_vsub (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
704 #else
705 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i],
706 Mode::sub (s1, s2),
707 JUCE_LOAD_SRC1_SRC2,
708 JUCE_INCREMENT_SRC1_SRC2_DEST, )
709 #endif
710 }
711
712 template <typename Size>
713 void subtract (double* dest, const double* src1, const double* src2, Size num) noexcept
714 {
715 #if JUCE_USE_VDSP_FRAMEWORK
716 vDSP_vsubD (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
717 #else
718 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i],
719 Mode::sub (s1, s2),
720 JUCE_LOAD_SRC1_SRC2,
721 JUCE_INCREMENT_SRC1_SRC2_DEST, )
722 #endif
723 }
724
725 template <typename Size>
726 void addWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept
727 {
728 #if JUCE_USE_VDSP_FRAMEWORK
729 vDSP_vsma (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num);
730 #else
731 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier,
732 Mode::add (d, Mode::mul (mult, s)),
733 JUCE_LOAD_SRC_DEST,
734 JUCE_INCREMENT_SRC_DEST,
735 const Mode::ParallelType mult = Mode::load1 (multiplier);)
736 #endif
737 }
738
739 template <typename Size>
740 void addWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept
741 {
742 #if JUCE_USE_VDSP_FRAMEWORK
743 vDSP_vsmaD (src, 1, &multiplier, dest, 1, dest, 1, (vDSP_Length) num);
744 #else
745 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier,
746 Mode::add (d, Mode::mul (mult, s)),
747 JUCE_LOAD_SRC_DEST,
748 JUCE_INCREMENT_SRC_DEST,
749 const Mode::ParallelType mult = Mode::load1 (multiplier);)
750 #endif
751 }
752
753 template <typename Size>
754 void addWithMultiply (float* dest, const float* src1, const float* src2, Size num) noexcept
755 {
756 #if JUCE_USE_VDSP_FRAMEWORK
757 vDSP_vma ((float*) src1, 1, (float*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num);
758 #else
759 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i],
760 Mode::add (d, Mode::mul (s1, s2)),
761 JUCE_LOAD_SRC1_SRC2_DEST,
762 JUCE_INCREMENT_SRC1_SRC2_DEST, )
763 #endif
764 }
765
766 template <typename Size>
767 void addWithMultiply (double* dest, const double* src1, const double* src2, Size num) noexcept
768 {
769 #if JUCE_USE_VDSP_FRAMEWORK
770 vDSP_vmaD ((double*) src1, 1, (double*) src2, 1, dest, 1, dest, 1, (vDSP_Length) num);
771 #else
772 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] += src1[i] * src2[i],
773 Mode::add (d, Mode::mul (s1, s2)),
774 JUCE_LOAD_SRC1_SRC2_DEST,
775 JUCE_INCREMENT_SRC1_SRC2_DEST, )
776 #endif
777 }
778
779 template <typename Size>
780 void subtractWithMultiply (float* dest, const float* src, float multiplier, Size num) noexcept
781 {
782 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier,
783 Mode::sub (d, Mode::mul (mult, s)),
784 JUCE_LOAD_SRC_DEST,
785 JUCE_INCREMENT_SRC_DEST,
786 const Mode::ParallelType mult = Mode::load1 (multiplier);)
787 }
788
789 template <typename Size>
790 void subtractWithMultiply (double* dest, const double* src, double multiplier, Size num) noexcept
791 {
792 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] -= src[i] * multiplier,
793 Mode::sub (d, Mode::mul (mult, s)),
794 JUCE_LOAD_SRC_DEST,
795 JUCE_INCREMENT_SRC_DEST,
796 const Mode::ParallelType mult = Mode::load1 (multiplier);)
797 }
798
799 template <typename Size>
800 void subtractWithMultiply (float* dest, const float* src1, const float* src2, Size num) noexcept
801 {
802 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i],
803 Mode::sub (d, Mode::mul (s1, s2)),
804 JUCE_LOAD_SRC1_SRC2_DEST,
805 JUCE_INCREMENT_SRC1_SRC2_DEST, )
806 }
807
808 template <typename Size>
809 void subtractWithMultiply (double* dest, const double* src1, const double* src2, Size num) noexcept
810 {
811 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST_DEST (dest[i] -= src1[i] * src2[i],
812 Mode::sub (d, Mode::mul (s1, s2)),
813 JUCE_LOAD_SRC1_SRC2_DEST,
814 JUCE_INCREMENT_SRC1_SRC2_DEST, )
815 }
816
817 template <typename Size>
818 void multiply (float* dest, const float* src, Size num) noexcept
819 {
820 #if JUCE_USE_VDSP_FRAMEWORK
821 vDSP_vmul (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
822 #else
823 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i],
824 Mode::mul (d, s),
825 JUCE_LOAD_SRC_DEST,
826 JUCE_INCREMENT_SRC_DEST, )
827 #endif
828 }
829
830 template <typename Size>
831 void multiply (double* dest, const double* src, Size num) noexcept
832 {
833 #if JUCE_USE_VDSP_FRAMEWORK
834 vDSP_vmulD (src, 1, dest, 1, dest, 1, (vDSP_Length) num);
835 #else
836 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] *= src[i],
837 Mode::mul (d, s),
838 JUCE_LOAD_SRC_DEST,
839 JUCE_INCREMENT_SRC_DEST, )
840 #endif
841 }
842
843 template <typename Size>
844 void multiply (float* dest, const float* src1, const float* src2, Size num) noexcept
845 {
846 #if JUCE_USE_VDSP_FRAMEWORK
847 vDSP_vmul (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
848 #else
849 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i],
850 Mode::mul (s1, s2),
851 JUCE_LOAD_SRC1_SRC2,
852 JUCE_INCREMENT_SRC1_SRC2_DEST, )
853 #endif
854 }
855
856 template <typename Size>
857 void multiply (double* dest, const double* src1, const double* src2, Size num) noexcept
858 {
859 #if JUCE_USE_VDSP_FRAMEWORK
860 vDSP_vmulD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
861 #else
862 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i],
863 Mode::mul (s1, s2),
864 JUCE_LOAD_SRC1_SRC2,
865 JUCE_INCREMENT_SRC1_SRC2_DEST, )
866 #endif
867 }
868
869 template <typename Size>
870 void multiply (float* dest, float multiplier, Size num) noexcept
871 {
872 #if JUCE_USE_VDSP_FRAMEWORK
873 vDSP_vsmul (dest, 1, &multiplier, dest, 1, (vDSP_Length) num);
874 #else
875 JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier,
876 Mode::mul (d, mult),
877 JUCE_LOAD_DEST,
878 const Mode::ParallelType mult = Mode::load1 (multiplier);)
879 #endif
880 }
881
882 template <typename Size>
883 void multiply (double* dest, double multiplier, Size num) noexcept
884 {
885 #if JUCE_USE_VDSP_FRAMEWORK
886 vDSP_vsmulD (dest, 1, &multiplier, dest, 1, (vDSP_Length) num);
887 #else
888 JUCE_PERFORM_VEC_OP_DEST (dest[i] *= multiplier,
889 Mode::mul (d, mult),
890 JUCE_LOAD_DEST,
891 const Mode::ParallelType mult = Mode::load1 (multiplier);)
892 #endif
893 }
894
895 template <typename Size>
896 void multiply (float* dest, const float* src, float multiplier, Size num) noexcept
897 {
898 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
899 Mode::mul (mult, s),
900 JUCE_LOAD_SRC,
901 JUCE_INCREMENT_SRC_DEST,
902 const Mode::ParallelType mult = Mode::load1 (multiplier);)
903 }
904
905 template <typename Size>
906 void multiply (double* dest, const double* src, double multiplier, Size num) noexcept
907 {
908 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier,
909 Mode::mul (mult, s),
910 JUCE_LOAD_SRC,
911 JUCE_INCREMENT_SRC_DEST,
912 const Mode::ParallelType mult = Mode::load1 (multiplier);)
913 }
914
915 template <typename Size>
916 void negate (float* dest, const float* src, Size num) noexcept
917 {
918 #if JUCE_USE_VDSP_FRAMEWORK
919 vDSP_vneg ((float*) src, 1, dest, 1, (vDSP_Length) num);
920 #else
921 copyWithMultiply (dest, src, -1.0f, num);
922 #endif
923 }
924
925 template <typename Size>
926 void negate (double* dest, const double* src, Size num) noexcept
927 {
928 #if JUCE_USE_VDSP_FRAMEWORK
929 vDSP_vnegD ((double*) src, 1, dest, 1, (vDSP_Length) num);
930 #else
931 copyWithMultiply (dest, src, -1.0f, num);
932 #endif
933 }
934
935 template <typename Size>
936 void abs (float* dest, const float* src, Size num) noexcept
937 {
938 #if JUCE_USE_VDSP_FRAMEWORK
939 vDSP_vabs ((float*) src, 1, dest, 1, (vDSP_Length) num);
940 #else
941 [[maybe_unused]] FloatVectorHelpers::signMask32 signMask;
942 signMask.i = 0x7fffffffUL;
943 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]),
944 Mode::bit_and (s, mask),
945 JUCE_LOAD_SRC,
946 JUCE_INCREMENT_SRC_DEST,
947 const Mode::ParallelType mask = Mode::load1 (signMask.f);)
948 #endif
949 }
950
951 template <typename Size>
952 void abs (double* dest, const double* src, Size num) noexcept
953 {
954 #if JUCE_USE_VDSP_FRAMEWORK
955 vDSP_vabsD ((double*) src, 1, dest, 1, (vDSP_Length) num);
956 #else
957 [[maybe_unused]] FloatVectorHelpers::signMask64 signMask;
958 signMask.i = 0x7fffffffffffffffULL;
959
960 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = std::abs (src[i]),
961 Mode::bit_and (s, mask),
962 JUCE_LOAD_SRC,
963 JUCE_INCREMENT_SRC_DEST,
964 const Mode::ParallelType mask = Mode::load1 (signMask.d);)
965 #endif
966 }
967
968 template <typename Size>
969 void min (float* dest, const float* src, float comp, Size num) noexcept
970 {
971 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp),
972 Mode::min (s, cmp),
973 JUCE_LOAD_SRC,
974 JUCE_INCREMENT_SRC_DEST,
975 const Mode::ParallelType cmp = Mode::load1 (comp);)
976 }
977
978 template <typename Size>
979 void min (double* dest, const double* src, double comp, Size num) noexcept
980 {
981 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmin (src[i], comp),
982 Mode::min (s, cmp),
983 JUCE_LOAD_SRC,
984 JUCE_INCREMENT_SRC_DEST,
985 const Mode::ParallelType cmp = Mode::load1 (comp);)
986 }
987
988 template <typename Size>
989 void min (float* dest, const float* src1, const float* src2, Size num) noexcept
990 {
991 #if JUCE_USE_VDSP_FRAMEWORK
992 vDSP_vmin ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num);
993 #else
994 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]),
995 Mode::min (s1, s2),
996 JUCE_LOAD_SRC1_SRC2,
997 JUCE_INCREMENT_SRC1_SRC2_DEST, )
998 #endif
999 }
1000
1001 template <typename Size>
1002 void min (double* dest, const double* src1, const double* src2, Size num) noexcept
1003 {
1004 #if JUCE_USE_VDSP_FRAMEWORK
1005 vDSP_vminD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num);
1006 #else
1007 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmin (src1[i], src2[i]),
1008 Mode::min (s1, s2),
1009 JUCE_LOAD_SRC1_SRC2,
1010 JUCE_INCREMENT_SRC1_SRC2_DEST, )
1011 #endif
1012 }
1013
1014 template <typename Size>
1015 void max (float* dest, const float* src, float comp, Size num) noexcept
1016 {
1017 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp),
1018 Mode::max (s, cmp),
1019 JUCE_LOAD_SRC,
1020 JUCE_INCREMENT_SRC_DEST,
1021 const Mode::ParallelType cmp = Mode::load1 (comp);)
1022 }
1023
1024 template <typename Size>
1025 void max (double* dest, const double* src, double comp, Size num) noexcept
1026 {
1027 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (src[i], comp),
1028 Mode::max (s, cmp),
1029 JUCE_LOAD_SRC,
1030 JUCE_INCREMENT_SRC_DEST,
1031 const Mode::ParallelType cmp = Mode::load1 (comp);)
1032 }
1033
1034 template <typename Size>
1035 void max (float* dest, const float* src1, const float* src2, Size num) noexcept
1036 {
1037 #if JUCE_USE_VDSP_FRAMEWORK
1038 vDSP_vmax ((float*) src1, 1, (float*) src2, 1, dest, 1, (vDSP_Length) num);
1039 #else
1040 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]),
1041 Mode::max (s1, s2),
1042 JUCE_LOAD_SRC1_SRC2,
1043 JUCE_INCREMENT_SRC1_SRC2_DEST, )
1044 #endif
1045 }
1046
1047 template <typename Size>
1048 void max (double* dest, const double* src1, const double* src2, Size num) noexcept
1049 {
1050 #if JUCE_USE_VDSP_FRAMEWORK
1051 vDSP_vmaxD ((double*) src1, 1, (double*) src2, 1, dest, 1, (vDSP_Length) num);
1052 #else
1053 JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = jmax (src1[i], src2[i]),
1054 Mode::max (s1, s2),
1055 JUCE_LOAD_SRC1_SRC2,
1056 JUCE_INCREMENT_SRC1_SRC2_DEST, )
1057 #endif
1058 }
1059
1060 template <typename Size>
1061 void clip (float* dest, const float* src, float low, float high, Size num) noexcept
1062 {
1063 jassert (high >= low);
1064
1065 #if JUCE_USE_VDSP_FRAMEWORK
1066 vDSP_vclip ((float*) src, 1, &low, &high, dest, 1, (vDSP_Length) num);
1067 #else
1068 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low),
1069 Mode::max (Mode::min (s, hi), lo),
1070 JUCE_LOAD_SRC,
1071 JUCE_INCREMENT_SRC_DEST,
1072 const Mode::ParallelType lo = Mode::load1 (low);
1073 const Mode::ParallelType hi = Mode::load1 (high);)
1074 #endif
1075 }
1076
1077 template <typename Size>
1078 void clip (double* dest, const double* src, double low, double high, Size num) noexcept
1079 {
1080 jassert (high >= low);
1081
1082 #if JUCE_USE_VDSP_FRAMEWORK
1083 vDSP_vclipD ((double*) src, 1, &low, &high, dest, 1, (vDSP_Length) num);
1084 #else
1085 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = jmax (jmin (src[i], high), low),
1086 Mode::max (Mode::min (s, hi), lo),
1087 JUCE_LOAD_SRC,
1088 JUCE_INCREMENT_SRC_DEST,
1089 const Mode::ParallelType lo = Mode::load1 (low);
1090 const Mode::ParallelType hi = Mode::load1 (high);)
1091 #endif
1092 }
1093
1094 template <typename Size>
1095 Range<float> findMinAndMax (const float* src, Size num) noexcept
1096 {
1097 #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1098 return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps32>::findMinAndMax (src, num);
1099 #else
1100 return Range<float>::findMinAndMax (src, num);
1101 #endif
1102 }
1103
1104 template <typename Size>
1105 Range<double> findMinAndMax (const double* src, Size num) noexcept
1106 {
1107 #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1108 return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps64>::findMinAndMax (src, num);
1109 #else
1110 return Range<double>::findMinAndMax (src, num);
1111 #endif
1112 }
1113
1114 template <typename Size>
1115 float findMinimum (const float* src, Size num) noexcept
1116 {
1117 #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1118 return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps32>::findMinOrMax (src, num, true);
1119 #else
1120 return juce::findMinimum (src, num);
1121 #endif
1122 }
1123
1124 template <typename Size>
1125 double findMinimum (const double* src, Size num) noexcept
1126 {
1127 #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1128 return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps64>::findMinOrMax (src, num, true);
1129 #else
1130 return juce::findMinimum (src, num);
1131 #endif
1132 }
1133
1134 template <typename Size>
1135 float findMaximum (const float* src, Size num) noexcept
1136 {
1137 #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1138 return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps32>::findMinOrMax (src, num, false);
1139 #else
1140 return juce::findMaximum (src, num);
1141 #endif
1142 }
1143
1144 template <typename Size>
1145 double findMaximum (const double* src, Size num) noexcept
1146 {
1147 #if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
1148 return FloatVectorHelpers::MinMax<FloatVectorHelpers::BasicOps64>::findMinOrMax (src, num, false);
1149 #else
1150 return juce::findMaximum (src, num);
1151 #endif
1152 }
1153
1154 template <typename Size>
1155 void convertFixedToFloat (float* dest, const int* src, float multiplier, Size num) noexcept
1156 {
1157 #if JUCE_USE_ARM_NEON
1158 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier,
1159 vmulq_n_f32 (vcvtq_f32_s32 (vld1q_s32 (src)), multiplier),
1160 JUCE_LOAD_NONE,
1161 JUCE_INCREMENT_SRC_DEST, )
1162 #else
1163 JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = (float) src[i] * multiplier,
1164 Mode::mul (mult, _mm_cvtepi32_ps (_mm_loadu_si128 (reinterpret_cast<const __m128i*> (src)))),
1165 JUCE_LOAD_NONE,
1166 JUCE_INCREMENT_SRC_DEST,
1167 const Mode::ParallelType mult = Mode::load1 (multiplier);)
1168 #endif
1169 }
1170
1171} // namespace
1172} // namespace FloatVectorHelpers
1173
1174//==============================================================================
1175template <typename FloatType, typename CountType>
1177 CountType numValues) noexcept
1178{
1179 FloatVectorHelpers::clear (dest, numValues);
1180}
1181
1182template <typename FloatType, typename CountType>
1184 FloatType valueToFill,
1185 CountType numValues) noexcept
1186{
1187 FloatVectorHelpers::fill (dest, valueToFill, numValues);
1188}
1189
1190template <typename FloatType, typename CountType>
1192 const FloatType* src,
1193 CountType numValues) noexcept
1194{
1195 memcpy (dest, src, (size_t) numValues * sizeof (FloatType));
1196}
1197
1198template <typename FloatType, typename CountType>
1200 const FloatType* src,
1201 FloatType multiplier,
1202 CountType numValues) noexcept
1203{
1204 FloatVectorHelpers::copyWithMultiply (dest, src, multiplier, numValues);
1205}
1206
1207template <typename FloatType, typename CountType>
1209 FloatType amountToAdd,
1210 CountType numValues) noexcept
1211{
1212 FloatVectorHelpers::add (dest, amountToAdd, numValues);
1213}
1214
1215template <typename FloatType, typename CountType>
1217 const FloatType* src,
1218 FloatType amount,
1219 CountType numValues) noexcept
1220{
1221 FloatVectorHelpers::add (dest, src, amount, numValues);
1222}
1223
1224template <typename FloatType, typename CountType>
1226 const FloatType* src,
1227 CountType numValues) noexcept
1228{
1229 FloatVectorHelpers::add (dest, src, numValues);
1230}
1231
1232template <typename FloatType, typename CountType>
1234 const FloatType* src1,
1235 const FloatType* src2,
1236 CountType num) noexcept
1237{
1238 FloatVectorHelpers::add (dest, src1, src2, num);
1239}
1240
1241template <typename FloatType, typename CountType>
1243 const FloatType* src,
1244 CountType numValues) noexcept
1245{
1246 FloatVectorHelpers::subtract (dest, src, numValues);
1247}
1248
1249template <typename FloatType, typename CountType>
1251 const FloatType* src1,
1252 const FloatType* src2,
1253 CountType num) noexcept
1254{
1255 FloatVectorHelpers::subtract (dest, src1, src2, num);
1256}
1257
1258template <typename FloatType, typename CountType>
1260 const FloatType* src,
1261 FloatType multiplier,
1262 CountType numValues) noexcept
1263{
1264 FloatVectorHelpers::addWithMultiply (dest, src, multiplier, numValues);
1265}
1266
1267template <typename FloatType, typename CountType>
1269 const FloatType* src1,
1270 const FloatType* src2,
1271 CountType num) noexcept
1272{
1273 FloatVectorHelpers::addWithMultiply (dest, src1, src2, num);
1274}
1275
1276template <typename FloatType, typename CountType>
1278 const FloatType* src,
1279 FloatType multiplier,
1280 CountType numValues) noexcept
1281{
1282 FloatVectorHelpers::subtractWithMultiply (dest, src, multiplier, numValues);
1283}
1284
1285template <typename FloatType, typename CountType>
1287 const FloatType* src1,
1288 const FloatType* src2,
1289 CountType num) noexcept
1290{
1291 FloatVectorHelpers::subtractWithMultiply (dest, src1, src2, num);
1292}
1293
1294template <typename FloatType, typename CountType>
1296 const FloatType* src,
1297 CountType numValues) noexcept
1298{
1299 FloatVectorHelpers::multiply (dest, src, numValues);
1300}
1301
1302template <typename FloatType, typename CountType>
1304 const FloatType* src1,
1305 const FloatType* src2,
1306 CountType numValues) noexcept
1307{
1308 FloatVectorHelpers::multiply (dest, src1, src2, numValues);
1309}
1310
1311template <typename FloatType, typename CountType>
1313 FloatType multiplier,
1314 CountType numValues) noexcept
1315{
1316 FloatVectorHelpers::multiply (dest, multiplier, numValues);
1317}
1318
1319template <typename FloatType, typename CountType>
1321 const FloatType* src,
1322 FloatType multiplier,
1323 CountType num) noexcept
1324{
1325 FloatVectorHelpers::multiply (dest, src, multiplier, num);
1326}
1327
1328template <typename FloatType, typename CountType>
1330 const FloatType* src,
1331 CountType numValues) noexcept
1332{
1333 FloatVectorHelpers::negate (dest, src, numValues);
1334}
1335
1336template <typename FloatType, typename CountType>
1338 const FloatType* src,
1339 CountType numValues) noexcept
1340{
1341 FloatVectorHelpers::abs (dest, src, numValues);
1342}
1343
1344template <typename FloatType, typename CountType>
1346 const FloatType* src,
1347 FloatType comp,
1348 CountType num) noexcept
1349{
1350 FloatVectorHelpers::min (dest, src, comp, num);
1351}
1352
1353template <typename FloatType, typename CountType>
1355 const FloatType* src1,
1356 const FloatType* src2,
1357 CountType num) noexcept
1358{
1359 FloatVectorHelpers::min (dest, src1, src2, num);
1360}
1361
1362template <typename FloatType, typename CountType>
1364 const FloatType* src,
1365 FloatType comp,
1366 CountType num) noexcept
1367{
1368 FloatVectorHelpers::max (dest, src, comp, num);
1369}
1370
1371template <typename FloatType, typename CountType>
1373 const FloatType* src1,
1374 const FloatType* src2,
1375 CountType num) noexcept
1376{
1377 FloatVectorHelpers::max (dest, src1, src2, num);
1378}
1379
1380template <typename FloatType, typename CountType>
1382 const FloatType* src,
1383 FloatType low,
1384 FloatType high,
1385 CountType num) noexcept
1386{
1387 FloatVectorHelpers::clip (dest, src, low, high, num);
1388}
1389
1390template <typename FloatType, typename CountType>
1392 CountType numValues) noexcept
1393{
1394 return FloatVectorHelpers::findMinAndMax (src, numValues);
1395}
1396
1397template <typename FloatType, typename CountType>
1399 CountType numValues) noexcept
1400{
1401 return FloatVectorHelpers::findMinimum (src, numValues);
1402}
1403
1404template <typename FloatType, typename CountType>
1406 CountType numValues) noexcept
1407{
1408 return FloatVectorHelpers::findMaximum (src, numValues);
1409}
1410
1415
1416void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, size_t num) noexcept
1417{
1418 FloatVectorHelpers::convertFixedToFloat (dest, src, multiplier, num);
1419}
1420
1421void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, const int* src, float multiplier, int num) noexcept
1422{
1423 FloatVectorHelpers::convertFixedToFloat (dest, src, multiplier, num);
1424}
1425
1426intptr_t JUCE_CALLTYPE FloatVectorOperations::getFpStatusRegister() noexcept
1427{
1428 intptr_t fpsr = 0;
1429 #if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
1430 fpsr = static_cast<intptr_t> (_mm_getcsr());
1431 #elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
1432 #if _MSC_VER
1433 // _control87 returns static values for x86 bits that don't exist on arm
1434 // to emulate x86 behaviour. We are only ever interested in de-normal bits
1435 // so mask out only those.
1436 fpsr = (intptr_t) (_control87 (0, 0) & _MCW_DN);
1437 #else
1438 #if JUCE_64BIT
1439 asm volatile("mrs %0, fpcr"
1440 : "=r"(fpsr));
1441 #elif JUCE_USE_ARM_NEON
1442 asm volatile("vmrs %0, fpscr"
1443 : "=r"(fpsr));
1444 #endif
1445 #endif
1446 #else
1447 #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1448 jassertfalse; // No support for getting the floating point status register for your platform
1449 #endif
1450 #endif
1451
1452 return fpsr;
1453}
1454
1455void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister ([[maybe_unused]] intptr_t fpsr) noexcept
1456{
1457 #if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
1458 // the volatile keyword here is needed to workaround a bug in AppleClang 13.0
1459 // which aggressively optimises away the variable otherwise
1460 volatile auto fpsr_w = static_cast<uint32_t> (fpsr);
1461 _mm_setcsr (fpsr_w);
1462 #elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
1463 #if _MSC_VER
1464 _control87 ((unsigned int) fpsr, _MCW_DN);
1465 #else
1466 #if JUCE_64BIT
1467 asm volatile("msr fpcr, %0"
1468 :
1469 : "ri"(fpsr));
1470 #elif JUCE_USE_ARM_NEON
1471 asm volatile("vmsr fpscr, %0"
1472 :
1473 : "ri"(fpsr));
1474 #endif
1475 #endif
1476 #else
1477 #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1478 jassertfalse; // No support for getting the floating point status register for your platform
1479 #endif
1480 #endif
1481}
1482
1484{
1485 #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1486 #if JUCE_USE_SSE_INTRINSICS
1488 #else /*JUCE_USE_ARM_NEON*/
1489 intptr_t mask = (1 << 24 /* FZ */);
1490 #endif
1491 setFpStatusRegister ((getFpStatusRegister() & (~mask)) | (shouldEnable ? mask : 0));
1492 #else
1493 #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1494 jassertfalse; // No support for flush to zero mode on your platform
1495 #endif
1496 #endif
1497}
1498
1500{
1501 #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1502 #if JUCE_USE_SSE_INTRINSICS
1503 intptr_t mask = 0x8040;
1504 #else /*JUCE_USE_ARM_NEON*/
1505 intptr_t mask = (1 << 24 /* FZ */);
1506 #endif
1507
1508 setFpStatusRegister ((getFpStatusRegister() & (~mask)) | (shouldDisable ? mask : 0));
1509 #else
1510
1511 #if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
1512 jassertfalse; // No support for disable denormals mode on your platform
1513 #endif
1514 #endif
1515}
1516
1518{
1519 #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1520 #if JUCE_USE_SSE_INTRINSICS
1521 intptr_t mask = 0x8040;
1522 #else /*JUCE_USE_ARM_NEON*/
1523 intptr_t mask = (1 << 24 /* FZ */);
1524 #endif
1525
1526 return ((getFpStatusRegister() & mask) == mask);
1527 #else
1528 return false;
1529 #endif
1530}
1531
1532ScopedNoDenormals::ScopedNoDenormals() noexcept
1533{
1534 #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1535 #if JUCE_USE_SSE_INTRINSICS
1536 intptr_t mask = 0x8040;
1537 #else /*JUCE_USE_ARM_NEON*/
1538 intptr_t mask = (1 << 24 /* FZ */);
1539 #endif
1540
1541 fpsr = FloatVectorOperations::getFpStatusRegister();
1542 FloatVectorOperations::setFpStatusRegister (fpsr | mask);
1543 #endif
1544}
1545
1546ScopedNoDenormals::~ScopedNoDenormals() noexcept
1547{
1548 #if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
1549 FloatVectorOperations::setFpStatusRegister (fpsr);
1550 #endif
1551}
1552
1553
1554//==============================================================================
1555//==============================================================================
1556#if JUCE_UNIT_TESTS
1557
1558class FloatVectorOperationsTests final : public UnitTest
1559{
1560public:
1561 FloatVectorOperationsTests()
1562 : UnitTest ("FloatVectorOperations", UnitTestCategories::audio)
1563 {}
1564
1565 template <typename ValueType>
1566 struct TestRunner
1567 {
1568 static void runTest (UnitTest& u, Random random)
1569 {
1570 const int range = random.nextBool() ? 500 : 10;
1571 const int num = random.nextInt (range) + 1;
1572
1573 HeapBlock<ValueType> buffer1 (num + 16), buffer2 (num + 16);
1574 HeapBlock<int> buffer3 (num + 16, true);
1575
1576 #if JUCE_ARM
1577 ValueType* const data1 = buffer1;
1578 ValueType* const data2 = buffer2;
1579 int* const int1 = buffer3;
1580 #else
1581 // These tests deliberately operate on misaligned memory and will be flagged up by
1582 // checks for undefined behavior!
1583 ValueType* const data1 = addBytesToPointer (buffer1.get(), random.nextInt (16));
1584 ValueType* const data2 = addBytesToPointer (buffer2.get(), random.nextInt (16));
1585 int* const int1 = addBytesToPointer (buffer3.get(), random.nextInt (16));
1586 #endif
1587
1588 fillRandomly (random, data1, num);
1589 fillRandomly (random, data2, num);
1590
1591 Range<ValueType> minMax1 (FloatVectorOperations::findMinAndMax (data1, num));
1592 Range<ValueType> minMax2 (Range<ValueType>::findMinAndMax (data1, num));
1593 u.expect (minMax1 == minMax2);
1594
1595 u.expect (valuesMatch (FloatVectorOperations::findMinimum (data1, num), juce::findMinimum (data1, num)));
1596 u.expect (valuesMatch (FloatVectorOperations::findMaximum (data1, num), juce::findMaximum (data1, num)));
1597
1598 u.expect (valuesMatch (FloatVectorOperations::findMinimum (data2, num), juce::findMinimum (data2, num)));
1599 u.expect (valuesMatch (FloatVectorOperations::findMaximum (data2, num), juce::findMaximum (data2, num)));
1600
1601 FloatVectorOperations::clear (data1, num);
1602 u.expect (areAllValuesEqual (data1, num, 0));
1603
1604 FloatVectorOperations::fill (data1, (ValueType) 2, num);
1605 u.expect (areAllValuesEqual (data1, num, (ValueType) 2));
1606
1607 FloatVectorOperations::add (data1, (ValueType) 2, num);
1608 u.expect (areAllValuesEqual (data1, num, (ValueType) 4));
1609
1610 FloatVectorOperations::copy (data2, data1, num);
1611 u.expect (areAllValuesEqual (data2, num, (ValueType) 4));
1612
1613 FloatVectorOperations::add (data2, data1, num);
1614 u.expect (areAllValuesEqual (data2, num, (ValueType) 8));
1615
1616 FloatVectorOperations::copyWithMultiply (data2, data1, (ValueType) 4, num);
1617 u.expect (areAllValuesEqual (data2, num, (ValueType) 16));
1618
1619 FloatVectorOperations::addWithMultiply (data2, data1, (ValueType) 4, num);
1620 u.expect (areAllValuesEqual (data2, num, (ValueType) 32));
1621
1622 FloatVectorOperations::multiply (data1, (ValueType) 2, num);
1623 u.expect (areAllValuesEqual (data1, num, (ValueType) 8));
1624
1625 FloatVectorOperations::multiply (data1, data2, num);
1626 u.expect (areAllValuesEqual (data1, num, (ValueType) 256));
1627
1628 FloatVectorOperations::negate (data2, data1, num);
1629 u.expect (areAllValuesEqual (data2, num, (ValueType) -256));
1630
1631 FloatVectorOperations::subtract (data1, data2, num);
1632 u.expect (areAllValuesEqual (data1, num, (ValueType) 512));
1633
1634 FloatVectorOperations::abs (data1, data2, num);
1635 u.expect (areAllValuesEqual (data1, num, (ValueType) 256));
1636
1637 FloatVectorOperations::abs (data2, data1, num);
1638 u.expect (areAllValuesEqual (data2, num, (ValueType) 256));
1639
1640 fillRandomly (random, int1, num);
1641 doConversionTest (u, data1, data2, int1, num);
1642
1643 FloatVectorOperations::fill (data1, (ValueType) 2, num);
1644 FloatVectorOperations::fill (data2, (ValueType) 3, num);
1645 FloatVectorOperations::addWithMultiply (data1, data1, data2, num);
1646 u.expect (areAllValuesEqual (data1, num, (ValueType) 8));
1647 }
1648
1649 static void doConversionTest (UnitTest& u, float* data1, float* data2, int* const int1, int num)
1650 {
1651 FloatVectorOperations::convertFixedToFloat (data1, int1, 2.0f, num);
1652 convertFixed (data2, int1, 2.0f, num);
1653 u.expect (buffersMatch (data1, data2, num));
1654 }
1655
1656 static void doConversionTest (UnitTest&, double*, double*, int*, int) {}
1657
1658 static void fillRandomly (Random& random, ValueType* d, int num)
1659 {
1660 while (--num >= 0)
1661 *d++ = (ValueType) (random.nextDouble() * 1000.0);
1662 }
1663
1664 static void fillRandomly (Random& random, int* d, int num)
1665 {
1666 while (--num >= 0)
1667 *d++ = random.nextInt();
1668 }
1669
1670 static void convertFixed (float* d, const int* s, ValueType multiplier, int num)
1671 {
1672 while (--num >= 0)
1673 *d++ = (float) *s++ * multiplier;
1674 }
1675
1676 static bool areAllValuesEqual (const ValueType* d, int num, ValueType target)
1677 {
1678 while (--num >= 0)
1679 if (! exactlyEqual (*d++, target))
1680 return false;
1681
1682 return true;
1683 }
1684
1685 static bool buffersMatch (const ValueType* d1, const ValueType* d2, int num)
1686 {
1687 while (--num >= 0)
1688 if (! valuesMatch (*d1++, *d2++))
1689 return false;
1690
1691 return true;
1692 }
1693
1694 static bool valuesMatch (ValueType v1, ValueType v2)
1695 {
1696 return std::abs (v1 - v2) < std::numeric_limits<ValueType>::epsilon();
1697 }
1698 };
1699
1700 void runTest() override
1701 {
1702 beginTest ("FloatVectorOperations");
1703
1704 for (int i = 1000; --i >= 0;)
1705 {
1706 TestRunner<float>::runTest (*this, getRandom());
1707 TestRunner<double>::runTest (*this, getRandom());
1708 }
1709 }
1710};
1711
1712static FloatVectorOperationsTests vectorOpTests;
1713
1714#endif
1715
1716} // namespace juce
static void JUCE_CALLTYPE disableDenormalisedNumberSupport(bool shouldDisable=true) noexcept
static void JUCE_CALLTYPE enableFlushToZeroMode(bool shouldEnable) noexcept
static bool JUCE_CALLTYPE areDenormalsDisabled() noexcept
static Range findMinAndMax(const ValueType *values, Integral numValues) noexcept
Definition juce_Range.h:279
static void JUCE_CALLTYPE add(FloatType *dest, FloatType amountToAdd, CountType numValues) noexcept
static void JUCE_CALLTYPE max(FloatType *dest, const FloatType *src, FloatType comp, CountType num) noexcept
static FloatType JUCE_CALLTYPE findMinimum(const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE multiply(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE clear(FloatType *dest, CountType numValues) noexcept
static void JUCE_CALLTYPE addWithMultiply(FloatType *dest, const FloatType *src, FloatType multiplier, CountType numValues) noexcept
static Range< FloatType > JUCE_CALLTYPE findMinAndMax(const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE copy(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE clip(FloatType *dest, const FloatType *src, FloatType low, FloatType high, CountType num) noexcept
static FloatType JUCE_CALLTYPE findMaximum(const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE subtractWithMultiply(FloatType *dest, const FloatType *src, FloatType multiplier, CountType numValues) noexcept
static void JUCE_CALLTYPE copyWithMultiply(FloatType *dest, const FloatType *src, FloatType multiplier, CountType numValues) noexcept
static void JUCE_CALLTYPE fill(FloatType *dest, FloatType valueToFill, CountType numValues) noexcept
static void JUCE_CALLTYPE subtract(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE abs(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE negate(FloatType *dest, const FloatType *src, CountType numValues) noexcept
static void JUCE_CALLTYPE min(FloatType *dest, const FloatType *src, FloatType comp, CountType num) noexcept