GUI Freezing in Reaper when using setValueNotifyingHost? Bug in juce? Don't usually like to say it but...?

Oh does it? Ohhh… oh now then. I will experiment. :). Thanks for the insight. This would maybe explain why the main thread was doing the xml stuff.

EDIT: I concur. My bad. I had no idea that Reaper did that. I will tell you what is weird though. I swear I put a breakpoint in that method when testing further up there ^^^, and it never triggered. Which is bizarre. Thanks for the help though. I will update the title accordingly. :). Oh… it seems I can’t anymore. Anyway i am sure this counts as solved.

Oh and… No… it isn’t a Juce bug. hahahaha. The question is… did I really think it was? Or was I just getting the old desperations in my burnt out struggles to understand? Well… you live and learn. :D.

Wait so… see I was under the impression that the methods only got called when saving/loading. This changes things. So a couple of questions that maybe you could offer some advice about at some kind of macro level.

Should I only update attributes that have changed? Or should I just ditch xml entirely? Is there another way to write to the memory buffer that can just do it sequentially without any of the more expensive xml methods?

EDIT : I see that there is MemoryOutputStream for example… does anyone know of any resources for how to use this approach? Cheers.

Unless… it is just as simple as something like this:-

// In getStateInformation...
juce::MemoryOutputStream stream(destData, false);
apvts.state.writeToStream(stream);

// In setStateInformation...
juce::ValueTree tree = juce::ValueTree::readFromData(data, size_t(sizeInBytes));
    if (tree.isValid())
        apvts.state = tree;

And then all I have to do is create a value tree for custom data and do the same? Or is it more like… I have to create a parent tree, put the apvts into it, then my custom data block, and somehow separate them out again? Pretty much like I was doing with the XML stuff.

All those sound like options. Without spending a while on it it’s difficult to say which is best.

But sounds like you have some ideas.

The fastest solution is to have some binary data that you just copy byte for byte into place. But it’s maybe not as flexible for future changes as using valuetree

Use the PerformanceCounter class in JUCE to measure the time in the function. And then see what’s the right balance of quick and maintainable for you!

2 Likes

Roger that. I am hacking away at it. Cheers for the help.

Okay all, to anyone reading this thread in the future who may also have similar issues, I have solved this problem. Here is what I did…

I tried stripping out the XML method calls and just used ValueTree’s, but it didn’t really improve the performance. So in the end I opted for sequentially reading / writing the data using the MemoryInputStream & MemoryOutputStream. This now reports only microseconds of time to call getStateInformation().

Average = 321 microsecs, minimum = 321 microsecs, maximum = 321 microsecs, total = 321 microsecs

Unfortunately… obviously I lose the robustness of using key / value pairs in a ValueTree, but in my case of having many parameters / banks, it really wasn’t a price that could be paid. In other plugins I have made I have not had nearly as many parameters and so this problem never presented itself to me.

So for example, this is a cutdown snippet of what I did:-

// in getStateInformation():-
juce::MemoryOutputStream stream(destData, false);
stream.writeBool(advancedMode);
stream.writeInt(selectedBankID);
stream.writeInt(selectedPatchID);
// etc for more parameters / settings

// in setStateInformation()
juce::MemoryInputStream stream(data, sizeInBytes, false);
advancedMode = stream.readBool();
selectedBankID = stream.readInt();
selectedPatchID = stream.readInt();
// etc for more parameters / settings

I was also able to chop out some parameters who’s values don’t need to be saved. Such as the toggling parameters that I would bind to midi controller buttons, to shave off a little bit more time.

I hope that this helps anyone else who should stumble upon it. Thanks for all the help to everyone who replied, and I have learnt quite a bit in the process about how some of the backend of Juce works which it seems I had some confusion over. So I’d say all is well that ends well :).

1 Like

I would say that it’s handy, if you are doing binary data blobs, to put some kind of magic number and version number at the front so you can add data later without it being a pain.

And if you wanted a fancy way of doing all this you can use: Protocol Buffers  |  Google Developers

1 Like

Well… what I did is write the plugins version number into the memory block, and then it can be retrieved out of there for comparison. If it is a different plugin version then it wont load the rest of the memory block in case of crashes / invalid data.

Then I have a way to export all the banks / patches into an XML file as a backup, which can be imported back in safely and of course… compared to getStateInformation() will only be ran once.

It seems to work well. :).

EDIT: But I will take a look at Protocol Buffers, thanks.

Yeah - I think your solution sounds good. You can if you do a new version branch based on teh version number so users can upgrade easily.