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