Forum
    • Categories
    • Register
    • Login

    Custom browser - custom preset file format???

    Scheduled Pinned Locked Moved General Questions
    28 Posts 6 Posters 840 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.
    • OrvillainO
      Orvillain
      last edited by

      @Christoph-Hart I'm looking at this again. Before I begin, is there a decent snippet anywhere that demonstrates how to do this for a simple plugin?

      Also, what are the gotcha's to watch out for? You mentioned killing voices, loading on the background thread, etc...

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

      Christoph HartC 1 Reply Last reply Reply Quote 0
      • Christoph HartC
        Christoph Hart @Orvillain
        last edited by Christoph Hart

        @Orvillain nope, I'm using it in Triaz, but I haven't made a public example yet, but it's a good idea to do so. The problem is that it cannot be encompassed into a nice simple snippet as it requires additional data (preset files) to be useful.

        Just from thinking about it there are a few things to watch out for:

        • initialisation order. Usually you can decide what you restore first by rearringing your script function, but be aware that restoring module states for whole HISE modules will always come after this method.
        • the function is being executed synchronously in the loading thread (but it should take a lock to prevent simultaneous execution of scripting tasks in the scripting thread). You can safely assume that there are no voices playing during this function call (because it kills all voices when loading a preset).
        • The XML -> JSON conversion is a bit weird because the data structures are not 100% convertible, so there are a few edge cases to consider here. You'll notice when you run into them :)
        OrvillainO 1 Reply Last reply Reply Quote 2
        • OrvillainO
          Orvillain @Christoph Hart
          last edited by

          @Christoph-Hart

          Hey Christoph - I've not really got my head around this yet, and my client is requesting multiple types of preset. They want effect chain presets as well as full state presets. They also want to be able to add meta-data and copy samples along with the preset.

          Does that mean I'm going to need custom data models for each type ??

          I could really do with a simple tutorial that shows some of this stuff 😁

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

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

            Here's what I've figured out so far:

            namespace PluginUserPresetHandling {
            
                const UserPresetHandler = Engine.createUserPresetHandler();
            
                
                inline function onPresetLoad(obj) {
                    Console.print("we just loaded a preset!");
                    if (obj.presetData.ui)
                        UserPresetHandler.updateSaveInPresetComponents(obj.presetData.ui);
                }
                
                inline function onPresetSave() {
                    Console.print("we just saved a preset!");
                    return {
                        "version": "1.0.0",
                        "presetName": "This is a magic string for the preset name",
                        "presetAuthor": "Drew",
                        "presetDescription": "This is a saucy preset",
                        "presetTags": ["Fat, Warm, Round"],
                        "presetData": {
                            "ui": UserPresetHandler.createObjectForSaveInPresetComponents()
                        }
                    };
                }
            
                inline function init() {
                    UserPresetHandler.setUseCustomUserPresetModel(onPresetLoad, onPresetSave, false);
                }
            }
            

            And this will actually produce a file that looks like this:
            ecc5224f-b00a-47c4-8a66-36b607908657-image.png

            So that's quite cool.... but something about my preset did sound different, versus how it sounded when I saved it. So I guess there's more data across the modules that I need to grab too.

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

            DanHD 1 Reply Last reply Reply Quote 1
            • LindonL
              Lindon @Orvillain
              last edited by

              @Orvillain said in Custom browser - custom preset file format???:

              @Christoph-Hart

              Hey Christoph - I've not really got my head around this yet, and my client is requesting multiple types of preset. They want effect chain presets as well as full state presets. They also want to be able to add meta-data and copy samples along with the preset.

              FX Chain presets should be pretty simple to encode in a json data model - what meta-data and samples?

              Does that mean I'm going to need custom data models for each type ??

              yes

              HISE Development for hire.
              www.channelrobot.com

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

                @Orvillain there’s a mini preset system posted on here a while back by the lunacy guys / Casey Kolb. I’m about to take off otherwise would post.

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

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

                  Okay... starting to get a feel for this system now....

                  One thing I ran into today was trying to decide whether my menus should have their saveInPreset bool enabled or not. My menus have a callback associated with them that controls the loading of an effect and the binding of parameter knobs.

                  But because I am eventually going to be aiming at an effect chain preset format.... I figured saveInPreset should be disabled, and I should track the effect data manually.

                  I got there in there, but it did require a bit of thought. Because loading the effect networks seems to be asynchronous, so you cannot rely on the parameter knobs to be properly flushed at the right time when calling updateSaveInPresetComponents().

                  So after a lot of trial and error, I just decided to call it twice!!

                      inline function onPresetLoad(obj) {
                          local data = obj.presetData;
                          if (!isDefined(data)) return;
                  
                          if (isDefined(data.ui)) {
                              UserPresetHandler.updateSaveInPresetComponents(data.ui);
                          }
                  
                          local engIds = ["Engine1", "Engine2", "Engine3"];
                          for (i = 0; i < engIds.length; i++) {
                              local engineIdx = i + 1;
                              local smKey = "engine" + engineIdx + "SampleMap";
                              local wtKey = "engine" + engineIdx + "Wavetable";
                  
                              if (isDefined(data[smKey]))
                                  UISoundSelector.syncSamplerMenu(engineIdx, data[smKey]);
                  
                              if (isDefined(data[wtKey]))
                                  UISoundSelector.syncSynthMenu(engineIdx, data[wtKey]);
                          }
                  
                          if (isDefined(data.fxSelections)) {
                              for (k in data.fxSelections) {
                                  local fxName = data.fxSelections[k];
                                  UIEffectDropDownMenu.syncEffectMenu(k, fxName);
                              }
                          }
                  
                          if (isDefined(data.ui)) {
                              UserPresetHandler.updateSaveInPresetComponents(data.ui);
                          }
                      }
                      
                      inline function onPresetSave() {
                          return {
                              "version": "1.0.0",
                              "presetAuthor": "",
                              "presetDescription": "User Preset",
                              "presetTags": [],
                              "presetData": {
                                  "ui": UserPresetHandler.createObjectForSaveInPresetComponents(),
                                  "engine1SampleMap": PluginSharedData.engineSounds["Engine1"].sampler,
                                  "engine2SampleMap": PluginSharedData.engineSounds["Engine2"].sampler,
                                  "engine3SampleMap": PluginSharedData.engineSounds["Engine3"].sampler,
                                  "engine1Wavetable": PluginSharedData.engineSounds["Engine1"].synth,
                                  "engine2Wavetable": PluginSharedData.engineSounds["Engine2"].synth,
                                  "engine3Wavetable": PluginSharedData.engineSounds["Engine3"].synth,
                                  "fxSelections": captureFXSelections()
                              }
                          };
                      }
                  

                  This works well, if a little wasteful perhaps.

                  Part of the reason I wanted to do this is because the menu values are obviously floats, not the text value of the menu. And I knew that in the future if I wanted to add an effect type, and change the order of effects in the menu list, that this would break backwards compatibility. So I basically have a shim that will take a string and convert it to the right integer for the menu as it is in that moment, and then set the menu to the appropriate value .... which then triggers the callback to load the right effect network...

                  and then that last updateSaveInPresetComponents() call makes sure the parameters match what the preset has stored.

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

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

                    @Orvillain this all seems massively complicated for preset saving and loading, what does the existing prest management and a custom tag based browser on the front of it not give you?

                    HISE Development for hire.
                    www.channelrobot.com

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

                      @Lindon said in Custom browser - custom preset file format???:

                      @Orvillain this all seems massively complicated for preset saving and loading, what does the existing prest management and a custom tag based browser on the front of it not give you?

                      Ultimately it isn't just about preset saving and loading.

                      They want full customization of the preset data model. They want each preset to have an associated image. They want to be able to import and export presets along with sample content at the same time. Which means I need full path control over the samples when saving. They want rich meta-data based browsing and on the fly searching. When saving a preset, they want to be able to specify various tags and descriptors, and it makes sense to store that stuff directly into the xml. There's probably more they want, but off the top of my head that's all I remember.

                      Everything they're asking for seems to involve deeper control over the load and save mechanics. But it's actually not that complicated. I'm essentially overriding the HISE automatic system, with a manual system. I'm capturing nearly everything that HISE captures automatically in a single call to UserPresetHandler.createObjectForSaveInPresetComponents() - everything else is custom.

                      Unless I'm missing something, there's a lot that the stock preset management system doesn't give you.

                      After spending a fair amount of time trying things out and reading the API, I'm fairly sure I have a decent grasp of how it all works now. There are also pre and post callbacks for loading and there's a post callback for saving too, which I'm going to need to tell the system to refresh the list of presets; or to update the external database, which is probably going to be required too.

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

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

                        woohoo! I've now got a custom FX chain file format too. At least in prototype form.

                        I think I'll write a tutorial on all of this once I've properly sussed it all out. Because it is quite powerful, and no-one else really seems to have dove into this.

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

                        Christoph HartC LindonL 2 Replies Last reply Reply Quote 2
                        • Christoph HartC
                          Christoph Hart @Orvillain
                          last edited by

                          @Orvillain said in Custom browser - custom preset file format???:

                          and no-one else really seems to have dove into this.

                          I have :)

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

                            Battling a little with extension issues however.

                            @Christoph-Hart When saving a user preset am I stuck with the .preset extension??

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

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

                              @Christoph-Hart said in Custom browser - custom preset file format???:

                              @Orvillain said in Custom browser - custom preset file format???:

                              and no-one else really seems to have dove into this.

                              I have :)

                              No one else with the time to do a tutorial example ;-)

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

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

                                @Orvillain said in Custom browser - custom preset file format???:

                                and no-one else really seems to have dove into this.

                                I have too... :)

                                HISE Development for hire.
                                www.channelrobot.com

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

                                  @Orvillain said in Custom browser - custom preset file format???:

                                  No one else with the time to do a tutorial example ;-)

                                  Seemed pretty trivial really - its just taking the values you have assigned to params of a given FX and encoding those with the FX name in a json object...

                                  HISE Development for hire.
                                  www.channelrobot.com

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

                                    @Lindon said in Custom browser - custom preset file format???:

                                    @Orvillain said in Custom browser - custom preset file format???:

                                    No one else with the time to do a tutorial example ;-)

                                    Seemed pretty trivial really - its just taking the values you have assigned to params of a given FX and encoding those with the FX name in a json object...

                                    Cool, thanks for the help.

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

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

                                      Here's a handy line:

                                              FileSystem.getFolder(FileSystem.UserPresets).getChildFile("FXChains").getChildFile(PluginSharedData.lastSavedFXChainFileName).move(FileSystem.getFolder(FileSystem.UserPresets).getChildFile("FXChains").getChildFile(PluginSharedData.lastSavedFXChainFileName.replace(".preset", "")));
                                      

                                      I've got this in the post save callback. It's job is to take the FXchain file I just saved, and rename it to take off the .preset extension that HISE automatically adds whenever you use Engine.saveUserPreset command.

                                      So now I can save two types of user preset: a global state preset, with a .preset extension... and an fxchain preset that collects module information for each of my FX slots, UI parameters, and bundles it all up into a .fxchain preset.

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

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

                                        @Orvillain You can simplify your chain by including multiple directory levels in the .getChildFile calls.

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

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

                                          @David-Healey said in Custom browser - custom preset file format???:

                                          @Orvillain You can simplify your chain by including multiple directory levels in the .getChildFile calls.

                                          Ohh, more like this I guess?

                                          const base = FileSystem.getFolder(FileSystem.UserPresets);
                                          
                                          base.getChildFile("FXChains/" + PluginSharedData.lastSavedFXChainFileName)
                                              .move(
                                                  base.getChildFile(
                                                      "FXChains/" +
                                                      PluginSharedData.lastSavedFXChainFileName.replace(".preset", "")
                                                  )
                                              );
                                          
                                          

                                          ??

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

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

                                            @Orvillain Yeah that's it! I'd break it up a little more to improve the readability and to remove some repetition.

                                            const presetDir = FileSystem.getFolder(FileSystem.UserPresets);
                                            const filePath = "FXChains/" + pluginSharedData.lastSavedFXChainFileName;
                                            const file = presetDir.getChildFile(filePath);
                                            const target = presetDir.getChildFile(filePath.replace(".preset"));
                                            
                                            file.move(target);
                                            

                                            You could simplify it further by using .rename instead of .move

                                            const presetDir = FileSystem.getFolder(FileSystem.UserPresets);
                                            const file = presetDir.getChildFile("FXChains/" + pluginSharedData.lastSavedFXChainFileName);
                                            
                                            file.rename(file.toString(file.Filename).replace(".preset"));
                                            

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

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

                                            36

                                            Online

                                            2.2k

                                            Users

                                            13.4k

                                            Topics

                                            116.2k

                                            Posts