Saving MIDI CC assignments in user presets?
-
HISE saves MIDI CC assignments in the
.presetwhen a user saves.This seems contrary to a lot of other synths I've used.
Feels like normally, I would set up some MIDI CCs on various knobs, then browse through presets and those CC assignments would stick across preset loads.
This allows me to [1] set up a consistent 'performance' system, like mod wheel to filter cutoff, knob1 to filter res, etc, for all presets and [2] play through presets and have any existing CC automation produce predictable results.
HISE saving MIDI CC assignments to the preset data means that, after setting up a bunch of CC assignments for one preset, when I load a new preset they will either [1] all disappear if the new preset has no saved assignments, or [2] change to different assignments.
If anything, I'd prefer to have MIDI CC assignments saved globally, separate from the preset data, so they persist across not only presets but instances of the plugin.
What do you all do about this?
-
@dannytaurus This is a very good point and something I'm going to start adding to my instruments, don't know why I didn't think about it before.
I'm pretty sure if can be achieved using the MidiAutomationHandler and storing the automation settings to a file which you load back in on init.
https://docs.hise.audio/scripting/scripting-api/midiautomationhandler/index.html
-
@David-Healey Scripting the saving and loading of MIDI CC assignments to a separate file is one step, but you also have to fight the saving and loading of the data in the presets.
Claude came up with a (hacky) way to script around it but in the end I felt like a PR with a new preprocessor was better.
https://github.com/christophhart/HISE/pull/995
(I know there are already too many preprocessors, but this is mainly just for me, only upstreaming in case anyone else wants it.)
So now I just turn this off (
HISE_MIDI_AUTOMATION_IN_USER_PRESETS=0) and then I don't have to fight anything in script. -
@dannytaurus load them in the post load callback
-
@David-Healey Unless you prevent saving/loading the CC data to presets, you're always doing more than you should have to.
Without the preprocessor:
- Launch the plugin - load the CC mappings from separate file
- Load a preset - in post load callback you need to reassign CC mappings because they're overwritten by the load
- Assign some CC mappings - automatically save the new mappings to separate file here
- Save the preset - the CC mappings save with the preset, so maybe do a post save callback to remove the data
- Load the next preset, etc.
With the preprocessor:
- Launch the plugin - load the CC mappings from separate file
- Load a preset - nothing to do
- Assign some CC mappings - automatically save the new mappings to separate file here
- Save the preset - nothing to do
- Load the next preset, etc.
-
@dannytaurus said in Saving MIDI CC assignments in user presets?:
Save the preset - the CC mappings save with the preset, so maybe do a post save callback to remove the data
You don't need to do anything here because you're already loading the CCs from the file.
So your preprocessor removes step 2 the rest is the same.
I think AppConfig.h is autogenerated when you save the juicer file so probably shouldn't be tracked by git - I could be wrong.
-
@David-Healey said in Saving MIDI CC assignments in user presets?:
Save the preset - the CC mappings save with the preset, so maybe do a post save callback to remove the data
You don't need to do anything here because you're already loading the CCs from the file.
That's true, but if you leave the CC mappings in the preset file then it becomes lies on disk.
Likely to be confusing to someone looking at the preset XML.
Agree on the AppConfig.h, Claude forced it into the commit, I'll remove it.
-
@David-Healey Claude also found another case to consider - plugin launch.
Looking at it now.
-
@dannytaurus said in Saving MIDI CC assignments in user presets?:
Launch the plugin - load the CC mappings from separate file
Handled here, no?
-
@David-Healey Maybe, yes.
-
@dannytaurus @David-Healey Can't the CC mapping simply be removed from the preset using the handler? Isn't the custom preset intended for this purpose in the first place? Never tried myself that being said...
-
@David-Healey Apparently not.
There are 3 HISE restore points that run after
onInit, so it still needs handling.From Claude:
Fresh instance in a DAW:
FrontendProcessor::restorePluginrunscompileAllScripts()(your onInit applies the file) and then restores the
MidiAutomation node from the embedded project state (FrontEndProcessor.cpp:458). The export always writes that node ā even when empty,exportAsValueTreeadds it unconditionally ā so a fresh instance immediately clears the mappings you just loaded. Your file-load is defeated before the user ever touches the plugin.Reopening a session: the host calls
setStateInformationat some point after instantiation (host-dependent timing), andFrontEndProcessor.cpp:576restores the session's stale mapping copy over whatever onInit applied.In the editor: every project load stashes the project XML's
<MidiAutomation/>and applies it after script compilation (MainController.cpp:562/577)
ā same wipe while you're developing. -
@ustk Not sure. To be honest, I just want all the 'CC data in presets' code out of my fork.
Might just drop the preprocessor and remove it all directly.
I can't see a situation where I would ever want CC data in the presets. So a preprocessor is only useful for backwards compatibility, which I don't have any of

-
I think this is what the custom user preset model is for: https://docs.hise.dev/scripting/scripting-api/userpresethandler/index.html#setusecustomuserpresetmodel
Haven't tried it myself.
-
@David-Healey Lol
@ustk said in Saving MIDI CC assignments in user presets?:
@dannytaurus @David-Healey Can't the CC mapping simply be removed from the preset using the handler? Isn't the custom preset intended for this purpose in the first place? Never tried myself that being said...
Just checked and the answer is no, you can't manage what is written... But Claude came with a neat solution:
// (processBeforeLoading, unpackComplexData) uph.setEnableUserPresetPreprocessing(true, false); uph.setPreCallback(function(presetData) { // presetData is a JS object; MidiAutomation is a top-level property. // Emptying it means applyJSON rebuilds an empty <MidiAutomation> node, // so the incoming preset never overwrites the current CC assignments. presetData.MidiAutomation = {}; // or just rewrite what you already saved }); -
@David-Healey @David-Healey So the working solution is
const var currentAutomationState = {"ChildId": "Controller", "Children": []}; const var mah = Engine.createMidiAutomationHandler(); mah.setUpdateCallback(function() { currentAutomationState.Children = this.getAutomationDataObject(); }); const var uph = Engine.createUserPresetHandler(); uph.setEnableUserPresetPreprocessing(true, false); uph.setPreCallback(function(presetData) { presetData.MidiAutomation = currentAutomationState; });The automation state is saved in the instance but you can just save it in a file if you wish so.
I'd prefer not in my case, because if you load multiple instances of the plugin, they'll all react to the same CC... -
@ustk said in Saving MIDI CC assignments in user presets?:
const var currentAutomationState = {"ChildId": "Controller", "Children": []};
Does this store MPE and Macro assignments too?
-
@David-Healey Apparently macro yes, but MPE

Here's the automation data object:[ { "Controller": 6, "Channel": -1, "Processor": "Interface", "MacroIndex": -1, "Start": 0.0, "End": 1.0, "FullStart": 0.0, "FullEnd": 1.0, "Skew": 3.106283926937945, "Interval": 0.0, "Converter": "37.nT6K8CBGgC..VEFa0U1Pu4lckIGckIG.ADPXiQWZ1UF.ADf...", "Attribute": "HiBoostBWKnb", "Inverted": false } ] -
@David-Healey Just tested with my seaboard and yes, it works for MPE that have been MIDI learnt (Since it's just MIDI in the end...)
-
@ustk said in Saving MIDI CC assignments in user presets?:
I'd prefer not in my case, because if you load multiple instances of the plugin, they'll all react to the same CC...
That's a very interesting point!
EDIT: actually, maybe it's fine. The DAW will only send MIDI CC to the active plugin, right?