Hey, don’t apologise! Template meta-programming is a bit like quantum mechanics - if you claim to understand it, you clearly don’t.
That’s exactly it. If you look at the OverdriveDemo.cpp and more specifically the DCFilter inside that demo, you can see how the IIR::Filter is duplicated. This duplicated filter is then used in the ProcessorChain.
Yes, I was staring at it, but it confuses me. Can the ProcessorChain actually chain mono and Duplicators after each other?
Or is a Processor already able to process multiple channels, and the Duplicator is only needed, if you need different states for each channel? - It annoys me, that I can only guess instead of understanding it.
I tired this setup now, wrapping several ProcessorDuplicators into one ProcessorChain, but fun fact, I can’t hear anything:
Yes your approach looks good except for a single line. You need to dereference the filter state, as each mono filter has a pointer to the state of the ProcessorDuplicator:
In general, what may be confusing is that some filters in the dsp module are multi-channel and some are only mono and need to be duplicated (like IIRFilter and FIRFilter).
Thank you, that did the trick!
I don’t understand the concept though, because out of curiosity I tried:
filter.get<0> ()->state = *loCoeff;
but that wouldn’t compile, so it is not the same dereferencing. I think I need more input on that…
Ah, that makes sense… would you or someone of your team mind to flesh out the documentation, so it could be looked up, which need a separate state, and which don’t?
(well, some are obvious, but would be good to have it written somewhere)
Is there no surefire way to update the states of the current processors that are held in ProcessDuplicator?
It seems like prepare() only updates the states if they happen to be instantiated (depending on the ProcessSpec channel count).
Right now in my prepareToPlay() I have to fully re-instantiate my ProcessDuplicator object to make sure the filter coefficients update (eg because of a possible new sample rate), or call prepare() with channel count = 0, then with the real channel count.
void ProcessorDuplicator::prepare (const ProcessSpec& spec)
{
processors.removeRange ((int) spec.numChannels, processors.size());
while (static_cast<size_t> (processors.size()) < spec.numChannels)
processors.add (new MonoProcessorType (state));
auto monoSpec = spec;
monoSpec.numChannels = 1;
for (auto* p : processors)
p->prepare (monoSpec);
}
Ideally I would like my code to read (like in some of the demos):