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.

496 lines
19KB

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