AudioProcessorValueTreeState is letting my DAW glitch for no reason (somehow)

gui
projucer
windows
audio

#1

Hello everyone,

I’ve encountered a very annoying error while linking my Sliders to ValueTreeStates.

First of all, I made a private tree for the Values in my PluginProcessor with a public getter for it

AudioProcessorValueTreeState& Z_reeseAudioProcessor::getTreeState() {
	return *state;
}

Everything worked fine, till I tried to initialize my SliderAttachments

volumeAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "volume1", *volumeSlider);
attackAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "attack1", *attackSlider);
releaseAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "release1", *releaseSlider);

The weird part is, that it worked fine when I build it for the first time and tried it out in my DAW (I’ve already set up the saving etc.) and it saved everything perfectly.
It actually started to bug out when I started initializing more SliderAttachments

For Example these:

    	volumeAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "volume1", *volumeSlider);
    	attackAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "attack1", *attackSlider);
    	releaseAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "release1", *releaseSlider);

So, to be more precise, it started to not load the VST again after I closed it (Error)

After removing the inits with the declarations, It kept crashing the VST after reopening it
(So, in conclusion: when I open the VST for the first time, it works perfectly fine, but when I close the window and reopen it, it doesn’t load it)

Does any1 know how to fix this error? I’m completely clueless…


#2

Debug it :slight_smile:

Edit, to elaborate: Run your plug-in in Debug mode e.g. on win: attach to the DAW process, or on mac: Open your DAW as executeable (cmd+< -> executable), and then load your plug-in. Once it crashes, your IDE will jump to the line of code where it happens. That should give you an idea what’s wrong, or at least gives you a stack trace you can post here, so we have an idea what possibly is going on. Without that we can only guess.

Edit2: Most of the time, we can’t even guess.


#3

I use Reaper on my Dev machines, I do not even have to attach to it. When I get a crash I get some friendly options to use my current IDE project or open another instance to show me where it went wrong.
Recommended and very cheap DAW for development!


#4

Thank you
Its not the DAW that is crashing - its my VST
And the only thing I can get out of debug is:

Thread 0x1afc ended with code 0 (0x0).
Exception triggered on 0x00007FF89894AA5A (Z_Reese.dll) in FL64.exe: 0xC0000005: Access violation while reading at position 0xFFFFFFFFFFFFFF.

JUCE assertion failure in juce_vst_wrapper.cpp: 1096
FL64.exe has thrown a breakpoint.

"FL64.exe" (Win32): "C: \ Windows \ System32 \ d3d10warp.dll" was unloaded.
"FL64.exe" (Win32): "C: \ Windows \ System32 \ DWrite.dll" has been unloaded.
"FL64.exe" (Win32): "C: \ Windows \ System32 \ d2d1.dll" has been unloaded.
JUCE assertion failure in juce_desktop.cpp: 47
FL64.exe has thrown a breakpoint.

Thread 0x1564 has ended with code 0 (0x0).
FL64.exe (Win32): "C: \ Program Files (x86) \ ImageLine \ FL Studio 12 \ Plugins \ Fruity \ Generators \ Fruity Wrapper \ Fruity Wrapper_x64.dll" has been unloaded.
"FL64.exe" (Win32): "C: \ Program Files (x86) \ ImageLine \ FL Studio 12 \ Plugins \ Fruity \ Generators \ Fruity Wrapper \ Fruity Wrapper_x64.dll" loaded. The module was created without symbols.
FL64.exe (Win32): "C: \ Program Files (x86) \ ImageLine \ FL Studio 12 \ Plugins \ Fruity \ Generators \ Fruity Wrapper \ Fruity Wrapper_x64.dll" has been unloaded.
"FL64.exe" (Win32): "C: \ Program Files (x86) \ ImageLine \ FL Studio 12 \ Plugins \ Fruity \ Generators \ Fruity Wrapper \ Fruity Wrapper_x64.dll" loaded. The module was created without symbols.
"FL64.exe" (Win32): "C: \ Windows \ System32 \ d2d1.dll" loaded. PDB file was not found or could not be opened.
"FL64.exe" (Win32): "C: \ Windows \ System32 \ DWrite.dll" loaded. PDB file was not found or could not be opened.
"FL64.exe" (Win32): "C: \ Windows \ System32 \ d3d10warp.dll" loaded. PDB file was not found or could not be opened.
Thread 0x1a5c ended with code 0 (0x0).
Thread 0x25a4 ended with code 0 (0x0).
Exception triggered on 0x00007FF89894AA5A (Z_Reese.dll) in FL64.exe: 0xC0000005: Access violation while reading at position 0xFFFFFFFFFFFFFF.
Thread 0x14f4 ended with code 0 (0x0).
Thread 0x2624 has ended with code 0 (0x0).

