Dynamic reassignment of effect slots
-
Just wanted to run this past you guys to make sure my thoughts were in the right direction.
So I've got multiple areas of my plugin that have insert effects. You can imagine it as engine insert effects, send bus insert effects, and master bus insert effects. Each one has 4 slots - so a total of 20 effect slots.
Right now I am not intending to offer drag-and-drop re-orderability, or any re-ordering of any kind. Simple as you like - you select an effect in a menu.
So.... I might have 10 effect types to choose from. I presume I shouldn't try to dynamically create and destroy panels when a user selects an effect; seems like it would super overkill to do that, come with a ton of id referencing problems, and probably end up being buggy and crashy - especially when dealing wth modulation signals.
So I'm thinking - I have an effect host object. This has a header with the typical label, selection menu, bypass button type stuff. It also has a content area that holds a pool of generic controls. Let's say 16. On effect change I look up the list of parameters that the effect has, and reconfigure the attributes for the knobs to correspond to the list of parameters for that effect. This means every knob can change its x/y/width/height details, colours, etc.
It could also change its processorId, parameterId, min/max/middle/default values, etc.
I'd hide any knobs that didn't need to be used for that effect. So the knob id's don't ever change. The json attribute dictionary just gets updated on an effect selection operation.
Since I'll be using Hardcoded Master FX for all of these, all the callback needs to do is trigger a .setEffect on the relevant slot.... and then call something like updateParameterAssignments, which does all of the above.
The things I'm not clear on is -
-
How would this interact with the matrix modulation system. Let's say a knob had some modulation assigned to it, do I have to clear the modulation from the knob before choosing the new effect and updating attributes, or do I store the mod settings so that the next time that same effect is chosen, I can restore the modulation settings as well? Or do I attempt to carry over the modulation settings from one effect to another???
-
How would this interact with presets?
-
How would this interact on first run - as I recall, all callbacks are triggered on first run ??
-
-
I'm doing exactly the same thing as you! :-)
I don't know yet if my strategy works, but I can tell you about it:
For each effect, I have a panel with a maximum of 15 sliders, as my effects have a maximum of 15 parameters.
The sliders are saveInPreset.
Each panel has a combo box for the user to select the effect. However, this combo box is not saveInPreset.
The actual (internal) selection of the effect is done via a label, in whose callback the actual effect is loaded. This label is saveInPreset. The selection of the effect depends on the label text.
In the callback of the combo box, I set the text of the label and the properties of the sliders, i.e., min, max, and center point, so that they match the parameters of the selected effect. When selecting a new combo box item, the changed() function must be used for the label to trigger its callback and load the correct effect.
This way, I hope that the correct data is saved in the preset and I can still set the sliders correctly when selecting a new effect. This would not work if everything took place in the callback of the combo box and it was set to saveInPreset.
When I select a new effect, I delete the modulation data of the sliders, as this is the most natural behavior for me.
-
@Orvillain
PS. I wanted to work with hardcoded effects and HISE internal effects, which is why I used an effect slot and a hardcoded effect, which I switched to bypass depending on the effect selection.Unfortunately, the bypass didn't work reliably, so I actually had to load the effects individually. It's not an ideal solution, but unfortunately I couldn't find another one. Since you only use hardcoded effects, this shouldn't be a problem for you.
-
@Orvillain
PPS. In the label callback, after loading the effect, I set the value of the CombBox so that it displays the correct effect name. However, I did not use the changed() function, as this would have created a loop. -
@Orvillain For points 2 & 3 I dealt with this by setting the state of my UI via the Engine.addModuleStateToUserPreset. Initially I made the mistake of constructing my dynamic-fx system around the UI components and it took me a while to undo this decision.
I found the benefits of constructing your system with the Module State means your UI can update according to whatever information is found in the modules, so your presets can load and save correctly, etc. I used a timer at the time but a broadcaster is arguably a better method now.
For point 1 about the matrix modulator I can't say as I haven't integrated this into a dynamic-fx system. I imagine if the user is rearranging the fx you are going to have to store then clear modulation connections first, then restore them once the effect is in a new position.
Sounds like @Oli-Ullmann has some interesting ideas on how to do this as well!
-
Just a small heads up that we have this now:
https://docs.hise.dev/tutorials/ui/index.html#draggable-fx-chain
Which should integrate well with the other ideas you‘re suggesting so the reordering is not too much out there.
Oh and yeah definitely go with addToModuleState and not the saveInPreset route for every component.
-
@Christoph-Hart said in Dynamic reassignment of effect slots:
addToModuleState
Why should we use “addToModuleState”? To save the modulation of the sliders, they have to be “saveInPreset” anyway, right? Isn't that redundant?
-
@Christoph-Hart
Ok, no they don't. I just checked it. -
Why should we use “addToModuleState”?
Because it stores everything (including audio files & sliderpacks if applicable) and you don't need to reroute components to the new modules.
To save the modulation of the sliders, they have to be “saveInPreset” anyway, right?
No. The modulation connections are not part of the slider's data model. For loading / saving matrix connections you just use this method and store the string somewhere.
EDIT: Actually you don't need to do this manually, as soon as you create a ScriptModulationMatrix, it registers itself and writes / loads its state from user presets.
-
@Christoph-Hart aww man I just did it all manually
-
@Christoph-Hart
Great, thanks for the info. :-) -
Does any kind soul have a snippet that demonstrates how to use Engine.addModuleStateToUserPreset???
-
// In onInit Engine.addModuleStateToUserPreset("InsertNameOfModule");
-
@d-healey So Do I have it right then.... call that function for every module that I want to save to a preset.... save to a preset in the browser..... then when I load it, those things will be recalled both in the module tree and the connected UI parameters, regardless of if saveInPreset is enabled????
-
@Orvillain It will be recalled to the module tree, not sure about the UI parameters but Christoph seems to indicate that with this dynamic effect slot system that it will be.
-
@Christoph-Hart
When I try to follow your advice with a HardcodedMasterFX, I get the following error message:
Can't store modules with child modules
Is it not possible to use
Engine.addModuleStateToUserPreset
with a HardcodedMasterFX? -
those things will be recalled both in the module tree and the connected UI parameters, regardless of if saveInPreset is enabled????
It will be recalled to the module tree, not sure about the UI parameters but Christoph seems to indicate that with this dynamic effect slot system that it will be.
No UI parameters are not part of the module that is restored with its state so they won't update automatically. But you can call this method after loading a user preset to ensure that all connected sliders are synced to their internal values:
Is it not possible to use Engine.addModuleStateToUserPreset with a HardcodedMasterFX?
Do you have any modulation slots enabled? If yes then this is preventing you from restoring the hardcoded FX because currently you can only restore modules that have no child modules with this function. But I might have to change this to allow it for hardcoded modules as this would be very limiting.
-
@Christoph-Hart
Ah, okay, that's where the problem lies...
Yes, I have enabled modulation slots. -
@Oli-Ullmann Alright this is fixed now - you can call this on modules with child elements now but the child elements will not be modified at all - the rule that rebuilding child elements is dangerous still stands, but this is a valid use case to restore a module without its modulation slots (which are restored by the script modulation matrix anyways).
-
@Christoph-Hart
That's great, thanks! I'll try it out and give feedback if I encounter any problems. Thanks very much! :-)