OpenShot Audio Library | OpenShotAudio  0.6.0
juce_ProcessorChain_test.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11  Agreement and JUCE Privacy Policy.
12 
13  End User License Agreement: www.juce.com/juce-7-licence
14  Privacy Policy: www.juce.com/juce-privacy-policy
15 
16  Or: You may also use this code under the terms of the GPL v3 (see
17  www.gnu.org/licenses).
18 
19  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21  DISCLAIMED.
22 
23  ==============================================================================
24 */
25 
26 namespace juce::dsp
27 {
28 
29 class ProcessorChainTest final : public UnitTest
30 {
31  template <int AddValue>
32  struct MockProcessor
33  {
34  void prepare (const ProcessSpec&) noexcept { isPrepared = true; }
35  void reset() noexcept { isReset = true; }
36 
37  template <typename Context>
38  void process (const Context& context) noexcept
39  {
40  bufferWasClear = approximatelyEqual (context.getInputBlock().getSample (0, 0), 0.0f);
41 
42  if (! context.isBypassed)
43  context.getOutputBlock().add (AddValue);
44  }
45 
46  bool isPrepared = false;
47  bool isReset = false;
48  bool bufferWasClear = false;
49  };
50 
51 public:
52  ProcessorChainTest()
53  : UnitTest ("ProcessorChain", UnitTestCategories::dsp) {}
54 
55  void runTest() override
56  {
57  beginTest ("After calling setBypass, processor is bypassed");
58  {
59  ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
60 
61  setBypassed<0> (chain, true);
62  expect (isBypassed<0> (chain));
63  setBypassed<0> (chain, false);
64  expect (! isBypassed<0> (chain));
65 
66  setBypassed<1> (chain, true);
67  expect (isBypassed<1> (chain));
68  setBypassed<1> (chain, false);
69  expect (! isBypassed<1> (chain));
70  }
71 
72  beginTest ("After calling prepare, all processors are prepared");
73  {
74  ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
75 
76  expect (! get<0> (chain).isPrepared);
77  expect (! get<1> (chain).isPrepared);
78 
79  chain.prepare (ProcessSpec{});
80 
81  expect (get<0> (chain).isPrepared);
82  expect (get<1> (chain).isPrepared);
83  }
84 
85  beginTest ("After calling reset, all processors are reset");
86  {
87  ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
88 
89  expect (! get<0> (chain).isReset);
90  expect (! get<1> (chain).isReset);
91 
92  chain.reset();
93 
94  expect (get<0> (chain).isReset);
95  expect (get<1> (chain).isReset);
96  }
97 
98  beginTest ("After calling process, all processors contribute to processing");
99  {
100  ProcessorChain<MockProcessor<1>, MockProcessor<2>> chain;
101 
102  AudioBuffer<float> buffer (1, 1);
103  AudioBlock<float> block (buffer);
104  ProcessContextReplacing<float> context (block);
105 
106  block.clear();
107  chain.process (context);
108  expectEquals (buffer.getSample (0, 0), 3.0f);
109  expect (get<0> (chain).bufferWasClear);
110  expect (! get<1> (chain).bufferWasClear);
111 
112  setBypassed<0> (chain, true);
113  block.clear();
114  chain.process (context);
115  expectEquals (buffer.getSample (0, 0), 2.0f);
116  expect (get<0> (chain).bufferWasClear);
117  expect (get<1> (chain).bufferWasClear);
118 
119  setBypassed<1> (chain, true);
120  block.clear();
121  chain.process (context);
122  expectEquals (buffer.getSample (0, 0), 0.0f);
123  expect (get<0> (chain).bufferWasClear);
124  expect (get<1> (chain).bufferWasClear);
125 
126  setBypassed<0> (chain, false);
127  block.clear();
128  chain.process (context);
129  expectEquals (buffer.getSample (0, 0), 1.0f);
130  expect (get<0> (chain).bufferWasClear);
131  expect (! get<1> (chain).bufferWasClear);
132  }
133 
134  beginTest ("Chains with trailing items that only support replacing contexts can be built");
135  {
136  AudioBuffer<float> inBuf (1, 1), outBuf (1, 1);
137  juce::dsp::AudioBlock<float> in (inBuf), out (outBuf);
138 
139  struct OnlyReplacing
140  {
141  void prepare (const juce::dsp::ProcessSpec&) {}
142  void process (const juce::dsp::ProcessContextReplacing<float>& c)
143  {
144  c.getOutputBlock().multiplyBy (2.0f);
145  }
146  void reset() {}
147  };
148 
149  {
150  juce::dsp::ProcessorChain<juce::dsp::Gain<float>, OnlyReplacing, OnlyReplacing> c;
152  get<0> (c).setGainLinear (1.0f);
153  c.prepare (ProcessSpec{});
154  inBuf.setSample (0, 0, 1.0f);
155  c.process (context);
156  expectEquals (outBuf.getSample (0, 0), 4.0f);
157  }
158  }
159  }
160 };
161 
162 static ProcessorChainTest processorChainUnitTest;
163 
164 } // namespace juce::dsp
void expectEquals(ValueType actual, ValueType expected, String failureMessage=String())
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
void expect(bool testResult, const String &failureMessage=String())
AudioBlock &JUCE_VECTOR_CALLTYPE multiplyBy(NumericType value) noexcept
void prepare(const ProcessSpec &spec)
void process(const ProcessContext &context) noexcept
AudioBlockType & getOutputBlock() const noexcept