Problem storing and loading extra plugin info (last editor size etc.)

I have a plugin that in addition to handling parameters the usual way (via an AudioProcessorValueTreeState) also has to keep track of a bunch of extra things (last editor size, selected colour scheme, last preset etc.).

Putting together some advice found on this forum, I ended up storing the info inside AudioProcessorValueTreeState::state.

Basically when I need to save extra state I call something like this from the editor (which has a reference to the processor’s apvts):

auto editorSettings = apvts.state.getOrCreateChildWithName ("editorSettings", nullptr);
editorSettings.setProperty ("theme", myTheme, nullptr);
editorSettings.setProperty ("width",lastWidth, nullptr);
// ... 

Then, in the editor’s constructor I load the info:

auto editorSettings = apvts.state.getOrCreateChildWithName ("editorSettings", nullptr);
auto selectedTheme = editorSettings.getProperty ("theme", "light");
auto lastWidth = editorSettings.getProperty ("width", 800);
// ... set editor size, set colour theme etc.

This seems to work except in one situation: the first time the plugin is loaded in a DAW, in which case we get the default values, as if the stuff in apvts.state wasn’t loaded yet; If I then close and reopen the editor again, it will start working fine (i.e. I can close and reopen the editor as many times as I want and it will preserve size and theme).

So it looks like I’m trying to access the data in the ValueTree too early, but why? The processor has been created before the editor is opened, and the plugin parameters are loaded correctly even when opening the editor for the first time (meaning that setStateInformation has been called, which if I understand correctly should load the parameters as well as the extra data since they are stored in the same ValueTree).

So what am I doing wrong? Am I missing something?

Note that I tried making the editor inherit from ValueTree::Listener and having it fetch the data when the value tree changes, which seems to “fix” the issue. I’ve got the feeling, however, that I might be overcomplicating it - is there’s a simpler, better solution?

Thanks in advance!

I posted this question a while ago coming to the conclusion, that one should just leave the „state“ in APVTS alone (even though it clearly advertised in the documentation. JUCE Team haven’t responded yet). AudioProcessorValueTreeState with custom ValueTree

„Is there a simpler solution“: I think yes, just use a different ValueTree were you know what happens (and what is thread safe).

Concerning your concrete problems: it really does sound a lot like the DAW is creating your plugin and editor before the state is set. Although you seemed to have debuged the method calls? I think it would be beneficial if you could share a bit more code so we can understand what exactly is going on.

Having the editor listening to the valueTree is (in my opinion) a must have feature. Imagine the DAW changing your state (for what ever reason), you‘d want your editor to reflect what’s in the state including the bounds of your editor window.

1 Like

Hey thanks for your reply! Sorry I completely missed your earlier post (I think I was using different search terms at the time).

Right, sounds like I could try the same approach (using a separate ValueTree for the extra data and only put it into the APVTS during get/set state).

I’ll give it a go and see if things work. If not I’ll post more details/code.
Thanks again for your input!

The method I use is to store that data in a config file via the use of an external json / xml file, and to provide a class with a bunch of static functions to read / write to that config file when we start the program / whenever a change is made. here’s an example of what the header would look like:

class Config
{
public:
	static juce::File getConfigFile();
	static json getConfigJson();

	// load / save window size multiplier via .config file

	static float loadWindowSize();
	static void saveWindowSize(float window_size);

	// load / save spectrogram metering state

	static bool loadMeteringState();
	static void saveMeteringState(bool metering_state);

	static void saveJsonToConfig(json config_state);
};

all of the load() functions call getConfigJson and get the values that they need from it, and all of the save() functions call getConfigJson(), set attributes to the value they should be at, and then saveJsonToConfig(), which saves it to the disk.

I think this is not applicable here since the DAW might change the state at any time (e.g. the user loads/saves state in Logic to a file he selects). The design goal here is to also store the window size information aside from the parameter settings.

