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.

138 lines
5.5KB

  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 const auto& get (const ProcessorType& a) noexcept { return AccessHelper<arg - 1>::get (a.processors); }
  33. template <typename ProcessorType>
  34. static void setBypassed (ProcessorType& a, bool bypassed) { AccessHelper<arg - 1>::setBypassed (a.processors, bypassed); }
  35. };
  36. template <>
  37. struct AccessHelper<0>
  38. {
  39. template <typename ProcessorType>
  40. static auto& get (ProcessorType& a) noexcept { return a.getProcessor(); }
  41. template <typename ProcessorType>
  42. static const auto& get (const ProcessorType& a) noexcept { return a.getProcessor(); }
  43. template <typename ProcessorType>
  44. static void setBypassed (ProcessorType& a, bool bypassed) { a.isBypassed = bypassed; }
  45. };
  46. //==============================================================================
  47. template <bool isFirst, typename Processor, typename Subclass>
  48. struct ChainElement
  49. {
  50. void prepare (const ProcessSpec& spec)
  51. {
  52. processor.prepare (spec);
  53. }
  54. template <typename ProcessContext>
  55. void process (const ProcessContext& context) noexcept
  56. {
  57. if (context.usesSeparateInputAndOutputBlocks() && ! isFirst)
  58. {
  59. jassert (context.getOutputBlock().getNumChannels() == context.getInputBlock().getNumChannels());
  60. ProcessContextReplacing<typename ProcessContext::SampleType> replacingContext (context.getOutputBlock());
  61. replacingContext.isBypassed = (isBypassed || context.isBypassed);
  62. processor.process (replacingContext);
  63. }
  64. else
  65. {
  66. ProcessContext contextCopy (context);
  67. contextCopy.isBypassed = (isBypassed || context.isBypassed);
  68. processor.process (contextCopy);
  69. }
  70. }
  71. void reset()
  72. {
  73. processor.reset();
  74. }
  75. bool isBypassed = false;
  76. Processor processor;
  77. Processor& getProcessor() noexcept { return processor; }
  78. const Processor& getProcessor() const noexcept { return processor; }
  79. Subclass& getThis() noexcept { return *static_cast<Subclass*> (this); }
  80. const Subclass& getThis() const noexcept { return *static_cast<const Subclass*> (this); }
  81. template <int arg> auto& get() noexcept { return AccessHelper<arg>::get (getThis()); }
  82. template <int arg> const auto& get() const noexcept { return AccessHelper<arg>::get (getThis()); }
  83. template <int arg> void setBypassed (bool bypassed) noexcept { AccessHelper<arg>::setBypassed (getThis(), bypassed); }
  84. };
  85. //==============================================================================
  86. template <bool isFirst, typename FirstProcessor, typename... SubsequentProcessors>
  87. struct ChainBase : public ChainElement<isFirst, FirstProcessor, ChainBase<isFirst, FirstProcessor, SubsequentProcessors...>>
  88. {
  89. using Base = ChainElement<isFirst, FirstProcessor, ChainBase<isFirst, FirstProcessor, SubsequentProcessors...>>;
  90. template <typename ProcessContext>
  91. void process (const ProcessContext& context) noexcept { Base::process (context); processors.process (context); }
  92. void prepare (const ProcessSpec& spec) { Base::prepare (spec); processors.prepare (spec); }
  93. void reset() { Base::reset(); processors.reset(); }
  94. ChainBase<false, SubsequentProcessors...> processors;
  95. };
  96. template <bool isFirst, typename ProcessorType>
  97. struct ChainBase<isFirst, ProcessorType> : public ChainElement<isFirst, ProcessorType, ChainBase<isFirst, ProcessorType>> {};
  98. }
  99. #endif
  100. //==============================================================================
  101. /**
  102. This variadically-templated class lets you join together any number of processor
  103. classes into a single processor which will call process() on them all in sequence.
  104. */
  105. template <typename... Processors>
  106. using ProcessorChain = ProcessorHelpers::ChainBase<true, Processors...>;
  107. } // namespace dsp
  108. } // namespace juce