It seems to trigger an exception, but it doesn’t tell me where and why .-.


#5

It does tell you where, with filename and line number:

JUCE assertion failure in juce_vst_wrapper.cpp: 1096

JUCE assertion failure in juce_desktop.cpp: 47

Using your IDE and the search it should be possible to find these files.

I think the asserts are just while trying to gracefully unwind the stack. Seems like the destruction is managed on different threads from the one that crashed.

Can you post, how your state variable is defined and initialised?
Ideally you create it as member and return it without the asterisk.

My gut feeling is it is an uninitialised raw pointer…


#6

Sure!

I have declared it in my PluginProcessor.h like this:

public:
	AudioProcessorValueTreeState& getTreeState();
private:
	ScopedPointer<AudioProcessorValueTreeState> state;

And in my PluginProcessor I initialized it like this (in the constructor):

state = new AudioProcessorValueTreeState(*this, nullptr);

And the getTreeState() being this:

AudioProcessorValueTreeState& Z_reeseAudioProcessor::getTreeState() {
	return *state;
}

Thank you in advance

Edit 1:

I figured out that it only crashes on reopening when I have these lines implemented in my PluginEditor.cpp:

volumeAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "volume1", *volumeSlider);
attackAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "attack1", *attackSlider);
releaseAttachment1 = new AudioProcessorValueTreeState::SliderAttachment(p.getTreeState(), "release1", *releaseSlider);

When I remove them, it doesn’t crash smh

I defined these attachments in the PluginEditor.h like this:

private:
	ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> volumeAttachment1;
	ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> attackAttachment1;
	ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> releaseAttachment1;

And I added the parameters to the state in the constructor like this:

state->createAndAddParameter("attack1", "Attack1", "Attack1", NormalisableRange<float>(0.1f, 5000.f), 0.1, nullptr, nullptr);
state->createAndAddParameter("release1", "Release1", "Release1", NormalisableRange<float>(0.1f, 5000.f), 0.1, nullptr, nullptr);
state->createAndAddParameter("volume1", "Volume1", "Volume", NormalisableRange<float>(0, 4), 1, nullptr, nullptr);

state->state = ValueTree("attack1");
state->state = ValueTree("release1");
state->state = ValueTree("volume1");

#7

Do you also cleanup the attachments in the destructor? Daws can create an editor twice in a row, so the first close of the editor might crash without properly resetting the attachments to nullptr.

A comment from my own code:
// Make sure the attachments go out of scope before the controls and the valueTree


#8

You can make sure that the attachments are destroyed first by having the attachment members defined after the controls, since when unrolling the stack the last members are destroyed first (and the attachments must not outlive the controls).


#9

Explicitly resetting the pointers and not relying on the fact that they are scoped can also make your code more clear and correct.


#10

I wouldn’t say so. Explicitly setting stuff, that is governed by RAII clutters the view from the interesting stuff. The deletion order is clearly specified, so just use your sense when you add members is my favourite way to go.

But like I said, there is personal preference in that.


#11

Thank you peter and daniel, thats exactly what was making the problem!
I fixed it by adding

	volumeAttachment1 = nullptr;
	attackAttachment1 = nullptr;
	releaseAttachment1 = nullptr;

And now it works perfectly :slight_smile: <3

Thank you all for helping me out with that dull problem :slight_smile: