(Possible bug) Clearing AudioProcessorValueTreeState undo history after setting state

I’m fairly surprised nobody else has come across this, but it took me days of debugging off and on over several weeks to figure out. I’m now looking for a solution.

I’m using AudioProcessorValueTreeState to manage my plugin state, along with an UndoManager which is set in the tree state’s constructor as required. Both are of course owned by the derived AudioProcessor.

At the end of my AudioProcessor constructor, I add all my parameters to the state via createParameter. So far so good.

I have undo/redo buttons in my AudioProcessorEditor hooked up to the changeListener callback of the UndoManager, such that when the state changes, I can update the status of the buttons (i.e. greyed out if no undo or redo can be done). This is where I start to have problems.

After plugin creation, setting the state tree of the AudioProcessorValueTreeState seems to generate at least one (incomplete?) action on the UndoManager's stack, which causes my buttons to always begin with the undo button perusable (since there is an event leftover from adding the state tree) which seems to contain an action for adding an id parameter object to the tree. Attempting to perform an undo causes an assert due to failing a reentrancy check in UndoManager.

My days of debugging have pointed me toward the fact that AudioProcessorValueTreeState updates via a timer, and that if I wait an arbitrary amount of time before calling clearUndoHistory(), I can get rid of the stray undo action.

My question is, is this intended behavior? Am I setting up my undo all wrong (i.e. working with the UndoManager directly from my UI code)? How do I work around it? Clearly, there’s a way it’s supposed to work, considering it’s been implemented in big plugins like Equator…

I also call clearUndoHistory() after a short delay here to get around that.
I think this is a known issue :

Redo is not working correctly also here. Not sure how they manage it in Equator (without workarounds?)

1 Like

Yes, we’re aware of this issue and we’ll be overhauling the AudioProcessorValueTreeState code fairly soon. Unfortunately fixing this is far more complicated than it might seem.

1 Like

I’ve eventually used that:
AudioProcessorUndoAttachment (kudos @yairadix)

You do need to add begin/end gestures for all elements. but it works pretty well allowing undo/redo and provides a solution until AudioProcessorValueTree will be fully matured.

I’ve looked at the AudioProcessorValueTreeState and how it does multithreaded interaction with ValueTree and it looks extremely complicated as-is. While I enjoy diagnosing and fixing hard problems, I really don’t envy you in this case!

Looking forward to the overhaul, AudioProcessorValueTreeState is one of the most useful classes in JUCE and it’ll be nice to see it become even better.

Also @lalala that was my planned workaround, but it felt like a total hack - turns out it is! I suppose I’ll do that for now since my deadline is next week…

I ended up adding this to the end of my processor’s constructor, ugly but it works:

Timer::callAfterDelay(100, [&]{ undoManager.clearUndoHistory(); });