First of all: there is a great article on StackOverflow How do I ask a good question? - Help Center - Stack Overflow. Please take your time and read it so we get all the information we need from the start without having to ask for it.
Second: please share your entire unit (header and implementation)
Third: I’m not entirely sure what your problem is, so I’m taking a shot in the dark right now, but here is how the parameter attachments in JUCE are designed.
The parameter attachments are basically a subclass for two listeners. One listener for the controller interaction from a user and one listener for the parameter in case the audio engine changes it (e.g. via midi automations) or, if its not an audio parameter, a different UI component or maybe a network connection etc. When you want to attach your control / component to a parameter of some sort, you create a new parameter attachment and provide the UI control and a reference to the parameter. I mostly see those parameter attachments stored in a unique pointer inside the parent component.
So imagine you have a box with four sliders, this class Box : juce::Component
would have the following member variables: four jute::Slider
and four std::unique_ptr<ParameterAttachment>
. In the ctor you set up the sliders accordingly (maybe disable mouse wheel interaction etc.) and create the parameter attachments.
The parameter attachment should (in its ctor) take care of setting the UI control to the current value of the parameter (e.g. place the slider to the value 5 if that’s the value of the audio parameter). When setting the value for the UI component, make sure to pass dontSendNotification
to prevent your attachment from triggering a change while just initially aligning the control.
Also make sure to unregister the listeners in the dtor to avoid dangling listener pointers. This way, when your Box
goes out of scope and destroys the unique pointers, everything will be cleaned up nicely.
And last but not least: here is a parameter attachment I’ve written recently to attach a Slider
control to a property of my SharedSoundSettings
(the property being defined as a template parameter).
On a side note: the parameter attachment uses AsyncUpdater
to suspend the control update (after the parameter changed by some other source) to the next iteration of the message thread loop. This was necessary in my case but nothing you should do if you don’t have to.
template <SoundProperty::Property property>
class SoundSettingSliderAttachment
: private Slider::Listener,
private SoundProperty::Listener<property>,
private juce::AsyncUpdater
{
public:
SoundSettingSliderAttachment(Slider& slider, const SharedSoundSettings& sound, UndoManager& undoManager);
~SoundSettingSliderAttachment();
private:
void sliderDragStarted(Slider*) override;
void sliderValueChanged(Slider*) override;
void propertyChanged() override;
void handleAsyncUpdate() override;
Slider& slider;
SharedSoundSettings sound;
UndoManager& undoManager;
};
#define DECLARE_SoundSettingSliderAttachment(returntype) \
template <SoundProperty::Property property> \
returntype SoundSettingSliderAttachment<property>::
DECLARE_SoundSettingSliderAttachment() SoundSettingSliderAttachment(Slider& slider, const SharedSoundSettings& s, UndoManager& undo)
: slider(slider),
sound(s),
undoManager(undo)
{
slider.addListener(this);
sound.addPropertyListener(*this);
slider.setValue(sound.getProperty<property>(), dontSendNotification);
}
DECLARE_SoundSettingSliderAttachment(void) sliderDragStarted(Slider*)
{
undoManager.beginNewTransaction();
}
DECLARE_SoundSettingSliderAttachment(void) sliderValueChanged(Slider*)
{
sound.setProperty<property>(slider.getValue(), &undoManager);
}
DECLARE_SoundSettingSliderAttachment(void) propertyChanged()
{
triggerAsyncUpdate();
}
DECLARE_SoundSettingSliderAttachment(void) handleAsyncUpdate()
{
slider.setValue(sound.getProperty<property>(), dontSendNotification);
}
DECLARE_SoundSettingSliderAttachment() ~SoundSettingSliderAttachment() // TODO: Bring under test
{
slider.removeListener(this);
}