Audio plugin host https://kx.studio/carla
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.

juce_AudioBlock_test.cpp 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. template <typename T>
  253. using ScalarVoid = typename std::enable_if_t < std::is_scalar <T>::value, void>;
  254. template <typename T>
  255. using SIMDVoid = typename std::enable_if_t <! std::is_scalar <T>::value, void>;
  256. //==============================================================================
  257. template <typename T = SampleType>
  258. ScalarVoid<T> copyingTests()
  259. {
  260. auto unchangedElement1 = block.getSample (0, 4);
  261. auto unchangedElement2 = block.getSample (1, 1);
  262. AudioBuffer<SampleType> otherBuffer (otherData.data(), (int) otherData.size(), numSamples);
  263. block.copyFrom (otherBuffer, 1, 2, 2);
  264. expectEquals (block.getSample (0, 4), unchangedElement1);
  265. expectEquals (block.getSample (1, 1), unchangedElement2);
  266. expectEquals (block.getSample (0, 2), otherBuffer.getSample (0, 1));
  267. expectEquals (block.getSample (1, 3), otherBuffer.getSample (1, 2));
  268. resetBlocks();
  269. unchangedElement1 = otherBuffer.getSample (0, 4);
  270. unchangedElement2 = otherBuffer.getSample (1, 3);
  271. block.copyTo (otherBuffer, 2, 1, 2);
  272. expectEquals (otherBuffer.getSample (0, 4), unchangedElement1);
  273. expectEquals (otherBuffer.getSample (1, 3), unchangedElement2);
  274. expectEquals (otherBuffer.getSample (0, 1), block.getSample (0, 2));
  275. expectEquals (otherBuffer.getSample (1, 2), block.getSample (1, 3));
  276. }
  277. #if JUCE_USE_SIMD
  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. #endif
  311. //==============================================================================
  312. template <typename T = SampleType>
  313. ScalarVoid<T> smoothedValueTests()
  314. {
  315. block.fill ((SampleType) 1.0);
  316. SmoothedValue<SampleType> sv { (SampleType) 1.0 };
  317. sv.reset (1, 4);
  318. sv.setTargetValue ((SampleType) 0.0);
  319. block.multiplyBy (sv);
  320. expect (block.getSample (0, 2) < (SampleType) 1.0);
  321. expect (block.getSample (1, 2) < (SampleType) 1.0);
  322. expect (block.getSample (0, 2) > (SampleType) 0.0);
  323. expect (block.getSample (1, 2) > (SampleType) 0.0);
  324. expectEquals (block.getSample (0, 5), (SampleType) 0.0);
  325. expectEquals (block.getSample (1, 5), (SampleType) 0.0);
  326. sv.setCurrentAndTargetValue (-1.0f);
  327. sv.setTargetValue (0.0f);
  328. otherBlock.fill (-1.0f);
  329. block.replaceWithProductOf (otherBlock, sv);
  330. expect (block.getSample (0, 2) < (SampleType) 1.0);
  331. expect (block.getSample (1, 2) < (SampleType) 1.0);
  332. expect (block.getSample (0, 2) > (SampleType) 0.0);
  333. expect (block.getSample (1, 2) > (SampleType) 0.0);
  334. expectEquals (block.getSample (0, 5), (SampleType) 0.0);
  335. expectEquals (block.getSample (1, 5), (SampleType) 0.0);
  336. }
  337. template <typename T = SampleType>
  338. SIMDVoid<T> smoothedValueTests() {}
  339. //==============================================================================
  340. void resetBlocks()
  341. {
  342. auto value = SampleType (1.0);
  343. for (size_t c = 0; c < block.getNumChannels(); ++c)
  344. {
  345. for (size_t i = 0; i < block.getNumSamples(); ++i)
  346. {
  347. block.setSample ((int) c, (int) i, value);
  348. value += SampleType (1.0);
  349. }
  350. }
  351. otherBlock.replaceWithNegativeOf (block);
  352. }
  353. //==============================================================================
  354. static SampleType* allocateAlignedMemory (int numSamplesToAllocate)
  355. {
  356. auto alignmentLowerBound = std::alignment_of<SampleType>::value;
  357. #if ! JUCE_WINDOWS
  358. alignmentLowerBound = jmax (sizeof (void*), alignmentLowerBound);
  359. #endif
  360. auto alignmentOrder = std::ceil (std::log2 (alignmentLowerBound));
  361. auto requiredAlignment = (size_t) std::pow (2, alignmentOrder);
  362. auto size = (size_t) numSamplesToAllocate * sizeof (SampleType);
  363. #if JUCE_WINDOWS
  364. auto* memory = _aligned_malloc (size, requiredAlignment);
  365. #else
  366. void* memory;
  367. auto result = posix_memalign (&memory, requiredAlignment, size);
  368. if (result != 0)
  369. {
  370. jassertfalse;
  371. return nullptr;
  372. }
  373. #endif
  374. return static_cast<SampleType*> (memory);
  375. }
  376. void deallocateAlignedMemory (void* address)
  377. {
  378. #if JUCE_WINDOWS
  379. _aligned_free (address);
  380. #else
  381. free (address);
  382. #endif
  383. }
  384. //==============================================================================
  385. static constexpr int numChannels = 2, numSamples = 6;
  386. std::array<SampleType*, numChannels> data, otherData;
  387. AudioBlock<SampleType> block, otherBlock;
  388. };
  389. static AudioBlockUnitTests<float> audioBlockFloatUnitTests;
  390. static AudioBlockUnitTests<double> audioBlockDoubleUnitTests;
  391. #if JUCE_USE_SIMD
  392. static AudioBlockUnitTests<SIMDRegister<float>> audioBlockSIMDFloatUnitTests;
  393. static AudioBlockUnitTests<SIMDRegister<double>> audioBlockSIMDDoubleUnitTests;
  394. #endif
  395. } // namespace dsp
  396. } // namespace juce