How to handle patch loading with backwards compatibility

I’m trying to implement a patch loading system which is able to load patches from an older version of my AudioProcessorValueTreeState (APVTS) as well. I’m interested in how other users do this, as it seems to me to be a pretty standard problem. My approaches so far, each with their unique problems are:

  1. use AudioProcessorValueTreeState::replaceState():
    It’s the obvious way but lacks backwards compatibility. Say I added a new audioparam, it will not be part of the APVTS after loading an old patch.

  2. like 1., but add some migration code to add new parameters to the APVTS:
    This works fine for adding non-audio params, however audio parameters can not be added to the tree during run-time.

  3. Iterate over the APVTS, check if the ValueTree to be loaded has the parameter, and overwrite the value if so:
    I tried to get this working, but had problems as described by me in this thread.
    Before using any more recources to try and fix this approach, I wanted to see what seems to a “standard” solution other people are using.

I’d be thankful for your input! :slight_smile:

I use a two-fold strategy. I am not using AudioProcessorValueTreeState, but my own ValueTree based state system, but the same principles could be applied.
Most importantly I save two version numbers with each patch. One is the current version of the plugin and the other the minimum compatible version (for forward compatiblity).
When a patch is loaded I compare these values to the current plugin version.

  • If a patch of an older version is loaded I run the data through a routine that might adjust some values which definitions might have changed over the lifetime of the plugin. If the data to load comes from a future version I check the min compatible version and refuse to load in case it is too new to load. Ideally this never happens.
  • When the plugin is first instantiated, default data is created which contains all parameters of the current version. I store a copy of this initial state data (before any preset is loaded) in memory. It can be static as it the same for all instances. Every time a new patch is loaded I first load this initial data again and then load the patch. This makes sure that any parameter that has been added in later version gets its init value - even if it isn’t preset in the older data to load.

Not sure these are standard approaches, but they have worked fine for me with plugins that have added lots of new patch parameters and changed some definitions over their lifetime.

2 Likes

Ok, thank you for sharing your approach! What you are doing sounds very similar to a combination of the methods 2) & 3) I have tried.