Plugin loaded with no state in FL 21

I have to preface this by saying that this is not only my first project in JUCE, but my first in C++ as well.

I’m working in VS on Win11.
The plugin I made works fine in AudioPluginHost, but not in FL Studio - I realize this may then be a problem with FL, but I think it’s more likely I did something wrong.

What happens is:
You can load the plugin, play around with it, every thing is fine. But when you save the project and reopen it, things get weird:

  • IF the plugin’s editor is open on load (saved with editor open), the plugin does not produce output until you close and re-open the editor.
  • IF the editor is closed on load, the plugin does not produce any output until you open the editor, close it and open it AGAIN.

… both of these things happen ALMOST all the time, but rarely it just works when loading. Also I’m certain that there is no output because my Gains are initialized with a default of 0.
The UI shows the correct settings directly after loading.

My guess is that it’s tied to loading the state (FL weirdly calls getState before setState, see here). I’m doing it like this:

void GnomeDistortAudioProcessor::getStateInformation(juce::MemoryBlock& destData) {
    juce::MemoryOutputStream mos(destData, true);
    apvts.state.writeToStream(mos);
}

void GnomeDistortAudioProcessor::setStateInformation(const void* data, int sizeInBytes) {
    auto state = juce::ValueTree::readFromData(data, sizeInBytes);
    if (state.isValid()) {
        apvts.replaceState(state);
        updateSettings(getChainSettings(apvts), getSampleRate(), leftChain, rightChain);
    }
}

updateSettings is a helper function defined as

...
settings.WaveShapeAmount = apvts.getRawParameterValue("WaveShapeAmount")->load();
settings.WaveShapeFunction = static_cast<WaveShaperFunction>(apvts.getRawParameterValue("WaveShapeFunction")->load());
settings.PostGain = apvts.getRawParameterValue("PostGain")->load();
settings.Mix = apvts.getRawParameterValue("DryWet")->load();
...

With

struct ChainSettings {
    float LoCutFreq{ 0 }, PeakFreq{ 0 }, PeakGain{ 0 }, PeakQ{ 0 }, HiCutFreq{ 0 }, PreGain{ 0 }, Bias{ 0 }, WaveShapeAmount{ 0 }, PostGain{ 0 }, Mix{ 0 };
    int LoCutSlope{ FilterSlope::Slope12 }, HiCutSlope{ FilterSlope::Slope12 }, WaveShapeFunction{ WaveShaperFunction::HardClip };
};

and FilterSlope, WaveShaperFunction as basic enums.

I can see from my logs, that FL calls getState and then setState. In the getState, all values are the default ones I specified when I generate the ValueTree (so not the struct defaults) and the subsequent setState has the values that should have been loaded (so that’s right at least).
But it seems to be using the default values in the “ChainSettingsstruct. I should also mention that the correct parameters are shown in the UI immediately, even before the re-opening that makes the Processor load its parameters.

One other thing I’ve noticed: when you re-open the interface and the parameters are right and everything starts working - my Choice-type parameters do NOT get loaded correctly. But this happens in AudioPluginHost as well so it’s more likely I screwed up - interestingly however, on the first load in FL, before the plugin starts working again, the Choices get loaded correctly - only when reopening (so that it actually works) are they reset to standard.

Now sadly, I can’t attach a debugger to FL, most likely because they want to protect their software - whenever I want to attach, it immediately closes. Whether I go via Debug->Attach or the Project Properties and Debug Command, FL closes immediately as VS tries to attach to it.
I’ve resorted to writing to a text file as some kind of DBG output log.

This must be a total newbie question, but I’ve absolutely run into a wall here, with my very limited knowledge of JUCE and C++ in general.

I’ve been logging the way in which FL calls some functions with some select parameter’s values logged as well (Gain is in dB):

createParameterLayout
getStateInformation
got state
LoCutFreq 20 - PreGain 0 - WaveShapeAmt 0 - WaveShapeFunc 0
editor costructor 
setStateInformation
LoCutFreq 357 - PreGain 19 - WaveShapeAmt 0.99 - WaveShapeFunc 3
prepareToPlay
LoCutFreq 357 - PreGain 19 - WaveShapeAmt 0.99 - WaveShapeFunc 3
prepareToPlay
LoCutFreq 357 - PreGain 19 - WaveShapeAmt 0.99 - WaveShapeFunc 3
prepareToPlay
LoCutFreq 357 - PreGain 19 - WaveShapeAmt 0.99 - WaveShapeFunc 3

I don’t know why it calls prepareToPlaymultiple times.
Also, even though the editor is constructed before setting the state, it shown the correct values in all regards (including the Choice parameters).
When I re-open the GUI to make things work, it only calls editor constructor again, with no further reading or setting of states.

I have also tried to use the generic editor; it’s even worse: it behaves the same after startup BUT does not even start to work after re-opening the editor.

I feel incredibly stupid.

I had a Gain processor that was not properly fed a gain value unless you set the “WaveshaperFunction” to it’s default value. Since Gains get initialized with a default (linear) gain of 0, it produced no sound.

However, re-opening the editor in FL re-set all Choice type parameters to their defaults and that circumvented that issue.

Now there only remains the question why FL resets those parameters when opening the editor.
That also was my stupidity at play. I falsely assumed that the editor’s constructor would be called once, which is not the case. It gets called every time the GUI is opened. So when I set the ComboBox’s default value as WaveshapeSelect.setSelectedId(1); (0 being “nothing selected”), I overruled the actual value every time. The correct approach is WaveshapeSelect.setSelectedId(audioProcessor.apvts.getRawParameterValue("WaveShapeFunction")->load() + 1);.

So, I had to bugs that partly mitigated each other. I hope someone might find this helpful in the future.