In an effort to reduce boilerplate code in my plug-in projects, I’ve been playing with creating a base class for plug-in Processors. And it works fine for handling simple stuff like acceptsMidi(), producesMidi(), isMidiEffect(), etc.
However, I also wanted this ProcessorBase class to handle implementing getStateInformation and setStateInformation, for which it would need access to the project’s AudioProcessorValueTreeState (APVTS). And that got trickier.
I tried having the APVTS be a member of the ProcessorBase class, but although it builds OK, that doesn’t work for DAWs to see the parameters. (In the APVTS constructor you have to provide a processorToConnectTo argument, and it probably doesn’t work to have that be a different type than what you initially passed back to a DAW in the createPluginFilter method… I didn’t fully dig through the layers to find the source of the conflict, just guessing there.)
So another idea I had was to have the derived Processor class own the APVTS member, but then have the ProcessorBase class own an AudioProcessorValueTreeState pointer. In the derived Processor’s constructor, it could set that pointer to its own APVTS member.
As a partial example of this approach:
BaseProcessor.h would include
protected:
AudioProcessorValueTreeState* apvtsPtr;
public:
void getStateInformation (juce::MemoryBlock& destData) override
{
jassert (apvtsPtr != nullptr);
auto state = apvtsPtr->copyState();
std::unique_ptr<juce::XmlElement> xml (state.createXml());
copyXmlToBinary (*xml, destData);
}
And the derived ProjectProcessor.h would include
AudioProcessorValueTreeState apvts;
// in constructor:
apvtsPtr = &apvts;
// in destructor:
apvtsPtr = nullptr;
So if was setting up a new project, and forgot to set the apvtsPtr in the ProjectProcessor’s constructor, then getStateInformation would assert and let me know. Or, if I wanted to implement something different for getStateInformation for a particular project, then I override it in the derived processor, and that apvtsPtr just sits unused in the base processor (no harm done).
OK, so, questions:
- Does a Base class owning a pointer to a Derived class member inherently have a bad code smell?
- Is there a more common or convenient CPP idiom for doing this?
