Hey all,
I’m relatively new to JUCE (<1 year) but I’ve been building a plugin and I think it’s coming along really nicely. I tried building a custom slider, and it works in every aspect except for when the GUI is closed and reopened again. All the values on the slider reset to their default values, which is then sent onto the processor. This doesn’t happen for any of my other sliders, as I’m using the APVTS to maintain consistency across their values.
I’ve spent hours debugging, trying to find where the switch occurs, and I just can’t figure it out for the life of me. I’m using REAPER as my debug environment. Here’s what happens:
- I open up the plugin and change the value on the slider.
- I close the GUI
- I open up the GUI again, to which Visual Studio executes a breakpoint and all processing stops.
- I check all the values for the slider, which remain correct even when the editor is reinstantiated in juce_audio_client_vst3.cpp.
- I step ahead until I reach a screen telling me that the debugger can’t open reaper.pdb. The values are still consistent but I can’t use the debugger to go forward anymore
- I go back and add a conditional breakpoint to the slider’s value and hit continue to find where it changes
- The slider’s value changes back to it’s default, and the call stack just consists of internal message broadcasting stemming from reaper.pdb except for when it hits .onValueChange() attachment class.
I have no idea why it’s switching back to its default here. The slider is part of a separate component, but I’m instantiating it the same way I do all my other sliders, whose values remain consistent. The slider appropriately changes the values I want it to change using the APVTS. Here’s the code for the attachment class I made:
#include <JuceHeader.h>
class TwoValueSliderAttachment : AudioProcessorValueTreeState::Listener
{
public:
TwoValueSliderAttachment(AudioProcessorValueTreeState& apvts,
const String& minParamID,
const String& maxParamID,
Slider& slider)
: apvtsRef(apvts), minParamID(minParamID), maxParamID(maxParamID), sliderRef(slider)
{
jassert(slider.getSliderStyle() == Slider::SliderStyle::TwoValueHorizontal);
minParam = apvtsRef.getParameter(minParamID);
maxParam = apvtsRef.getParameter(maxParamID);
jassert(minParam && maxParam);
updating = true;
//Set Initial Values
sliderRef.setMinAndMaxValues(
minParam->convertFrom0to1(minParam->getValue()),
maxParam->convertFrom0to1(maxParam->getValue()),
dontSendNotification);
updating = false;
/* Sync Slider to parameters*/
this->sliderRef.onValueChange = [this]() {
if (this->updating) return;
this->updating = true;
if (this->minParam != nullptr)
this->minParam->setValueNotifyingHost(this->minParam->convertTo0to1((float)this->sliderRef.getMinValue()));
if (this->maxParam != nullptr)
this->maxParam->setValueNotifyingHost(this->maxParam->convertTo0to1((float)this->sliderRef.getMaxValue()));
this->updating = false;
};
DBG("Slider triggered: " << slider.getMinValue() << " " << slider.getMaxValue());
apvtsRef.addParameterListener(minParamID, this);
apvtsRef.addParameterListener(maxParamID, this);
}
~TwoValueSliderAttachment() {
apvtsRef.removeParameterListener(minParamID, this);
apvtsRef.removeParameterListener(maxParamID, this);
}
void parameterChanged(const juce::String& parameterID, float newValue) override
{
if (updating) return;
updating = true;
if (parameterID == minParamID)
sliderRef.setMinValue(newValue, juce::dontSendNotification);
else if (parameterID == maxParamID)
sliderRef.setMaxValue(newValue, juce::dontSendNotification);
updating = false;
}
private:
AudioProcessorValueTreeState& apvtsRef;
String minParamID;
String maxParamID;
Slider& sliderRef;
RangedAudioParameter* minParam = nullptr;
RangedAudioParameter* maxParam = nullptr;
bool updating = false;
};