Forum
    • Categories
    • Register
    • Login

    Using custom preset system - as in the actual presets themselves, not a browser

    Scheduled Pinned Locked Moved General Questions
    12 Posts 6 Posters 82 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • DanHD
      DanH
      last edited by

      I'm deep into making my own browser and tag system and the issue of not being able to update .preset files on the fly like you can a json is forcing me to have a second 'tag' file for each preset (in order to maximise flexibility - I know I can have a main json for tags etc but this doesn't work if users share presets etc).

      So I'm thinking of bypassing the Hise Engine.saveUserPreset(presetFile); etc completely and rolling my own.

      What are the potential issues that anyone can think of?!! Before I go down this rabbit hole!!!

      Not having access to saveInPreset is one I can think of, but perhaps just not including the non save in preset components in the preset files might be enough...

      DHPlugins / DC Breaks | Artist / Producer / DJ / Developer
      https://dhplugins.com/ | https://dcbreaks.com/
      London, UK

      dannytaurusD 1 Reply Last reply Reply Quote 0
      • dannytaurusD
        dannytaurus @DanH
        last edited by dannytaurus

        @DanH Might be better to extend the source code to support what you need. Then you get all the current solid functionality plus whatever you need.

        The added bonus (for others😜) is that if your changes are needed by others they can merge them.

        Sounds like you've done a lot of work on a custom system already, but if you were to take a step back and say "how would the current preset system need to change to accommodate my needs?", what would your answer be?

        Meat Beats: https://meatbeats.com
        Klippr Video: https://klippr.video

        DanHD 1 Reply Last reply Reply Quote 0
        • DanHD
          DanH @dannytaurus
          last edited by DanH

          @dannytaurus well it would be being able to write to a .preset file without calling Engine.saveUserPreset(presetFile); to enable users to add non-critical data like tags / text fields and update text arrays etc. Maybe like a 'light' version of Engine.saveUserPreset(presetFile); which doesn't kill voices or reload sample maps etc....

          DHPlugins / DC Breaks | Artist / Producer / DJ / Developer
          https://dhplugins.com/ | https://dcbreaks.com/
          London, UK

          David HealeyD 1 Reply Last reply Reply Quote 0
          • David HealeyD
            David Healey @DanH
            last edited by

            @DanH why not use the built in preset tag system?

            Free HISE Bootcamp Full Course for beginners.
            YouTube Channel - Public HISE tutorials
            My Patreon - HISE tutorials

            DanHD 1 Reply Last reply Reply Quote 0
            • DanHD
              DanH @David Healey
              last edited by

              @David-Healey for many many reasons

              DHPlugins / DC Breaks | Artist / Producer / DJ / Developer
              https://dhplugins.com/ | https://dcbreaks.com/
              London, UK

              Christoph HartC ustkU 2 Replies Last reply Reply Quote 0
              • Christoph HartC
                Christoph Hart @DanH
                last edited by

                @DanH use a separate data system for metadata but rely on the user preset system to load the actual presets. If you start hacking around there you will open a can of worms.

                DanHD 1 Reply Last reply Reply Quote 0
                • DanHD
                  DanH @Christoph Hart
                  last edited by

                  @Christoph-Hart ok, that's essentially what I'm doing.

                  PS - did you see my latest email?

                  DHPlugins / DC Breaks | Artist / Producer / DJ / Developer
                  https://dhplugins.com/ | https://dcbreaks.com/
                  London, UK

                  ustkU 1 Reply Last reply Reply Quote 0
                  • ustkU
                    ustk @DanH
                    last edited by ustk

                    @DanH The stock preset system doesn't just recall parameters, it also stop/release the audio (or something like that) during loading time, and probably a bunch of other stuff you don't want to do without...

                    An approach could be to store an object in a panel that contains what you need like tags.
                    Then at init (or anytime you want really) you automatically create/update a unique JSON file that contains all the tags from all the available presets. So if a user shares a preset, this can be automated (or with a "collect tags from presets" button) and the local JSON file updates (as well as your preset browser which ever it is).

                    Hise made me an F5 dude, any other app just suffers...

                    1 Reply Last reply Reply Quote 0
                    • ustkU
                      ustk @DanH
                      last edited by

                      @DanH Oh in fact you don't even need to create a JSON file, all can be kept internally in a variable since the tag list is gathered at init...

                      Hise made me an F5 dude, any other app just suffers...

                      1 Reply Last reply Reply Quote 0
                      • OrvillainO
                        Orvillain
                        last edited by Orvillain

                        We're covering a lot of this in this thread:
                        https://forum.hise.audio/topic/13701/custom-browser-custom-preset-file-format/29

                        Basically, you've got this:

                        namespace PluginUserPresetHandling {
                        
                            const UserPresetHandler = Engine.createUserPresetHandler();
                        
                            inline function onPresetSave() // this is your main preset save method
                            {
                                Console.print("onPresetSave triggered");
                            }
                        
                            inline function onPresetLoad(obj) // this is your main preset load method
                            {
                                Console.print("onPresetLoad triggered");
                            }
                        
                            inline function preLoadCallback() // things you want to happen before loading a preset happen here - looking for samples, looking for graphical assets, etc.
                            {
                                Console.print("preLoadCallback triggered");
                            }
                        
                            inline function postLoadCallback() // things you want to happen after loading a preset happen here - updating preset name labels in your UI, triggering other UI updates, etc.
                            {
                                Console.print("postLoadCallback triggered");
                            }
                        
                            inline function postSaveCallback() // things you want to happen after saving a preset happen here - copying samples to an external location, removing any dirty flags you might've setup in the UI layer, etc.
                            {
                                Console.print("postSaveCallback triggered");
                            }
                        
                        
                            inline function init() {
                                UserPresetHandler.setUseCustomUserPresetModel(onPresetLoad, onPresetSave, false); // this line is essential
                                UserPresetHandler.setPreCallback(preLoadCallback);
                                UserPresetHandler.setPostCallback(postLoadCallback);
                                UserPresetHandler.setPostSaveCallback(postSaveCallback);
                            }
                        }
                        
                        

                        You can achieve a hell of a lot with this, without discarding the HISE preset system.

                        For example, here is my onPresetSave method in my current project:

                            inline function onPresetSave() {
                                Console.print("onPresetSave triggered");
                                PluginSharedHelpers.forceAllOuterSlotsEnabled();
                        
                                if (PluginSharedData.presetMode == "Global") {
                                    return saveGlobalPreset();
                                }
                                if (PluginSharedData.presetMode == "FXChain") {
                                    return saveFXChain();
                                }
                            }
                        

                        In this way, I'm able to gate different save functions based on a master type, which means I can either write the HISE .preset file, or I can write a custom file using my own data model.

                        My load one is this:
                        inline function onPresetLoad(obj) {
                        Console.print("onPresetLoad triggered");
                        PluginSharedData.isRestoringPreset = true;

                            if (PluginSharedData.presetMode == "Global") {
                                loadGlobalPreset(obj);
                            }
                            if (PluginSharedData.presetMode == "FXChain") {
                                loadFXChain(obj);
                            }
                        
                            PluginSharedData.isRestoringPreset = false;
                        }
                        

                        The loadFXchain method is this:

                        inline function loadFXChain(obj) {
                                if (!isDefined(obj)) return;
                        
                                Console.print("we are now attempting to load an fx chain");
                                PluginSharedHelpers.forceAllOuterSlotsEnabled();
                        
                                local fxSelections = obj.fxSelections;
                                local fxChainOrder = obj.fxChainOrder;
                                local params = obj.parameters;
                        
                                // Set effect menus by stable id (this loads the networks)
                                if (isDefined(fxSelections)) {
                                    for (i = 0; i < fxSelections.length; i++) {
                                        local sel = fxSelections[i];
                                        if (!isDefined(sel) || !isDefined(sel.id)) continue;
                        
                                        local idName = (isDefined(sel.idName) && sel.idName != "") ? sel.idName : "empty";
                                        UIEffectDropDownMenu.setMenuToId(sel.id, idName, true); // fire callback
                                    }
                                }
                        
                                // Restore FX parameters for the current fxchainScope, skipping selectors (already set)
                                if (isDefined(params)) {
                                    for (i = 0; i < params.length; i++) {
                                        local p = params[i];
                                        if (!isDefined(p) || !isDefined(p.id)) continue;
                                        if (!_isFxParam(p.id)) continue;
                                        if (p.id.contains("EffectSelector")) continue; // handled above
                        
                                        local c = Content.getComponent(p.id);
                                        if (!isDefined(c)) continue;
                        
                                        c.setValue(p.value);
                                        c.changed();
                                    }
                                }
                        

                        And you can hopefully see, that what that is doing is skipping userPresetLoad altogether - and instead is manually iterating around whatever data exists in the file, finding the right UI component, and setting the value. This allows me to circumvent some of the HISE assumptions; namely that if a UI component is not specified when loading a user preset, it gets reset to the default value. Which is super no bueno.

                        Bear in mind some of this stuff can be asynchronous. So I don't think you can always rely on the order of things.

                        Musician - Instrument Designer - Sonic Architect - Creative Product Owner
                        Crafting sound at every level. From strings to signal paths, samples to systems.

                        OrvillainO 1 Reply Last reply Reply Quote 0
                        • OrvillainO
                          Orvillain @Orvillain
                          last edited by Orvillain

                          @Christoph-Hart along these lines....

                          Calling:
                          updateSaveInPresetComponents(params) does indeed have the effect of setting any non specified parameters to their default value. This is not optimal for all use cases, for example my fx chain use case. Because what is happening is my synthesis generators are being reset to their default state, and the only way I can see how to avoid this is by iterating over all controls I do want to edit, and calling .setValue and then .changed() on them... which is actually quite slow it turns out.

                          Could anything be done about this???

                          Musician - Instrument Designer - Sonic Architect - Creative Product Owner
                          Crafting sound at every level. From strings to signal paths, samples to systems.

                          ustkU 1 Reply Last reply Reply Quote 0
                          • ustkU
                            ustk @Orvillain
                            last edited by

                            @Orvillain I'm not certain my brain gets all this so pardon me if it's not helping...
                            But can't you do it the other way round, saving the module state with addModuleStateToUserPreset and then restore the UI components from it with updateConnectedComponentsFromModuleState?

                            Hise made me an F5 dude, any other app just suffers...

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            21

                            Online

                            2.2k

                            Users

                            13.4k

                            Topics

                            116.3k

                            Posts