カテゴリー
C++ JUCE

Message Thread

他のプログラミング言語、フレームワークと同様に、UIに関わる変更は、message thread (main thread)で行われる必要があります。

特に、AudioParameterの変更(background threadで処理されるようです)をトリガーとしてUIに変更を加える場合は、juce::CallbackMessageクラスを使って処理をmessage threadにdispatchしないと上手く動作しなかったり、Pluginがクラッシュします。

class ModulesContainerComponent
{
public:
  ModulesContainerComponent()
  {} 
  // 省略
  
  void parameterChanged(const juce::String &parameterID, 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)
};