I am developing a VCV Rack plugin with multiple UI panel modes (like an “advanced” and “basic” layout) & I am trying to find a clean way to manage the internal parameter state when switching between these panels. For instance; if the user adjusts a knob in the basic panel & then switches to advanced; I want the parameter to retain its state but also reflect additional modulations /ons that only exist in the advanced panel.
Has anyone tackled this kind of state preservation without overcomplicating the DSP / UI logic?
I have seen mentions of json serialization and context-based updates, but I am unsure if that’s the most efficient path. Also wondering if ParamQuantity needs to be handled separately for each mode / shared universally. Would love to see how others have approached this or any general advice on structuring dual-panel plugins efficiently.
Also; while researching tooling for managing plugin logic, I stumbled upon a Microsoft tool and got curious what is power apps, and could ideas from low-code platforms like that help streamline basic config logic in Rack plugin prototypes?
Just to see if I understood this correctly (I will assume a really simple module in this example):
There is a module with two faceplates: the “basic” one has a knob to control “FOO”, an “OUT” port that contains the signal “FOO” generates and a switch “MODE” that can enable an advanced mode for the faceplate with additional controls, say, a trimpot to attenuvert a signal and an input “BAR” to modulate “FOO”.
Handling the controls and faceplates is rather easy:
An easy example to switch faceplates can be found in the source for Audible Instruments’ Tidal Modulator: it has two faceplates: one for the standard modulator and the other for the “Sheep” firmware.
Fragments here:
Examples of controls hiding and showing can be found in Audible Instruments’ Macro Oscillator 2.
Fragments:
As for the logic: an approach is to separate the logic into modules (methods), somewhere near the beginning of process() a switch statement could handle calling the appropriate stuff: the common methods for the basic and advanced modes in both branches (or however many) and just add stuff as the branches get more advanced:
An example akin to the stuff above, modularizing logic and reusing it in different branching paths (but not due to having Basic, Expert and so on modes); but for an actual module can be found in my Anuli module:
No physical modules can switch the faceplate and hardware visible, so Andrew’s answer would likely be: don’t try to do that. Consider making two complementary modules: the basic one and an advanced one. They can share a lot of code in common. You can add a copy/paste functionality to exchange settings between the advanced module and the basic one.
Or have a main module and an expander module for it. That’s what I’m currently doing for a set of modules I’m working on: additional modulation inputs and outputs are on an expander module so that the main module covers most common usages, and the expander provides additional control.
Well if I’m not entirely mistaken, Andrew wrote the Audible Instruments modules (based on Emilie’s DSP of course), which as evidenced above can do this. So I wouldn’t be so sure.
That being said, I would agree with not-things that the expander seems like an easier way to achieve the goal.
aren’t panels “just” an editor for a param that reflects the state of the param? While not commenting on whether it’s a good idea or not, I don’t understand why this should be a difficult programming task? Two different UIs for the same underlying parameters? sounds “easy”?
If all the underlying parameters are in fact the same, then yeah maybe! And I suppose programming an expander while also “easy”, is not zero work either. I guess either way could work. And the changing faceplate would certainly avoid the problem expanders have where you forget to grab both when moving them. IDK, whatever honks your boat I guess!
true, if the parameters mean different things in different modes that’s not super easy to make work. Again, without mentioning if that’s good idea or not. and making expanders isn’t trivial. Like 6 years ago I made some, and wouldn’t really want to do that again!
There are certainly multiple ways to do this, with various tradeoffs for things like midi mapping/parameter automation, preset save/apply, and ease of implementation.
In my WIP plugin I have several modules with a dynamic UI - basically meta-modules where you can customize the parameters. In my case, it’s for making patches that incorporate controlling complex external hardware. Dynamic UI is a lot of work in Rack, so I recommend keeping it as simple as you can. Bloodbat’s reply is probably the easiest route to go.