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.

168 lines
5.5KB

  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. class ProcessorChainTest : public UnitTest
  23. {
  24. template <int AddValue>
  25. struct MockProcessor
  26. {
  27. void prepare (const ProcessSpec&) noexcept { isPrepared = true; }
  28. void reset() noexcept { isReset = true; }
  29. template <typename Context>
  30. void process (const Context& context) noexcept
  31. {
  32. bufferWasClear = context.getInputBlock().getSample (0, 0) == 0;
  33. if (! context.isBypassed)
  34. context.getOutputBlock().add (AddValue);
  35. }
  36. bool isPrepared = false;
  37. bool isReset = false;
  38. bool bufferWasClear = false;
  39. };
  40. public:
  41. ProcessorChainTest()
  42. : UnitTest ("ProcessorChain", UnitTestCategories::dsp) {}
  43. void runTest() override
  44. {
  45. beginTest ("After calling setBypass, processor is bypassed");
  46. {
  47. ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
  48. setBypassed<0> (chain, true);
  49. expect (isBypassed<0> (chain));
  50. setBypassed<0> (chain, false);
  51. expect (! isBypassed<0> (chain));
  52. setBypassed<1> (chain, true);
  53. expect (isBypassed<1> (chain));
  54. setBypassed<1> (chain, false);
  55. expect (! isBypassed<1> (chain));
  56. }
  57. beginTest ("After calling prepare, all processors are prepared");
  58. {
  59. ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
  60. expect (! get<0> (chain).isPrepared);
  61. expect (! get<1> (chain).isPrepared);
  62. chain.prepare (ProcessSpec{});
  63. expect (get<0> (chain).isPrepared);
  64. expect (get<1> (chain).isPrepared);
  65. }
  66. beginTest ("After calling reset, all processors are reset");
  67. {
  68. ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
  69. expect (! get<0> (chain).isReset);
  70. expect (! get<1> (chain).isReset);
  71. chain.reset();
  72. expect (get<0> (chain).isReset);
  73. expect (get<1> (chain).isReset);
  74. }
  75. beginTest ("After calling process, all processors contribute to processing");
  76. {
  77. ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
  78. AudioBuffer<float> buffer (1, 1);
  79. AudioBlock<float> block (buffer);
  80. ProcessContextReplacing<float> context (block);
  81. block.clear();
  82. chain.process (context);
  83. expectEquals (buffer.getSample (0, 0), 3.0f);
  84. expect (get<0> (chain).bufferWasClear);
  85. expect (! get<1> (chain).bufferWasClear);
  86. setBypassed<0> (chain, true);
  87. block.clear();
  88. chain.process (context);
  89. expectEquals (buffer.getSample (0, 0), 2.0f);
  90. expect (get<0> (chain).bufferWasClear);
  91. expect (get<1> (chain).bufferWasClear);
  92. setBypassed<1> (chain, true);
  93. block.clear();
  94. chain.process (context);
  95. expectEquals (buffer.getSample (0, 0), 0.0f);
  96. expect (get<0> (chain).bufferWasClear);
  97. expect (get<1> (chain).bufferWasClear);
  98. setBypassed<0> (chain, false);
  99. block.clear();
  100. chain.process (context);
  101. expectEquals (buffer.getSample (0, 0), 1.0f);
  102. expect (get<0> (chain).bufferWasClear);
  103. expect (! get<1> (chain).bufferWasClear);
  104. }
  105. beginTest ("Chains with trailing items that only support replacing contexts can be built");
  106. {
  107. AudioBuffer<float> inBuf (1, 1), outBuf (1, 1);
  108. juce::dsp::AudioBlock<float> in (inBuf), out (outBuf);
  109. struct OnlyReplacing
  110. {
  111. void prepare (const juce::dsp::ProcessSpec&) {}
  112. void process (const juce::dsp::ProcessContextReplacing<float>& c)
  113. {
  114. c.getOutputBlock().multiplyBy (2.0f);
  115. }
  116. void reset() {}
  117. };
  118. {
  119. juce::dsp::ProcessorChain<juce::dsp::Gain<float>, OnlyReplacing, OnlyReplacing> c;
  120. juce::dsp::ProcessContextNonReplacing<float> context (in, out);
  121. get<0> (c).setGainLinear (1.0f);
  122. c.prepare (ProcessSpec{});
  123. inBuf.setSample (0, 0, 1.0f);
  124. c.process (context);
  125. expectEquals (outBuf.getSample (0, 0), 4.0f);
  126. }
  127. }
  128. }
  129. };
  130. static ProcessorChainTest processorChainUnitTest;
  131. } // namespace dsp
  132. } // namespace juce