Issues dereferencing a pointer in SliderAttachment

Hi everyone I’m totally new to audio programming and I’m getting started following a tutorial for a drive plugin that is a few years old, so things have changed a bit.

I’m stuck at a part where I need to link the sliders and knobs I’ve initialized to the audio processor value tree state (slider attachment).

The tutorial used scoped pointers which have since been deprecated and I was able to work out how to do it in the up to date framework except one thing, the compiler (I think) says I am dereferencing null pointers. Here are the snippets of code if you could help me out it’d be much appreciated.

Here is the error:

 error: no match for ‘operator=’ (operand types are ‘std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment>

from PluginEditor.h:

    std::unique_ptr<juce::Slider> driveKnob;
    std::unique_ptr<juce::Slider> preVolumeKnob;
    std::unique_ptr<juce::Slider> postVolumeKnob;
    std::unique_ptr<juce::Slider> lowCut;
    std::unique_ptr<juce::Slider> highCut;

    std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> driveAttachment;
    std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> preVolumeAttachment;
    std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> postVolumeAttachment;
    std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> lowCutAttachment;
    std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment> highCutAttachment;

from PluginEditor.cpp

driveKnob = std::make_unique<juce::Slider> ("Drive");
    addAndMakeVisible(driveKnob.get());
    driveKnob->setSliderStyle(juce::Slider::RotaryVerticalDrag);
    driveKnob->setTextBoxStyle(juce::Slider::NoTextBox, false, 100, 100);

    preVolumeKnob = std::make_unique<juce::Slider> ("Pre Volume");
    addAndMakeVisible(preVolumeKnob.get());
    preVolumeKnob->setSliderStyle(juce::Slider::LinearVertical);
    preVolumeKnob->setTextBoxStyle(juce::Slider::NoTextBox, false, 100, 100);

    postVolumeKnob = std::make_unique<juce::Slider> ("Post Volume");
    addAndMakeVisible(postVolumeKnob.get());
    postVolumeKnob->setSliderStyle(juce::Slider::LinearVertical);
    postVolumeKnob->setTextBoxStyle(juce::Slider::NoTextBox, false, 100, 100);

    lowCut = std::make_unique<juce::Slider> ("Low Cut");
    addAndMakeVisible(lowCut.get());
    lowCut->setSliderStyle(juce::Slider::RotaryVerticalDrag);
    lowCut->setTextBoxStyle(juce::Slider::NoTextBox, false, 100, 100);

    highCut = std::make_unique<juce::Slider> ("High Cut");
    addAndMakeVisible(highCut.get());
    highCut->setSliderStyle(juce::Slider::RotaryVerticalDrag);
    highCut->setTextBoxStyle(juce::Slider::NoTextBox, false, 100, 100);

    driveAttachment = new juce::AudioProcessorValueTreeState::SliderAttachment(p.getState(), "Drive", *driveKnob);
    preVolumeAttachment = new juce::AudioProcessorValueTreeState::SliderAttachment(p.getState(), "Pre Volume", *preVolumeKnob);
    postVolumeAttachment = new juce::AudioProcessorValueTreeState::SliderAttachment(p.getState(), "Post Volume", *postVolumeKnob);
    lowCutAttachment = new juce::AudioProcessorValueTreeState::SliderAttachment(p.getState(), "Low Cut", *lowCut);
    highCutAttachment = new juce::AudioProcessorValueTreeState::SliderAttachment(p.getState(), "High Cut", *highCut);

try replacing all the lines using new with

driveAttachment.reset(new juce::AudioProcessorValueTreeState::SliderAttachment(p.getState(), "Drive", *driveKnob));

Also, unless you have a reason to, you don’t need to be making these members pointers, just regular member variables are fine.

1 Like

Thank you! Worked great for compiling but now I’m getting a segmentation fault.

I tried commenting out the lines you gave me and it seems thats the issue:

   driveAttachment.reset(new juce::AudioProcessorValueTreeState::SliderAttachment(p.getState(), "drive", *driveKnob));

Do you think it could be the dereferencing of *driveKnob?

@Fandusss

Can you share the error you are getting specifically? Only thing I can think of is “drive” isn’t a parameter.

1 Like

The error comes from running the standalone plugin, and instead of opening just says “segmentation fault” in the terminal. When I comment out the SliderAttachment lines it goes away. Not sure what to think

put a breakpoint in your IDE on the first attachment and step through to see what specifically breaks?

Sorry, I’m a big time noob to this and I have no idea how to set up a debugger lol. I’m using vscode for this and I can’t make the launch.json file work since I need it set in the parent directory to get it to find all the files for debugging. Do you happen to know how I could set that up or should I switch to a recommended IDE

You need to learn how to use a debugger. What OS are you on?
Try with the default IDEs like VisualStudio on Windows and Xcode on MacOS first.

But there is a high chance, that the order of the members is reversed (destruction order).
The members are destroyed in the reverse order of appearance in the declaration. If you happen to declare the attachments before the sliders, they will be destroyed after the sliders are destroyed. So the attachments reference the deleted slider, which leads to a crash.

Two solutions: change the declaration to have the attachments declared after the sliders (preferred) or delete the attachments manually in the destructor by calling driveAttachment.reset(); and so on for all the attachments.

But in the long run it pays off to learn how to debug.

why are you using unique_ptr for all these things? it doesn’t look like stuff that is meant to be replaced at some point

I am trying to set up the debugger with VSCode since I’m on Linux but am running into issues with the dependencies, it says it can’t find this headerfile:

cannot open source file "juce_audio_basics/juce_audio_basics.h" (dependency of "JuceHeader.h")

but in my properties JSON file I have it set to the correct filepath:

"${workspaceFolder}/**",
"/home/wolf/vst/distort/JuceLibraryCode/**",
"/home/wolf/JUCE/modules/**"

I never used VScode, but maybe running in gdb would be an option to try?
When it crashes typing bt (for back trace) should show you the stack and give clues.

1 Like

Thanks for that, I am very new to C++ having only coded in Python before. Not sure how to debug compiled languages

Here what comes up when running gdb:

Thread 1 "Distort" received signal SIGSEGV, Segmentation fault.
0x00005555556fe25e in std::_Rb_tree<juce::StringRef, std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > >, std::_Select1st<std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > > >, juce::AudioProcessorValueTreeState::StringRefLessThan, std::allocator<std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > > > >::_M_begin (this=0x68) at /usr/include/c++/9/bits/stl_tree.h:756

and running backtrace shows this:

#0  0x00005555556fe25e in std::_Rb_tree<juce::StringRef, std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > >, std::_Select1st<std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > > >, juce::AudioProcessorValueTreeState::StringRefLessThan, std::allocator<std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > > > >::_M_begin (this=0x68) at /usr/include/c++/9/bits/stl_tree.h:756
#1  0x00005555556f019b in std::_Rb_tree<juce::StringRef, std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > >, std::_Select1st<std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > > >, juce::AudioProcessorValueTreeState::StringRefLessThan, std::allocator<std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > > > >::find (this=0x68, __k=...) at /usr/include/c++/9/bits/stl_tree.h:2575
#2  0x00005555556e2b77 in std::map<juce::StringRef, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> >, juce::AudioProcessorValueTreeState::StringRefLessThan, std::allocator<std::pair<juce::StringRef const, std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter, std::default_delete<juce::AudioProcessorValueTreeState::ParameterAdapter> > > > >::find (this=0x68, __x=...) at /usr/include/c++/9/bits/stl_map.h:1194
#3  0x00005555556be4c0 in juce::AudioProcessorValueTreeState::getParameterAdapter (this=0x0, paramID=...) at /home/wolf/JUCE/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:335
#4  0x00005555556be717 in juce::AudioProcessorValueTreeState::getParameter (this=0x0, paramID=...) at /home/wolf/JUCE/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:370
#5  0x00005555556e2d5b in juce::makeAttachment<juce::SliderParameterAttachment, juce::Slider> (stateToUse=..., parameterID=..., control=...)
    at /home/wolf/JUCE/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:481
#6  0x00005555556bf301 in juce::AudioProcessorValueTreeState::SliderAttachment::SliderAttachment (this=0x555555fcb120, stateToUse=..., parameterID=..., slider=...)
    at /home/wolf/JUCE/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:491
#7  0x0000555555607fbe in DistortAudioProcessorEditor::DistortAudioProcessorEditor (this=0x55555603cf30, p=...) at ../../Source/PluginEditor.cpp:43
#8  0x000055555560628d in DistortAudioProcessor::createEditor (this=0x55555601b110) at ../../Source/PluginProcessor.cpp:175
#9  0x00005555556a8eb0 in juce::AudioProcessor::createEditorIfNeeded (this=0x55555601b110) at /home/wolf/JUCE/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp:899
#10 0x00005555555f8ded in juce::StandaloneFilterWindow::MainContentComponent::MainContentComponent (this=0x5555560332a0, filterWindow=...)
    at /home/wolf/JUCE/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h:888
#11 0x00005555555f88b3 in juce::StandaloneFilterWindow::updateContent (this=0x55555600f980) at /home/wolf/JUCE/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h:853
#12 0x00005555555f8187 in juce::StandaloneFilterWindow::StandaloneFilterWindow (this=0x55555600f980, title=..., backgroundColour=..., settingsToUse=0x55555600e750, takeOwnershipOfSettings=false,
    preferredDefaultDeviceName=..., preferredSetupOptions=0x0, constrainToConfiguration=..., autoOpenMidiDevices=false)
    at /home/wolf/JUCE/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h:739
