OpenShot Library | OpenShotAudio  0.2.1
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>
34 {
35 public:
36  //==============================================================================
37  using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;
38 
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
A utility class for values that need smoothing to avoid audio glitches.
UnitTest(const String &name, const String &category=String())
Creates a test with the given name and optionally places it in a category.
Minimal and lightweight data-structure which contains a list of pointers to channels containing some ...
void reset(double sampleRate, double rampLengthInSeconds) noexcept
Reset to a new sample rate and ramp length.
Type getSample(int channel, int sampleIndex) const noexcept
Returns a sample from the buffer.
A wrapper around the platform&#39;s native SIMD register type.
void expectEquals(ValueType actual, ValueType expected, String failureMessage=String())
Compares a value to an expected value.
static void process(AudioBlock< Src1SampleType > inBlock, AudioBlock< Src2SampleType > outBlock, FunctionType &&function)
Applies a function to each value in an input block, putting the result into an output block...
This is a base class for classes that perform a unit test.
Definition: juce_UnitTest.h:73
void runTest() override
Implement this method in your subclass to actually run your tests.
void beginTest(const String &testName)
Tells the system that a new subsection of tests is beginning.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
void applyGainRamp(int channel, int startSample, int numSamples, Type startGain, Type endGain) noexcept
Applies a range of gains to a region of a channel.
void expect(bool testResult, const String &failureMessage=String())
Checks that the result of a test is true, and logs this result.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer&#39;s channels.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer&#39;s channels.