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.

129 lines
4.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. namespace dsp
  22. {
  23. #ifndef DOXYGEN
  24. namespace ProcessorHelpers // Internal helper classes used in building the ProcessorChain
  25. {
  26. template <int arg>
  27. struct AccessHelper
  28. {
  29. template <typename ProcessorType>
  30. static auto& get (ProcessorType& a) noexcept { return AccessHelper<arg - 1>::get (a.processors); }
  31. template <typename ProcessorType>
  32. static void setBypassed (ProcessorType& a, bool bypassed) { AccessHelper<arg - 1>::setBypassed (a.processors, bypassed); }
  33. };
  34. template <>
  35. struct AccessHelper<0>
  36. {
  37. template <typename ProcessorType>
  38. static auto& get (ProcessorType& a) noexcept { return a.getProcessor(); }
  39. template <typename ProcessorType>
  40. static void setBypassed (ProcessorType& a, bool bypassed) { a.isBypassed = bypassed; }
  41. };
  42. //==============================================================================
  43. template <bool isFirst, typename Processor, typename Subclass>
  44. struct ChainElement
  45. {
  46. void prepare (const ProcessSpec& spec)
  47. {
  48. processor.prepare (spec);
  49. }
  50. template <typename ProcessContext>
  51. void process (const ProcessContext& context) noexcept
  52. {
  53. if (context.usesSeparateInputAndOutputBlocks() && ! isFirst)
  54. {
  55. jassert (context.getOutputBlock().getNumChannels() == context.getInputBlock().getNumChannels());
  56. ProcessContextReplacing<typename ProcessContext::SampleType> replacingContext (context.getOutputBlock());
  57. replacingContext.isBypassed = (isBypassed || context.isBypassed);
  58. processor.process (replacingContext);
  59. }
  60. else
  61. {
  62. ProcessContext contextCopy (context);
  63. contextCopy.isBypassed = (isBypassed || context.isBypassed);
  64. processor.process (contextCopy);
  65. }
  66. }
  67. void reset()
  68. {
  69. processor.reset();
  70. }
  71. bool isBypassed = false;
  72. Processor processor;
  73. Processor& getProcessor() noexcept { return processor; }
  74. Subclass& getThis() noexcept { return *static_cast<Subclass*> (this); }
  75. template <int arg> auto& get() noexcept { return AccessHelper<arg>::get (getThis()); }
  76. template <int arg> void setBypassed (bool bypassed) noexcept { AccessHelper<arg>::setBypassed (getThis(), bypassed); }
  77. };
  78. //==============================================================================
  79. template <bool isFirst, typename FirstProcessor, typename... SubsequentProcessors>
  80. struct ChainBase : public ChainElement<isFirst, FirstProcessor, ChainBase<isFirst, FirstProcessor, SubsequentProcessors...>>
  81. {
  82. using Base = ChainElement<isFirst, FirstProcessor, ChainBase<isFirst, FirstProcessor, SubsequentProcessors...>>;
  83. template <typename ProcessContext>
  84. void process (const ProcessContext& context) noexcept { Base::process (context); processors.process (context); }
  85. void prepare (const ProcessSpec& spec) { Base::prepare (spec); processors.prepare (spec); }
  86. void reset() { Base::reset(); processors.reset(); }
  87. ChainBase<false, SubsequentProcessors...> processors;
  88. };
  89. template <bool isFirst, typename ProcessorType>
  90. struct ChainBase<isFirst, ProcessorType> : public ChainElement<isFirst, ProcessorType, ChainBase<isFirst, ProcessorType>> {};
  91. }
  92. #endif
  93. //==============================================================================
  94. /**
  95. This variadically-templated class lets you join together any number of processor
  96. classes into a single processor which will call process() on them all in sequence.
  97. */
  98. template <typename... Processors>
  99. using ProcessorChain = ProcessorHelpers::ChainBase<true, Processors...>;
  100. } // namespace dsp
  101. } // namespace juce