# ProcessorChain with dynamic Processor

**URL:** <https://forum.juce.com/t/processorchain-with-dynamic-processor/58158>\
**Category:** General JUCE discussion\
**Created:** [October 4, 2023, 1:03pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158 "2023-10-04T13:03:41Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![dhng22](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dhng22/32/16493_2.png) [@dhng22](https://forum.juce.com/u/dhng22)\
**Post date:** [October 4, 2023, 1:03pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/1 "2023-10-04T13:03:41Z")

</div>

Hi, I’m playing aroung with **FilterDesign::designIIRHighpassHighOrderButterworthMethod** , I want to set the \ ***processorChain.get\<\>.state** with the \***coefficient.getObjectPointer(i)**.

However, i realized that the **getObjectPointer(i)** with i can be more than 0, which will return a dynamically number of coefficients, depend on the **order** i put.

But i can only initialize **ProcessorChain** with defined **Processors** (eg: dsp::ProcessorChain\<Duplicator\>). The processor chain also has no method to add processor dynamically, so I’m wondering if I can just define a lot of Duplicator (eg: dsp::ProcessorChain\<Duplicator,Duplicator,Duplicator,Duplicator\>) so that i can set the state if i want, is that ok? Thanks for any help.

---

<div class="post-metadata">

**Author:** ![PluginPenguin](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/pluginpenguin/32/10203_2.png) [@PluginPenguin](https://forum.juce.com/u/PluginPenguin)\
**Post date:** [October 4, 2023, 1:28pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/2 "2023-10-04T13:28:34Z")

</div>

The processor duplicator is meant to transform a single-channel processor into a multichannel one, so that’s not what you need here. We have a helper class like this that can be used for that exact purpose:

```auto
/** A chain of a dynamic number of processors of the same type. Use init to set the numbers of processors you want to
    chain and to initialize them with constructor arguments
 */
template <typename ProcessorType>
class DynamicProcessorChain
{
public:
    /** Initializes this chain to create a given number of chained processors. ProcessorType
        needs a default constructor to call this constructor
     */
    void init (size_t numProcessors)
    {
        processors.clear();
        processors.reserve (numProcessors);

        for (size_t i = 0; i < numProcessors; ++i)
            processors.push_back (std::make_unique<ProcessorType>());
    }

    /** Initializes this chain to create a given number of chained processors, each one with the same constructor
        arguments
     */
    template <typename... ProcessorConstructorArgs>
    void init (size_t numProcessors, ProcessorConstructorArgs&&... args)
    {
        processors.clear();
        processors.reserve (numProcessors);

        for (size_t i = 0; i < numProcessors; ++i)
            processors.push_back (std::make_unique<ProcessorType> (std::forward<ProcessorConstructorArgs> (args)...));
    }

    /** Initializes this chain to create a given number of chained processors, each one constructed with the
        corresponding constructor element from the Initializers, which can be any sort of array, vector or initializer
        list that has a begin, end and size method. The number of processors to create is derived from the number of
        initializers passed
     */
    template <typename Initializers>
    void init (const Initializers& initializers)
    {
        processors.clear();
        processors.reserve (initializers.size());

        for (auto initializer = initializers.begin(); initializer != initializers.end(); ++initializer)
            processors.push_back (std::make_unique<ProcessorType> (*initializer));
    }

    /** Get a reference to the processor at that index */
    ProcessorType& get (size_t index)
    {
        return *processors[index];
    }

    /** Get a reference to the processor at that index */
    const ProcessorType& get (size_t index) const
    {
        return *processors[index];
    }

    /** Prepares all processors in the chain */
    void prepare (const juce::dsp::ProcessSpec& spec)
    {
        for (auto& processor : processors)
            processor->prepare (spec);
    }

    /** Resets all processors in the chain */
    void reset()
    {
        for (auto& processor : processors)
            processor->reset();
    }

    template <class SampleType>
    void process (const juce::dsp::ProcessContextReplacing<SampleType>& context)
    {
        if (context.isBypassed)
            return;

        for (auto& processor : processors)
            processor->process (context);
    }

    /** Returns a begin iterator to allow a range-based loop over all processors */
    auto begin() { return processors.begin(); }

    /** Returns an end iterator to allow a range-based loop over all processors */
    auto end() { return processors.end(); }

private:
    std::vector<std::unique_ptr<ProcessorType>> processors;
};

```

Example usage in the context of a `juce::dsp::ProcesorChain`looks like this:

```auto
// Somewhere in the member section of your AudioProcessor
using MyChain = juce::dsp::ProcessorChain<juce::dsp::Gain<float>,
                                          DynamicChain<juce::dsp::IIR::Filter<float>>,
                                          juce::dsp::Gain<float>>;

MyChain myChain;

// Somewhere in your AudioProcessor implementation
void MyAudioProcessor::prepareToPlay	(double sampleRate, int maximumExpectedSamplesPerBlock) override
{
    juce::dsp::ProcessSpec spec { .sampleRate = sampleRate,
                                  .maximumBlockSize = static_cast<juce::uint32> (maximumExpectedSamplesPerBlock),
                                  .numChannels = static_cast<juce::uint32> (getMainBusNumInputChannels()) };

    // Using a structured binding for a more expressive syntax than e.g. myChain.get<1>()
    auto& [preGain, dynamicIIRChain, postGain] = myChain;

    // Expecting myCutoffFreq and myOrder to be some constants for your filter design declared somewhere
    dynamicIIRChain.init (juce::dsp::FilterDesign::designIIRHighpassHighOrderButterworthMethod (myCutoffFreq, sampleRate, myOrder));

    myChain.prepare (spec);
}

```

Hope that helps. Code is untested and should primarily illustrate the concept 😉

---

<div class="post-metadata">

**Author:** ![dhng22](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dhng22/32/16493_2.png) [@dhng22](https://forum.juce.com/u/dhng22)\
**Post date:** [October 4, 2023, 1:34pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/3 "2023-10-04T13:34:30Z")

</div>

Much love❤️ I’ll test it out

---

<div class="post-metadata">

**Author:** ![dhng22](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dhng22/32/16493_2.png) [@dhng22](https://forum.juce.com/u/dhng22)\
**Post date:** [October 4, 2023, 5:08pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/4 "2023-10-04T17:08:59Z")

</div>

@PluginPenguin Is there a way to combine two filters like this:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/juce/original/3X/d/0/d0d248141eb7e935aa99cf017230c7764b52dce5.png)  
Or i have to make it into two dynamicChains, and after calling **prepare()**, i only have to call **process()** right? Thanks

---

<div class="post-metadata">

**Author:** ![daniel](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/daniel/32/790_2.png) [@daniel](https://forum.juce.com/u/daniel)\
**Post date:** [October 4, 2023, 5:27pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/5 "2023-10-04T17:27:32Z")

</div>

While it is nice that this approach retains the API of ProcessorBase/ProcessorChain, the benefit of the ProcessorChain was to be constructed at compile time to allow as much optiisation as possible.  
This advantage is not the case with this setup.

Still better than AudioProcessorGraph though 😉

---

<div class="post-metadata">

**Author:** ![dhng22](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dhng22/32/16493_2.png) [@dhng22](https://forum.juce.com/u/dhng22)\
**Post date:** [October 4, 2023, 5:58pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/6 "2023-10-04T17:58:55Z")

</div>

@PluginPenguin I get AssertionFailure for not using ProcessorDuplicator:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/juce/original/3X/a/0/a0ee0be341a414ae4b4343e4e46c0b68c0ea9454.png)

---

<div class="post-metadata">

**Author:** ![PluginPenguin](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/pluginpenguin/32/10203_2.png) [@PluginPenguin](https://forum.juce.com/u/PluginPenguin)\
**Post date:** [October 4, 2023, 9:28pm UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/7 "2023-10-04T21:28:56Z")

</div>

If you want to chain two such filters, you should create a processor chain with to such dynamic chains, one for the high pass and one for the low pass, like

```auto
using HigherOrderIIR = DynamicProcessorChain<juce::dsp::IIR::Filter<float>>
using MyChain = juce::dsp::ProcessorChain< HigherOrderIIR, HigherOrderIIR>;

MyChain myChain;

void prepareToPlay	(double sampleRate, int maximumExpectedSamplesPerBlock) override
{
    auto& [highPassFilter, lowPassFilter] = myChain;

    highPassFilter.init (juce::dsp::FilterDesign::designIIRHighpassHighOrderButterworthMethod (hfrequency, sampleRate, horder);
    lowPassFilter.init ((juce::dsp::FilterDesign::designIIRHighpassHighOrderButterworthMethod (lfrequency, sampleRate, lorder);

    myChain.prepare (spec);
}

```

Note that I called `prepare` on the outer `juce::dsp::ProcessorChain` instance and so you have to call process on the outer chain, this will invoke them in the right order for all sub-processors. This is one of the core concepts of a processor chain 😉

One more thing, I noted that you passed different sample rate variables to your highpass and lowpass design functions, which seems like a mistake. You should pass the same sample rate to all filter design functions and the process spec passed to `prepare`.

> [@dhng22](#):
>
> I get AssertionFailure for not using ProcessorDuplicator

This is because the juce filters are only intended for single channel usage. You seem to use them in a multi channel context. You have to wrap the filter in a a `juce::dsp::ProcessorDuplicator` as the comment says:

```auto
using HigherOrderIIR = DynamicProcessorChain<juce::dsp::ProcessorDuplicator<juce::dsp::IIR::Filter<float>, juce::dsp::IIR::Coefficients<float>>>
using MyChain = juce::dsp::ProcessorChain< HigherOrderIIR, HigherOrderIIR>;

MyChain myChain;

```

> [@daniel](#):
>
> While it is nice that this approach retains the API of ProcessorBase/ProcessorChain, the benefit of the ProcessorChain was to be constructed at compile time to allow as much optiisation as possible.  
> This advantage is not the case with this setup.
> 
> Still better than AudioProcessorGraph though 😉

I agree to some extent – maximum optimization is one point that makes the processor chain approach great, but I also like how descriptive the API is when it comes to declaring chains of processors as types.  
Still, if you are aiming for maximum optimization, it’s not too hard to build a IIR filter chain that takes the filter order as template parameter and keeps a compile time static sized `std::array` of filter instances.

---

<div class="post-metadata">

**Author:** ![dhng22](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/dhng22/32/16493_2.png) [@dhng22](https://forum.juce.com/u/dhng22)\
**Post date:** [October 5, 2023, 3:17am UTC](https://forum.juce.com/t/processorchain-with-dynamic-processor/58158/8 "2023-10-05T03:17:35Z")

</div>

It worked!, thanks a lot
