他のプログラミング言語、フレームワークと同様に、UIに関わる変更は、message thread (main thread)で行われる必要があります。
特に、AudioParameterの変更(background threadで処理されるようです)をトリガーとしてUIに変更を加える場合は、juce::CallbackMessageクラスを使って処理をmessage threadにdispatchしないと上手く動作しなかったり、Pluginがクラッシュします。
class ModulesContainerComponent
{
public:
ModulesContainerComponent()
{}
// 省略
void parameterChanged(const juce::String ¶meterID, float newValue) override {
// dispatching to the message thread
(new ResizeByAudioParameterCallback(*this))->post();
}
void updateControlBound() {
lowerBound = (int)*valueTreeState.getRawParameterValue(LOWER_CONTROL_BOUND_ID);
upperBound = (int)*valueTreeState.getRawParameterValue(UPPER_CONTROL_BOUND_ID);
}
void rebuild() {
updateControlBound();
int moduleCount = upperBound - lowerBound;
// clear modules and rebuild
modules.clear();
if(moduleCount > 0) {
for (int i = lowerBound; i <= upperBound; i++) {
addAndMakeVisible(modules.add(std::make_unique<PerKeyModuleComponent>(i, valueTreeState, presetManager, lookAndFeel, voicings, dirtyVoices, colorHandler, showVoicingConfig)));
}
}
repaint();
resized();
}
// for dispatching to the message thread
class ResizeByAudioParameterCallback : public juce::CallbackMessage
{
public:
ResizeByAudioParameterCallback(ModulesContainerComponent& o)
: owner(o)
{
}
ModulesContainerComponent& owner;
void messageCallback() override {
owner.rebuild();
}
};
private:
// 省略
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ModulesContainerComponent)
};