#13 0x00005555555fa6d5 in juce::StandaloneFilterApp::createWindow (this=0x555555ff45a0) at /home/wolf/JUCE/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp:92
#14 0x00005555555fa7b7 in juce::StandaloneFilterApp::initialise (this=0x555555ff45a0) at /home/wolf/JUCE/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterApp.cpp:98
#15 0x00005555558339b7 in juce::JUCEApplicationBase::initialiseApp (this=0x555555ff45a0) at /home/wolf/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:297
#16 0x00005555559fe50e in juce::JUCEApplication::initialiseApp (this=0x555555ff45a0) at /home/wolf/JUCE/modules/juce_gui_basics/application/juce_Application.cpp:92
#17 0x0000555555833840 in juce::JUCEApplicationBase::main () at /home/wolf/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:256
#18 0x0000555555833723 in juce::JUCEApplicationBase::main (argc=1, argv=0x7fffffffdeb8) at /home/wolf/JUCE/modules/juce_events/messages/juce_ApplicationBase.cpp:240
#19 0x00005555555f31f7 in main (argc=1, argv=0x7fffffffdeb8) at /home/wolf/JUCE/modules/juce_audio_plugin_client/juce_audio_plugin_client_Standalone.cpp:47

Sorry for the info dump, but I can’t really make sense of it so far. Does it give you any clues?

