Suggestions / Discussion About Increasing HISE's Generalisability
-
My experience with HISE is that it's optimised for a specific type of plugin, implemented in a specific way. The suggestions here are aimed at easing some of these barriers. My other goal is to help new developers—some aspects of HISE development require the knowledge of specific information that is not implied by the API or concepts (or perhaps not documented).
@Christoph-Hart wisely suggested that changing behaviours wasn't a good idea, because it would break all existing plugins. Therefore, except for one API addition, all my suggestions are made as flags. (This also likely makes them easier to implement, and less likely to cause problems because the existing code is hopefully unchanged.) The default value for all flags is zero, to current HISE behaviour (except for
ALL_QUEUES_ENABLED
).I've attempted to collect information on these specific topics in the forum, but it's not been possible to get all the information—so some of my underlying assumptions may be incorrect. And I probably haven't thought all of this through, sufficiently, so it's more a springboard for discussion than perhaps an explicit set of suggestions. Likewise, some of these flags may already exist, and/or I'm missing some obvious things.
NEW FLAGS
INDEPENDENT_DEFAULT_VALUES
Decouples the Preset system from the Default Value system. Currently, the two are linked; but the two systems are either redundant (i.e., Default Preset), unrelated (double-click to restore) or ontologically different (HISE feature vs. plugin architecture feature). The logical case is made in the documentation:
OVERRIDE_DEFAULTS_WITH_PRESET
Deals with the above problem (regardless of any other changes). Before designing a solution (if even possible), it would need be established which hosts (i.e., ProTools) do (or still do) this.
DEFAULT_VALUES_IN_EDITOR
Default Values are applied within the HISE Editor. When a project is compiled (including when loaded), the Default Values for all Components are set. (I'm assuming that they're always set in compiled plugins.)
CACHING
All caching that could result in unexpected behaviour, is disabled.
NO_REGISTRATION_CALLBACKS
Callbacks are not executed when they're registered. I don't see why automatic execution is desirable for all (or most) plugins.
NO_REGISTRATION_BROADCASTERS
Broadcasters are not executed when they're registered. I don't see why automatic execution is desirable for all (or most) plugins. There also might be a case for this flag to eliminate simply all secondary/illogical broadcasting (i.e., "EXPLICIT_BROADCASTERS"). For example, if I call
clearSampleMap()
, the Broadcaster for Samplemap loading fires—but no Samplemap has loaded.NO_PREINIT_DEFAULT_PRESET_CALLBACKS
Only loads the Default Preset after
onInit
. (Currently, it's loaded before and afteronInit
, with Callbacks firing both times.) Self-explanatory.NO_PRESET_LOADING_CALLBACKS
When a Preset loads, values are set, but Callbacks are not automatically executed. Without this, the Preset system is seems unnecessarily limited. (Even better would be a new Component flag dictating whether the Callback should be executed, but that sounds like a lot of work.)
EXPLICIT_DEFAULT_PRESET_NAME
Engine.getCurrentUserPresetName() returns a specific value to indicate that the Default Preset was loaded. The rationale is to distinguish from cases where no Preset was loaded.
RELEASE_FERRETS
Randomly releases angry ferrets at the offices of competing plug-in companies.
INCLUDE_ALL_MODULES_IN_PRESETS
Saves and restores Modules, including Child Modules, in Presets.
ALL_QUEUES_ENABLED
As an example, by default, there appears to be no queue for Broadcasters. This can result in the illogical (and potentially difficult to debug) behaviour of Broadcasters doing nothing—sometimes. Unlike the other flags presented here, this one defaults to the opposite state of current HISE behaviour; new users get what they expect, and experienced developers will know to set the flag.
NEW HISE PREFERENCES
"No Compile on Load"
Useful if you're plugin is crashing HISE when it's compiled."Default Save Stores All"
When command/control-s is pressed, or the Save menu command is chosen, these three operations are executed: Save the current XML file, Save all open editor files, Save the current Preset. Default is TRUE. (Rationale: Experienced users will know to turn that off if desired; new users won't know to turn it on.)"Clear Console at Compilation"
Currently, the order in which text is printed to the Console, during startup, is not ordered. This makes debugging more difficult. This is especially so in cases where the first line ofonInit
clears the Console, but the out-of-ordering causesprint
statements withinonInit
to print beforeonInit
—this also includes error messages printed by HISE—so all you see if a bunch of Console text, which then disappears, followed by whatever Console prints are displayed afteronInit
. With this preference item selected, HISE clears the Console each time compilation occurs—this removes the need for developers to clear the Console manually at startup."Global Persistence"
Dictates whether global variables persist across execution instances in the HISE editor. Default is TRUE (because that's the current behaviour)."Use Compiled File Paths"
Uses the file paths for when a plugin is compiled. Default is FALSE.Note
It may be more efficient to combine the previous two preference items, as well
DEFAULT_VALUES_IN_EDITOR
, into a singleSimulate Plugin Execution
preference item.
NEW API CALLS
Engine.resetDefaultValues(executeCallbacks);
The sister call to
UserPresetHandler.resetToDefaultUserPreset()
. The argument dictates whether the Control callback is executed.Screenshot 2024-11-21 at 11.52.15 pm -
@clevername27 said in Suggestions / Discussion About Increasing HISE's Generalisability:
there appears to be no queue for Broadcasters.
https://docs.hise.dev/scripting/scripting-api/broadcaster/index.html#setenablequeue
@clevername27 said in Suggestions / Discussion About Increasing HISE's Generalisability:
"Use Compiled File Paths"
Uses the file paths for when a plugin is compiled. Default is FALSE.Which file paths are you referring to?
-
@d-healey said in Suggestions / Discussion About Increasing HISE's Generalisability:
there appears to be no queue for Broadcasters.
https://docs.hise.dev/scripting/scripting-api/broadcaster/index.html#setenablequeueExactly—the queue is not in place, but the concept of Broadcasters implies that it would be.
"Use Compiled File Paths": Uses the file paths for when a plugin is compiled. Default is FALSE.
Which file paths are you referring to?Everything that is different between the two instances (e.g. PROJECT_FOLDER).
-
@clevername27 said in Suggestions / Discussion About Increasing HISE's Generalisability:
Exactly—the queue is not in place, but the concept of Broadcasters implies that it would be.
But why a preprocessor definition when you can enable the queue with a function call already?
@clevername27 said in Suggestions / Discussion About Increasing HISE's Generalisability:
Everything that is different between the two instances (e.g. PROJECT_FOLDER).
I'm still not sure what you mean, can you give me a specific example?
-
@d-healey said in Suggestions / Discussion About Increasing HISE's Generalisability:
But why a preprocessor definition when you can enable the queue with a function call already?
Good question. I wrote there was no default queue. For new developers, the assumption (and presumably safest behaviour) for publish/subscribe (to my knowledge) is to have a message queue by default. (Otherwise, if I'm trouble-shooting unexpected behaviour in my HISE plugin, I am not inclined to consider the possibility that a message queue must be enabled.)
@d-healey said in Suggestions / Discussion About Increasing HISE's Generalisability:
I'm still not sure what you mean, can you give me a specific example?
(Thank you for reading my long post, btw.)
-
So while there are a few good suggestions in here in general I see two big issues:
- stuff that changes internal behaviour (eg.
CACHING
). When I implement this I will not be thoroughly testing it in all possible use cases because there are too many. And then I'll deactivate it again like 99% of all users which marks it for instant deprecation / regression. - stuff that switch the default behaviour of an existing solution to another (eg.
QUEUES_ARE_ENABLED
). Of course this is up to discussion but there is a reason why the default is no queue - if you use the broadcaster system to "synchronize" different things to a common state (eg. updating the UI to reflect state changes of the internal data set), having a queue that eg. hammers down its messages for each UI change (eg. mouse movements) will lead to clogging and a sluggish UI performance, especially with big projects. On the other hand having a queue not work by default is an instantly recognizable problem which you can address while actually writing the function (BTW the broadcaster system is automatically switching to a queue based messaging if it's necessary so when you eg. attach a broadcaster to a single parameter of a single module, it won't queue because it assumes to just use the current value, but as soon as you're attaching it to one or more sources it assumes that it needs to update all changes so the queue is enabled automatically).
Engine.resetDefaultValues(executeCallbacks)
I have to look again but I vaguely remember that you can already recall the default user preset (if you're using that feature). If it's not there then it's definitely a valuable addition.
"Global Persistence"
Also a bit hesitant about deactivating this (and therefore clearing out the globals with each compilation). Might lead to subtle glitches that nobody will encounter because it's not active.
Currently, the order in which text is printed to the Console, during startup, is not ordered.
I remember you experienced this somehow but I actually don't see a reason why it wouldn't be ordered - sure some things are executed on different threads, but they should all end up in the console queue in a chronologic fashion.
"Default Save Stores All" (Save the current Preset.)
Hard pass. The default user preset should definitely not be saved when you edit & save the XML as it might be in any random state you left it in when dragging around sliders for their functionality. Actually when you use the default preset it will restore those values before saving the XML (so it's even the other way around) and this reduces the noise in the git history by 99%.
Script files should be saved though but I think I've added this a few weeks ago (somebody was complaining about external files not being saved with compilation and the fix for this should also implement the save script on save.NO_REGISTRATION_CALLBACKS
&NO_REGISTRATION_BROADCASTERS
The rationale behind those are the main use case of the broadcaster system which is propagating the internal state to various targets and this includes setting it to the correct initial value (otherwise you would always have to call
sendMessage()
after registering new listeners). However this is a thing that I could add as a function (just likesetEnableQueue()
with the default being on so you can deactivate it. No need for a compile time preprocessor though...NO_PREINIT_DEFAULT_PRESET_CALLBACKS
Yeah, I'd rather spend an evening with a glass of red wine and the default preset system to ensure that it behaves sanely than to branch between different opaque execution options.
When a Preset loads, values are set, but Callbacks are not automatically executed.
Can you elaborate on this? I would assume that all callbacks are executed.
INCLUDE_ALL_MODULES_IN_PRESETS
Nope, crash fest incoming if we allow this.
"No Compile on Load" - Useful if you're plugin is crashing HISE when it's compiled.
Yup, why not, good idea.
OVERRIDE_DEFAULTS_WITH_PRESET
,DEFAULT_VALUES_IN_EDITOR
,INDEPENDENT_DEFAULT_VALUES
I'm not sure if you've checked out the default user preset system yet but it covers a few of the things addressed with these suggestions. The
defaultValue
property is still useful if you want to change the double click position of a slider (which is almost always zero) from the initial state when you load the plugin (and I'm excluding Protools here because they made the decision to fuck up this distinction on their end).What I could add is another sanity check that checks if the default value deviates from the value in the default preset and prints a warning (or even autocorrects it).
- stuff that changes internal behaviour (eg.
-
@Christoph-Hart Thank you for wading through my message, and taking the time to thoughtfully respond. It means a lot to me as a (one of many) developer(s). (Thank you, @d-healey, as well.)
stuff that changes internal behaviour (eg. CACHING). When I implement this I will not be thoroughly testing it in all possible use cases because there are too many. And then I'll deactivate it again like 99% of all users which marks it for instant deprecation / regression.
I see your point — isn't that accounted for by making it a preprocessor flag, tho?
On the other hand having a queue not work by default is an instantly recognizable problem which you can address while actually writing the function (BTW the broadcaster system is automatically switching to a queue based messaging if it's necessary so when you eg. attach a broadcaster to a single parameter of a single module, it won't queue because it assumes to just use the current value, but as soon as you're attaching it to one or more sources it assumes that it needs to update all changes so the queue is enabled automatically).
I hear you saying some of these things are instantly recognisable (if I understand you correctly), but I'm not sure that's always the case—if something doesn't seem logical as causing a problem, we may not look there for a solution, regardless of obvious the problems was (once you know).
…lead to clogging and a sluggish UI performance…
Understood, but as a developer, I'd prefer sluggish first (and working), then optimising.
I have to look again but I vaguely remember that you can already recall the default user preset (if you're using that feature). If it's not there then it's definitely a valuable addition.
Default preset, yes (though no Callback flag); Default Values, no. I may be missing something, but I'm confused why Default Values seem linked to Presets—what is the benefit of them as a shared feature, verses the flexibility gained by keeping them separate? Like maybe…
- Default Value: The value assigned to a component upon creation (in the compiled plugin), and the double-click value.
- Default Preset: Values for starting with a specific configuration.
Also a bit hesitant about deactivating this (and therefore clearing out the globals with each compilation). Might lead to subtle glitches that nobody will encounter because it's not active.
Absolutely—but would it be problematic as a preprocessor flag? I'm thinking new developers here, who might not expect global persistence.
I remember you experienced this somehow but I actually don't see a reason why it wouldn't be ordered - sure some things are executed on different threads, but they should all end up in the console queue in a chronologic fashion.
(Understood - I only included it after seeing another user's post about the same issue.)
Script files should be saved though but I think I've added this a few weeks ago (somebody was complaining about external files not being saved with compilation and the fix for this should also implement the save script on save.
(Thank you — I am one of the guilty.)
However this is a thing that I could add as a function (just like setEnableQueue() with the default being on so you can deactivate it.
Be still my heart…
Yeah, I'd rather spend an evening with a glass of red wine and the default preset system to ensure that it behaves sanely than to branch between different opaque execution options.
Can you elaborate on this? I would assume that all callbacks are executed.
I meant that the preprocessor flag I'm suggesting would change this behaviour, so no Callbacks were selected. (Currently, all my component callbacks are wrapped in "if-than"s to ensure they don't fire on startup, because their correct functionality depends on various states.)
I'm not sure if you've checked out the default user preset system yet but it covers a few of the things addressed with these suggestions. The defaultValue property is still useful if you want to change the double click position of a slider (which is almost always zero) from the initial state when you load the plugin (and I'm excluding Protools here because they made the decision to fuck up this distinction on their end).
What I could add is another sanity check that checks if the default value deviates from the value in the default preset and prints a warning (or even autocorrects it).
Indeed—I love (almost) everything about the Default Preset system, particularly that there are Callbacks for before and *after. I remember your note about Pro Tools in the docs…hurray for Avid.
My plugin has over 50 GUI widgets, all of which have different states depending on the other widgets and such…for my case at least, the Default Preset system is the GOAT except for the automatic Callbacks on registration (because none of them are ready to do anything).
Thanks again for your replies and thoughts.