Just out of curiosity: is there a reason you didn’t use the built in stuff from JUCE JUCE: ApplicationProperties Class Reference? This would have the advantage to directly support both user and system wide settings and JUCE takes care of the proper file location (since they are different on MacOS and Windows).

just like rincewind, i’d suggest to use ApplicationProperties instead of apvts.state. unlike rincewind, i’d say that using additional state in the apvts.state is totally fine and doesn’t require another valueTree. but saving and loading window bounds in this valueTree assumes the user wants to have different window bounds in every instance of the plugin. i kinda doubt that this is true in most cases. most of the time people just wanna drag the window to some bounds that feel nice and then leave it at that for the rest of their lives

Could you elaborate that more? Maybe I’m missing something but the problem using apvts.state is the thread problem. AudioProcessor::setState might be called from any thread at any time. This was already discussed in a different thread and the reason why there are locks inside APVTS. Since you don’t know when or from what thread the ValueTree is written to, you can’t store any additional information into the ValueTree (in this case size updates when ResizeableWindow callback strikes) without taking that lock yourself – which is not possible due to it being a private member in APVTS.

Therefore, I don’t see how you should be able to store your own stuff inside the valueTree during setState and getState. But that kind of defeats the hole purpose of the ValueTree so you may just use a different one. (And even that last part assumes, that setState and getState are not called concurrently)

sure.

ok so first of all i start with the assumption that saving and loading the state doesn’t happen all the time. it doesn’t need to be realtime save. it’s just loading and saving presets. once presets are loaded people work with the plugins in realtime.

with this assumption you can just put a lock into set- and getState to make sure it doesn’t do anything thread-unsafe. or you could use an AsyncUpdater to let the message thread handle the changes. that way you can make sure that even the GUI doesn’t try to update itself while the state is changed.

idk what’s the deal with the private internal lock of apvts, but if it really gets in the way i might rather ditch apvts than using a lot of seperate objects as state, because it just feels less like a solution and more like a workaround to me to introduce extra objects just because some objects are not accessible. (i can not really comment on apvts’ lock, because i don’t use apvts anymore)

I didn’t think about it, I started researching the topic and came across some post talking about adding stuff to apvts.state so I just tried that first.

Sounds like ApplicationProcess could be a good way of saving the info I need (window size, colour theme etc.) without sticking it into the apvts.state (also because that’s actually info that has to do with the UI, not the processor!).

Yeah that’s right, I don’t want each instance to have different size or colour theme, or for those things to be saved into presets (that used to happen when I was putting data into apvts.state and I wasn’t happy about it).

Are you sure the issue isn’t as simple at the editor get constructed before state is loaded? That’s the case in VST3 — the editor builds before the state from the DAW is set, storing your window size a global setting on disk outside your state will probably solve this, but you might find some other per plugin UI setting isn’t constructing properly.

Yeah that’s what’s happening - it definitely behaves like this (in Live at least)!

I did some debugging of the VST3 in Live and this is the sequence of events when you load the plugin:

  • getStateInformation is called (at this point we only have default values for all the parameters, and no editor size, theme etc.)
  • plugin editor constructor is called (so it gets default window size)
  • setStateInformation is called (at this point we get actual parameter values as well as extra info such as window size etc.; parameters update “magically” but not editor size etc. unless I use e.g. a ValueTree::Listener)

In Reaper seems to be a bit different actually; the call sequence is

  • getStateInformation (called twice for some reason)
  • setStateInformation
  • editor constructor (so “it works”)

(I haven’t tried other DAWs yet.)

So finally I understand what’s going on and why it behaves like that! :slight_smile:
As a quick fix here I could use ValueTree::Listener and it will “just work” (modulo the possible threading issues discussed earlier).

I’m still wondering though, what’s the best solution in general… I’m not sure i want things like the window size to be part of the processor and being unique to plugin instance. Maybe ApplicationProperties (as was suggested previously in this thread) is the way to go. I’ll have a think.

By the way… One other piece of information I’d like to store is the current preset name; where is that supposed to be stored normally?

thanks again all for your input!