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.

492 lines
19KB

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