OpenShot Audio Library | OpenShotAudio 0.4.0
 
Loading...
Searching...
No Matches
juce_AudioBlock_test.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 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce::dsp
27{
28
29#if JUCE_USE_SIMD
30template <typename SampleType>
31String& operator<< (String& str, SIMDRegister<SampleType>) { return str; }
32#endif
33
34template <typename SampleType>
35class AudioBlockUnitTests final : public UnitTest
36{
37public:
38 //==============================================================================
39 using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;
40
41 AudioBlockUnitTests()
42 : UnitTest ("AudioBlock", UnitTestCategories::dsp)
43 {
44 for (auto v : { &data, &otherData })
45 for (auto& channel : *v)
46 channel = allocateAlignedMemory (numSamples);
47
48 block = { data.data(), data.size(), (size_t) numSamples };
49 otherBlock = { otherData.data(), otherData.size(), (size_t) numSamples };
50
51 resetBlocks();
52 }
53
54 ~AudioBlockUnitTests() override
55 {
56 for (auto v : { &data, &otherData })
57 for (auto channel : *v)
58 deallocateAlignedMemory (channel);
59 }
60
61 void runTest() override
62 {
63 beginTest ("Equality");
64 {
65 expect (block == block);
66 expect (block != otherBlock);
67 }
68
69 beginTest ("Constructors");
70 {
71 expect (block == AudioBlock<SampleType> (data.data(), data.size(), numSamples));
72 expect (block == AudioBlock<SampleType> (data.data(), data.size(), (size_t) 0, numSamples));
73 expect (block == AudioBlock<SampleType> (block));
74
75 expect (block == AudioBlock<const SampleType> (data.data(), data.size(), numSamples));
76 expect (block == AudioBlock<const SampleType> (data.data(), data.size(), (size_t) 0, numSamples));
77 expect (block == AudioBlock<const SampleType> (block));
78 }
79
80 beginTest ("Swap");
81 {
82 resetBlocks();
83
84 expect (block != otherBlock);
85 expectEquals (block.getSample (0, 0), SampleType (1.0));
86 expectEquals (block.getSample (0, 4), SampleType (5.0));
87 expectEquals (otherBlock.getSample (0, 0), SampleType (-1.0));
88 expectEquals (otherBlock.getSample (0, 3), SampleType (-4.0));
89
90 block.swap (otherBlock);
91
92 expect (block != otherBlock);
93 expectEquals (otherBlock.getSample (0, 0), SampleType (1.0));
94 expectEquals (otherBlock.getSample (0, 4), SampleType (5.0));
95 expectEquals (block.getSample (0, 0), SampleType (-1.0));
96 expectEquals (block.getSample (0, 3), SampleType (-4.0));
97
98 block.swap (otherBlock);
99
100 expectEquals (block.getSample (0, 0), SampleType (1.0));
101 expectEquals (block.getSample (0, 4), SampleType (5.0));
102 expectEquals (otherBlock.getSample (0, 0), SampleType (-1.0));
103 expectEquals (otherBlock.getSample (0, 3), SampleType (-4.0));
104 }
105
106 beginTest ("Getters and setters");
107 {
108 resetBlocks();
109
110 expectEquals ((int) block.getNumChannels(), (int) data.size());
111 expectEquals ((int) block.getNumSamples(), numSamples);
112
113 expectEquals (block.getChannelPointer (0)[2], SampleType (3.0));
114 block.getChannelPointer (0)[2] = SampleType (999.0);
115 expectEquals (block.getChannelPointer (0)[2], SampleType (999.0));
116
117 expectEquals (block.getSample (0, 4), SampleType (5.0));
118 expectEquals (block.getSample (1, 4), SampleType (11.0));
119
120 expectEquals (block.getSingleChannelBlock (1).getSample (0, 3), block.getSample (1, 3));
121
122 expectEquals (block.getSubsetChannelBlock (0, 2).getSample (1, 3), block.getSample (1, 3));
123 expectEquals (block.getSubsetChannelBlock (1, 1).getSample (0, 3), block.getSample (1, 3));
124
125 block.setSample (1, 1, SampleType (777.0));
126 expectEquals (block.getSample (1, 1), SampleType (777.0));
127
128 block.addSample (1, 1, SampleType (1.0));
129 expectEquals (block.getSample (1, 1), SampleType (778.0));
130 }
131
132 beginTest ("Basic copying");
133 {
134 block.clear();
135 expectEquals (block.getSample (0, 2), SampleType (0.0));
136 expectEquals (block.getSample (1, 4), SampleType (0.0));
137
138 block.fill ((NumericType) 456.0);
139 expectEquals (block.getSample (0, 2), SampleType (456.0));
140 expectEquals (block.getSample (1, 4), SampleType (456.0));
141
142 block.copyFrom (otherBlock);
143 expect (block != otherBlock);
144 expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2));
145 expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4));
146
147 resetBlocks();
148
149 SampleType testSample1 = block.getSample (0, 2);
150 SampleType testSample2 = block.getSample (1, 3);
151 expectNotEquals (testSample1, block.getSample (0, 4));
152 expectNotEquals (testSample2, block.getSample (1, 5));
153 block.move (0, 2);
154 expectEquals (block.getSample (0, 4), testSample1);
155 expectEquals (block.getSample (1, 5), testSample2);
156 }
157
158 beginTest ("Addition");
159 {
160 resetBlocks();
161
162 block.add ((NumericType) 15.0);
163 expectEquals (block.getSample (0, 4), SampleType (20.0));
164 expectEquals (block.getSample (1, 4), SampleType (26.0));
165
166 block.add (otherBlock);
167 expectEquals (block.getSample (0, 4), SampleType (15.0));
168 expectEquals (block.getSample (1, 4), SampleType (15.0));
169
170 block.replaceWithSumOf (otherBlock, (NumericType) 9.0);
171 expectEquals (block.getSample (0, 4), SampleType (4.0));
172 expectEquals (block.getSample (1, 4), SampleType (-2.0));
173
174 resetBlocks();
175
176 block.replaceWithSumOf (block, otherBlock);
177 expectEquals (block.getSample (0, 4), SampleType (0.0));
178 expectEquals (block.getSample (1, 4), SampleType (0.0));
179 }
180
181 beginTest ("Subtraction");
182 {
183 resetBlocks();
184
185 block.subtract ((NumericType) 15.0);
186 expectEquals (block.getSample (0, 4), SampleType (-10.0));
187 expectEquals (block.getSample (1, 4), SampleType (-4.0));
188
189 block.subtract (otherBlock);
190 expectEquals (block.getSample (0, 4), SampleType (-5.0));
191 expectEquals (block.getSample (1, 4), SampleType (7.0));
192
193 block.replaceWithDifferenceOf (otherBlock, (NumericType) 9.0);
194 expectEquals (block.getSample (0, 4), SampleType (-14.0));
195 expectEquals (block.getSample (1, 4), SampleType (-20.0));
196
197 resetBlocks();
198
199 block.replaceWithDifferenceOf (block, otherBlock);
200 expectEquals (block.getSample (0, 4), SampleType (10.0));
201 expectEquals (block.getSample (1, 4), SampleType (22.0));
202 }
203
204 beginTest ("Multiplication");
205 {
206 resetBlocks();
207
208 block.multiplyBy ((NumericType) 10.0);
209 expectEquals (block.getSample (0, 4), SampleType (50.0));
210 expectEquals (block.getSample (1, 4), SampleType (110.0));
211
212 block.multiplyBy (otherBlock);
213 expectEquals (block.getSample (0, 4), SampleType (-250.0));
214 expectEquals (block.getSample (1, 4), SampleType (-1210.0));
215
216 block.replaceWithProductOf (otherBlock, (NumericType) 3.0);
217 expectEquals (block.getSample (0, 4), SampleType (-15.0));
218 expectEquals (block.getSample (1, 4), SampleType (-33.0));
219
220 resetBlocks();
221
222 block.replaceWithProductOf (block, otherBlock);
223 expectEquals (block.getSample (0, 4), SampleType (-25.0));
224 expectEquals (block.getSample (1, 4), SampleType (-121.0));
225 }
226
227 beginTest ("Multiply add");
228 {
229 resetBlocks();
230
231 block.addProductOf (otherBlock, (NumericType) -1.0);
232 expectEquals (block.getSample (0, 4), SampleType (10.0));
233 expectEquals (block.getSample (1, 4), SampleType (22.0));
234
235 block.addProductOf (otherBlock, otherBlock);
236 expectEquals (block.getSample (0, 4), SampleType (35.0));
237 expectEquals (block.getSample (1, 4), SampleType (143.0));
238 }
239
240 beginTest ("Negative abs min max");
241 {
242 resetBlocks();
243 otherBlock.negate();
244
245 block.add (otherBlock);
246 expectEquals (block.getSample (0, 4), SampleType (10.0));
247 expectEquals (block.getSample (1, 4), SampleType (22.0));
248
249 block.replaceWithNegativeOf (otherBlock);
250 expectEquals (block.getSample (0, 4), SampleType (-5.0));
251 expectEquals (block.getSample (1, 4), SampleType (-11.0));
252
253 block.clear();
254 otherBlock.negate();
255 block.replaceWithAbsoluteValueOf (otherBlock);
256 expectEquals (block.getSample (0, 4), SampleType (5.0));
257 expectEquals (block.getSample (1, 4), SampleType (11.0));
258
259 resetBlocks();
260 block.replaceWithMinOf (block, otherBlock);
261 expectEquals (block.getSample (0, 4), SampleType (-5.0));
262 expectEquals (block.getSample (1, 4), SampleType (-11.0));
263
264 resetBlocks();
265 block.replaceWithMaxOf (block, otherBlock);
266 expectEquals (block.getSample (0, 4), SampleType (5.0));
267 expectEquals (block.getSample (1, 4), SampleType (11.0));
268
269 resetBlocks();
270 auto range = block.findMinAndMax();
271 expectEquals (SampleType (range.getStart()), SampleType (1.0));
272 expectEquals (SampleType (range.getEnd()), SampleType (12.0));
273 }
274
275 beginTest ("Operators");
276 {
277 resetBlocks();
278 block += (NumericType) 10.0;
279 expectEquals (block.getSample (0, 4), SampleType (15.0));
280 expectEquals (block.getSample (1, 4), SampleType (21.0));
281 block += otherBlock;
282 expectEquals (block.getSample (0, 4), SampleType (10.0));
283 expectEquals (block.getSample (1, 4), SampleType (10.0));
284
285 resetBlocks();
286 block -= (NumericType) 10.0;
287 expectEquals (block.getSample (0, 4), SampleType (-5.0));
288 expectEquals (block.getSample (1, 4), SampleType (1.0));
289 block -= otherBlock;
290 expectEquals (block.getSample (0, 4), SampleType (0.0));
291 expectEquals (block.getSample (1, 4), SampleType (12.0));
292
293 resetBlocks();
294 block *= (NumericType) 10.0;
295 expectEquals (block.getSample (0, 4), SampleType (50.0));
296 expectEquals (block.getSample (1, 4), SampleType (110.0));
297 block *= otherBlock;
298 expectEquals (block.getSample (0, 4), SampleType (-250.0));
299 expectEquals (block.getSample (1, 4), SampleType (-1210.0));
300 }
301
302 beginTest ("Process");
303 {
304 resetBlocks();
305 AudioBlock<SampleType>::process (block, otherBlock, [] (SampleType x) { return x + (NumericType) 1.0; });
306 expectEquals (otherBlock.getSample (0, 4), SampleType (6.0));
307 expectEquals (otherBlock.getSample (1, 4), SampleType (12.0));
308 }
309
310 beginTest ("Copying");
311 {
312 resetBlocks();
313 copyingTests();
314 }
315
316 beginTest ("Smoothing");
317 {
318 resetBlocks();
319 smoothedValueTests();
320 }
321 }
322
323private:
324 //==============================================================================
325 void copyingTests()
326 {
327 if constexpr (std::is_scalar_v<SampleType>)
328 {
329 auto unchangedElement1 = block.getSample (0, 4);
330 auto unchangedElement2 = block.getSample (1, 1);
331
332 AudioBuffer<SampleType> otherBuffer (otherData.data(), (int) otherData.size(), numSamples);
333
334 block.copyFrom (otherBuffer, 1, 2, 2);
335
336 expectEquals (block.getSample (0, 4), unchangedElement1);
337 expectEquals (block.getSample (1, 1), unchangedElement2);
338 expectEquals (block.getSample (0, 2), otherBuffer.getSample (0, 1));
339 expectEquals (block.getSample (1, 3), otherBuffer.getSample (1, 2));
340
341 resetBlocks();
342
343 unchangedElement1 = otherBuffer.getSample (0, 4);
344 unchangedElement2 = otherBuffer.getSample (1, 3);
345
346 block.copyTo (otherBuffer, 2, 1, 2);
347
348 expectEquals (otherBuffer.getSample (0, 4), unchangedElement1);
349 expectEquals (otherBuffer.getSample (1, 3), unchangedElement2);
350 expectEquals (otherBuffer.getSample (0, 1), block.getSample (0, 2));
351 expectEquals (otherBuffer.getSample (1, 2), block.getSample (1, 3));
352 }
353 #if JUCE_USE_SIMD
354 else
355 {
356 auto numSIMDElements = SIMDRegister<NumericType>::SIMDNumElements;
357 AudioBuffer<NumericType> numericData ((int) block.getNumChannels(),
358 (int) (block.getNumSamples() * numSIMDElements));
359
360 for (int c = 0; c < numericData.getNumChannels(); ++c)
361 std::fill_n (numericData.getWritePointer (c), numericData.getNumSamples(), (NumericType) 1.0);
362
363 numericData.applyGainRamp (0, numericData.getNumSamples(), (NumericType) 0.127, (NumericType) 17.3);
364
365 auto lastUnchangedIndexBeforeCopiedRange = (int) ((numSIMDElements * 2) - 1);
366 auto firstUnchangedIndexAfterCopiedRange = (int) ((numSIMDElements * 4) + 1);
367 auto unchangedElement1 = numericData.getSample (0, lastUnchangedIndexBeforeCopiedRange);
368 auto unchangedElement2 = numericData.getSample (1, firstUnchangedIndexAfterCopiedRange);
369
370 block.copyTo (numericData, 1, 2, 2);
371
372 expectEquals (numericData.getSample (0, lastUnchangedIndexBeforeCopiedRange), unchangedElement1);
373 expectEquals (numericData.getSample (1, firstUnchangedIndexAfterCopiedRange), unchangedElement2);
374 expect (SampleType (numericData.getSample (0, 2 * (int) numSIMDElements)) == block.getSample (0, 1));
375 expect (SampleType (numericData.getSample (1, 3 * (int) numSIMDElements)) == block.getSample (1, 2));
376
377 numericData.applyGainRamp (0, numericData.getNumSamples(), (NumericType) 15.1, (NumericType) 0.7);
378
379 auto unchangedSIMDElement1 = block.getSample (0, 1);
380 auto unchangedSIMDElement2 = block.getSample (1, 4);
381
382 block.copyFrom (numericData, 1, 2, 2);
383
384 expect (block.getSample (0, 1) == unchangedSIMDElement1);
385 expect (block.getSample (1, 4) == unchangedSIMDElement2);
386 expectEquals (block.getSample (0, 2).get (0), numericData.getSample (0, (int) numSIMDElements));
387 expectEquals (block.getSample (1, 3).get (0), numericData.getSample (1, (int) (numSIMDElements * 2)));
388
389 if (numSIMDElements > 1)
390 {
391 expectEquals (block.getSample (0, 2).get (1), numericData.getSample (0, (int) (numSIMDElements + 1)));
392 expectEquals (block.getSample (1, 3).get (1), numericData.getSample (1, (int) ((numSIMDElements * 2) + 1)));
393 }
394 }
395 #endif
396 }
397
398 //==============================================================================
399 void smoothedValueTests()
400 {
401 if constexpr (std::is_scalar_v<SampleType>)
402 {
403 block.fill ((SampleType) 1.0);
404 SmoothedValue<SampleType> sv { (SampleType) 1.0 };
405 sv.reset (1, 4);
406 sv.setTargetValue ((SampleType) 0.0);
407
408 block.multiplyBy (sv);
409 expect (block.getSample (0, 2) < (SampleType) 1.0);
410 expect (block.getSample (1, 2) < (SampleType) 1.0);
411 expect (block.getSample (0, 2) > (SampleType) 0.0);
412 expect (block.getSample (1, 2) > (SampleType) 0.0);
413 expectEquals (block.getSample (0, 5), (SampleType) 0.0);
414 expectEquals (block.getSample (1, 5), (SampleType) 0.0);
415
416 sv.setCurrentAndTargetValue (-1.0f);
417 sv.setTargetValue (0.0f);
418 otherBlock.fill (-1.0f);
419 block.replaceWithProductOf (otherBlock, sv);
420 expect (block.getSample (0, 2) < (SampleType) 1.0);
421 expect (block.getSample (1, 2) < (SampleType) 1.0);
422 expect (block.getSample (0, 2) > (SampleType) 0.0);
423 expect (block.getSample (1, 2) > (SampleType) 0.0);
424 expectEquals (block.getSample (0, 5), (SampleType) 0.0);
425 expectEquals (block.getSample (1, 5), (SampleType) 0.0);
426 }
427 }
428
429 //==============================================================================
430 void resetBlocks()
431 {
432 auto value = SampleType (1.0);
433
434 for (size_t c = 0; c < block.getNumChannels(); ++c)
435 {
436 for (size_t i = 0; i < block.getNumSamples(); ++i)
437 {
438 block.setSample ((int) c, (int) i, value);
439 value += SampleType (1.0);
440 }
441 }
442
443 otherBlock.replaceWithNegativeOf (block);
444 }
445
446 //==============================================================================
447 static SampleType* allocateAlignedMemory (int numSamplesToAllocate)
448 {
449 auto alignmentLowerBound = std::alignment_of_v<SampleType>;
450 #if ! JUCE_WINDOWS
451 alignmentLowerBound = jmax (sizeof (void*), alignmentLowerBound);
452 #endif
453 auto alignmentOrder = std::ceil (std::log2 (alignmentLowerBound));
454 auto requiredAlignment = (size_t) std::pow (2, alignmentOrder);
455
456 auto size = (size_t) numSamplesToAllocate * sizeof (SampleType);
457
458 #if JUCE_WINDOWS
459 auto* memory = _aligned_malloc (size, requiredAlignment);
460 #else
461 void* memory;
462 auto result = posix_memalign (&memory, requiredAlignment, size);
463
464 if (result != 0)
465 {
466 jassertfalse;
467 return nullptr;
468 }
469 #endif
470
471 return static_cast<SampleType*> (memory);
472 }
473
474 void deallocateAlignedMemory (void* address)
475 {
476 #if JUCE_WINDOWS
477 _aligned_free (address);
478 #else
479 free (address);
480 #endif
481 }
482
483 //==============================================================================
484 static constexpr int numChannels = 2, numSamples = 6;
485 std::array<SampleType*, numChannels> data, otherData;
486 AudioBlock<SampleType> block, otherBlock;
487};
488
489static AudioBlockUnitTests<float> audioBlockFloatUnitTests;
490static AudioBlockUnitTests<double> audioBlockDoubleUnitTests;
491
492#if JUCE_USE_SIMD
493static AudioBlockUnitTests<SIMDRegister<float>> audioBlockSIMDFloatUnitTests;
494static AudioBlockUnitTests<SIMDRegister<double>> audioBlockSIMDDoubleUnitTests;
495#endif
496
497} // namespace juce::dsp
void expectEquals(ValueType actual, ValueType expected, String failureMessage=String())
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
void expect(bool testResult, const String &failureMessage=String())
void expectNotEquals(ValueType value, ValueType valueToCompareTo, String failureMessage=String())
static void process(AudioBlock< Src1SampleType > inBlock, AudioBlock< Src2SampleType > outBlock, FunctionType &&function)
static constexpr size_t SIMDNumElements