The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

500 lines
19KB

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