OpenShot Audio Library | OpenShotAudio  0.6.0
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 
26 namespace juce::dsp
27 {
28 
29 #if JUCE_USE_SIMD
30 template <typename SampleType>
31 String& operator<< (String& str, SIMDRegister<SampleType>) { return str; }
32 #endif
33 
34 template <typename SampleType>
35 class AudioBlockUnitTests final : public UnitTest
36 {
37 public:
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 
323 private:
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 
489 static AudioBlockUnitTests<float> audioBlockFloatUnitTests;
490 static AudioBlockUnitTests<double> audioBlockDoubleUnitTests;
491 
492 #if JUCE_USE_SIMD
493 static AudioBlockUnitTests<SIMDRegister<float>> audioBlockSIMDFloatUnitTests;
494 static 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