Also thanks for bearing with me I started this stuff yesterday

It’s been a while since I debugged with gdb, but let’s try:
The std is probably not giving much information, so we need to step out of the stack by three frames.
If you type up 3 you are placed in getParameterAdapter.
There are several commands to look around in the memory, like info locals etc. I would suggest to read a gdb tutorial at this point, they will likely explain it better than I can.

But again a lucky guess is, the AudioProcessorValueTreeState doesn’t exist at all? What does p.getState() return? Is that already created or is it a nullptr?

So I found a cheatcheet for gdb and ran what you said, but still can’t understand it. Here’s the output for up 3 and info locals as you said:

(gdb) up 3
#3  0x00005555556be4c0 in juce::AudioProcessorValueTreeState::getParameterAdapter (this=0x0, paramID=...) at /home/wolf/JUCE/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:335
335         auto it = adapterTable.find (paramID);
(gdb) info locals
it =
    {first = {text = {data = 0x5555556bf301 <juce::AudioProcessorValueTreeState::SliderAttachment::SliderAttachment(juce::AudioProcessorValueTreeState&, juce::String const&, juce::Slider&)+67> "H\213E\350H\203\300\bH\211\307\350\307:\002"}}, second = std::unique_ptr<juce::AudioProcessorValueTreeState::ParameterAdapter> = {get() = 0x55555603d0a0}}

Also just said screw it and uploaded to github, if you don’t mind taking a peek:

That helps. because line 25 in your processor.cpp is commented out, the state is not created.

1 Like

Ah youre definitely right, but the nullptr in the options causes an error when compiling:

../../Source/PluginProcessor.cpp: In constructor ‘DistortAudioProcessor::DistortAudioProcessor()’:
../../Source/PluginProcessor.cpp:25:66: error: no match for ‘operator=’ (operand types are ‘std::unique_ptr<juce::AudioProcessorValueTreeState>’ and ‘juce::AudioProcessorValueTreeState*’)
   25 |     state = new juce::AudioProcessorValueTreeState(*this, nullptr)
                                                                         ^

Not sure how to fix this, the docs don’t give me any clues

It is the same problem like above: You cannot assign a raw pointer (which is what new returns) to a smart pointer aka std::unique_ptr.
There are two ways, like the .reset(new Foo()) you learned above, or the better using std::make_unique:

state = std::make_unique<juce::AudioProcessorValueTreeState>(*this, nullptr);

This is still not all, because you still didn’t create the parameters you are trying to attach, but at least a step further.

1 Like

Ahhhhh thank you! I get confused with pointers, especially in C++ with these different types. Really appreciate you bearing with me I just strated making plugins yesterday. Thanks again, I’m gonna continue hopefully without these roadblocks

But I may ask a question later about setting up debugging in this sort of environment with CMake and VS code

Please don’t use vscode, it’s not Visual Studio in any way. The free Visual Studio 2022 is what you want. VScode is made by an independent developer, and it’s great for JavaScript, and other languages. Visual Studio is Microsoft, and the go to for C++ devs, plus, people on the forum can help you more with what they use themselves.
Besides, VS has a far superior editor, and all the tools like profiling & debugging. And you can launch it from the Projucer, and pass all the correct parameters.