HISE Logo Forum
    • Categories
    • Register
    • Login

    Custom Mini Preset Browser Example using FileSystem API

    Scheduled Pinned Locked Moved Scripting
    17 Posts 9 Posters 1.3k 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.
    • Casey KolbC
      Casey Kolb
      last edited by Casey Kolb

      Hey folks!

      This seems to be a hot topic with the new FileSystem API, so for those who need a starting place for building a custom mini-preset browser in HiseScript, here's a simple snippet showing how to achieve the most basic steps for:

      • Loading presets from the user preset directory
      • Saving a set of controls to a file in the user preset directory with user input for the preset name
      • Fetching all preset names in a given directory and displaying them in a viewport
      • Showing the preset directory
      HiseSnippet 2295.3ocsZ0ziaabFd3tKCrjsRrcC5odfXOoscqhVWmzFajZ48q1MwqWUK6Ew0wMlhbzpIhhi.GpcsRvhZfdnWxk.zS8TAxgh.TTTzeAEnsW5ugV.+SH28A224CRNbHor1EwBvFly7Ny6y6Gyy7Ny3tQTOLiQiPV0t+rIXj0kr6MKLd3VCcIgn81FYcA6tQXFNFs4rItLF1GYYs7uf2qUsUPhee6s1zMvMzCm0DBcHk3guCYLINq0tc9HRPvtt936SFqI806rmGMbKZ.cJfjksail35Mx8H7cc4hsjMx5M1wmDSi5E6FiYHqU1j5Oq2P5IgR4OjvH8Cv7O1.0ClHYy6RC74Hl2JZqgj.+tIVLCAyR2L6eYo8+116S7Iosm4GtrnCmrQn6OrVZdvaCc30dwgmkF7VQBuqX2yKhLINqGN1tn8dgw3nAtPHPGVRYQKc5aYuEEjHLt0X2Q3cifORGQy2qc60cd21sW6lMp2n967NNbYinALmXpSerCy8XruCIzYhHQnQcHVwhcN1MxoW.waD7W93HmOvIQGGgi2hNdBMD9n4pZxrJWEYidSr6zXxfoAaNMNlFV4LXH2pRfJf513AjPLywMHvwKA1tg9NdPK8gjHly.ZjB4N8inmvvQMpGB4ULHGC6HSt2T1gyWzntC7KChxtuCA9rJzkIh.X7wm0TKFWVAt1Rgnlzvr9U8kLPS0ySgjBKRUliS1PvTnX1Q4.xTpWErfLBo3UCnTQxfRZSU.hz9WX0evjXBz7BfBkjoforY69j3.7BLWB4JYlj8x4rtOkK8qHkISvUmmkdvn4BoCFkyAevnpctGLRywVlp1hShGLW0IEImJkMUsZk8WZLcBcxz.fxLaAQy7B.Kw6pjgkrJ9XB9jIzHX47LmA3XugjviDD.CHP3SrzlyVEOD67.XQsJQ0mDg8.J5YxIlDF.DGNClF5wSLJEIIzA7eATfQQgf6JTwGnh2+RftI.VXIfRVjkAVR5nySHzbURLdLa000muVeFkD1b0OAn2TC7TcGgIdKgDooWRnZcHhFLEWhAHTL.8TQ4g3D7rVK1j.RrDD2rTSufUGPc8ULGf2uoXhdjP6ONIRx+kkbbHuOVS4zkHxo2b91ZE7Sy2hICbZpZMOlYFyVyEFFlLTyG.EXeDZNYnR4OCZNc46Ba1ZsVVNbZvLiIRlNDieZFsc9b3TeXpsIh6YS55NGYFqWybpxuSfPplCbCX34Hn2P2viv9MMEYNTHZKhVD+aNdpEMxNGCXNfe9vonCTW2Q33oQglw1bkYcC8By3gTIBWaciwXVX0MLKISarYdzEfcpvxce2X27dPM.l5B4R0RqGcuoIxxOHidSXPqeppNQnd4igYjkBQYcgb1KwtGPEiPFM+ep3436k.xDQGK1HQr0BaFCn2JV8nZMQh4UR3LOaSIQS9hndhom6xUBp0X1FYr76NTulo5JtOjyWTuVM8E+7c.zlbnDZe9mrlEf55Nq9CaIGDrcUbDmwxXxR1M7QOl2C2q1T3sROv.aMn8Z5a0MYJanPnVwzdwQfau4FBRBPN3OJeh1HfY9z5EMUiMexFPQSlKvYvp0HI+QNqVhGHGF4SyiZ+Xwlg2lcP+OCpzfu8eofdNLmpUIkC8BnTTcF+PiFyiNhEXMaZZcRDrCsBfBsUAHylscdJPoxJ3aU1+4CTsHLQ2U5hJrAsPmEUFWP0rbpFa9cofQFBbVvnpeZcGytFLnz9TTVA7otjt42YQz7FXyvoi6iiR1vHQP3v64uc.6puc.8KuvSVDtlfzv8BIPwD3vpty.jpxcDxZIEp.QiE2cvapt6.I2Jh3irZXqw1hDvleqLVHzy+5I+uagpZJjrrho3J1FbuYSSxUAgdvdaC4Z7azPAO.xSvQwDt2vZa7wDOr79MpYuMlMJlNQfe0NvHq5R02H41ObCwABs+V14N.O5oo58eD0YlNHNg3GOTu2gXxQCytbpN+1N8OJ4Jnp8Fu7kuTzLuTnhsxKyMqUFa5I4a8Z7lgV9c7lsr0rjZ4sj631WYIeekk3jbWDhSYpYPn2maP1V+cKSioC0zXP62YhaDnPMMa5p3VF+ZsxqVz.HB0i744tcNTwPQIYBW01rLcczumd33i6H0dCwPbTRSX6SGCJwMBD0Zo7FI5gc3Lm6oN2C+5sdklnoW4mmyRpUokbI6rZ2zrgm3UgMvOquR5BftHFNylgNnunDzWUAZr+gpSCq.dVYvU47exS5jGj+IhIHedzYGjhS9grVydyHWW2w02hRC5EOcvfr+00pu6zvQy1mFNBOCMkgEvDhz5K7788kqwzz0kpZ4+2ytvYrpLm6sMLaTAytyCVrUMYfMgbQ2.RZKOGwW9k+w1kvQjz7wIaAXsr0JKBcwUrMtOJM69Yali5yvtcdRgbxqWztKyyJy2eS878agvvVatJnOmXVFxups4gNKPxk8Qdn+79Ef96uXPWO.8Ue0e3uURnX3P5KJF2fF9m7VKRKttZ8+kryRvQKFS4ErkmmW2v+05F9cLL7m8qNuFtDiqXCJybIsAc6hAcI0n7nxUF29tF9WvVovytITjyntcx6anieD5rVsP97j+8+4EkUCve9u7eOoJBhxoRrVt53PkUtos1+P8.gIUO52XZHOqaw.glGRG223F+qGThIdu68Munn4LZzWWfF+hmghHqvhdVvq1h9nE1ht8s+qkYQe3G96KgI3gO7aFjXmbVrTD6nfLZQ3subJRJVf200Lzu8y6bdJxSyPk37GnoOp3Job1KLoXkRq0q3iNdY68o97KYK+6gxeDXUGvZ0bO7H+wECYj3Y5OR7qkGIcQg6Ur6Rh8FVNdWpD7xOA0qY7pdx4F16LX.bf7Lvth8te7q+2WFcOJj.Gdz9twQDHMz9tSG2CR18v.RBA5R9QUARU9PEe2l+M2yzCG5K9.NOzKUctA+aKUmajzIZrqWD8SSdZVvodAQK.lBEuseM684e6rQxwFssa2pMZLwm7oddbWwOFvd4i4Zmiw7SNGi45miw7tmiw7dmiw7SOGi4mM2wv+u4vsmFSGKWl.MzcGww2sr1IjWomHiD8+gi7rcn
      

      Hope this is helpful! 😀

      A few extra things to consider:

      • This example saves the preset files in a certain format (key-value pairs), but it's up to you to choose how you'll save your controls and load them from your custom preset files.
      • This is completely separate from the built-in preset browser, so proceed with caution. The actual HISE user presets are formatted differently.
      • This doesn't include any protections for overwriting files or checks for invalid files / objects loaded.

      Casey Kolb
      Founder & CEO of Lunacy Audio
      Composer | Producer | Software Developer

      ? Dan KorneffD musictopM 3 Replies Last reply Reply Quote 13
      • ?
        A Former User @Casey Kolb
        last edited by

        @Lunacy-Audio Great. It will help me to learn.

        1 Reply Last reply Reply Quote 0
        • Dan KorneffD
          Dan Korneff @Casey Kolb
          last edited by

          @Lunacy-Audio "beautiful button" and "slick slider" 😁
          Love it!

          Dan Korneff - Producer / Mixer / Audio Nerd

          1 Reply Last reply Reply Quote 2
          • B
            BWSounds
            last edited by

            @Lunacy-Audio
            Nice work! Im still having an issue with exporting midi using

            MIDIPlayer.saveAsMidiFile("{PROJECT_FOLDER}FileMIDI.mid", 0);
            

            Been trying to figure it out for over a year now :/

            1 Reply Last reply Reply Quote 0
            • musictopM
              musictop @Casey Kolb
              last edited by

              @Lunacy-Audio i wonder if this can be used/modified to make a preset system for an arpeggiator part of the synth, in paralel to default preset browser?

              my website: https://musictop69.wixsite.com/ilirbajri
              https://musictop69.wixsite.com/creatools
              https://musictop69.wixsite.com/orchestools

              Casey KolbC 1 Reply Last reply Reply Quote 0
              • Christoph HartC
                Christoph Hart
                last edited by

                @BWSounds Have you tried this:

                FileSystem.browse(FileSystem.Desktop, true, "*.mid", function(f)
                {
                    MIDIPlayer1.saveAsMidiFile(f.toString(0), 1);
                });
                

                Track indexes are not zero-based (super confusing, but it's the MIDI standard) and you need to convert the file object that is passed into the result function to a String containing the full path.

                B M 2 Replies Last reply Reply Quote 4
                • Casey KolbC
                  Casey Kolb @musictop
                  last edited by

                  @musictop I think that would be precisely the use case for this kinda thing! This will work best for smaller sub-presets within a larger plugin.

                  Casey Kolb
                  Founder & CEO of Lunacy Audio
                  Composer | Producer | Software Developer

                  musictopM 1 Reply Last reply Reply Quote 1
                  • B
                    BWSounds @Christoph Hart
                    last edited by

                    @Christoph-Hart
                    Legend 👐 👏

                    1 Reply Last reply Reply Quote 0
                    • musictopM
                      musictop @Casey Kolb
                      last edited by

                      @Lunacy-Audio great! Thank you.

                      my website: https://musictop69.wixsite.com/ilirbajri
                      https://musictop69.wixsite.com/creatools
                      https://musictop69.wixsite.com/orchestools

                      1 Reply Last reply Reply Quote 0
                      • DalartD
                        Dalart
                        last edited by

                        Nice one, this will be useful. thanks for sharing. :)

                        1 Reply Last reply Reply Quote 0
                        • M
                          Mwins @Christoph Hart
                          last edited by Mwins

                          @Christoph-Hart said in Custom Mini Preset Browser Example using FileSystem API:

                          @BWSounds Have you tried this:

                          FileSystem.browse(FileSystem.Desktop, true, "*.mid", function(f)
                          {
                              MIDIPlayer1.saveAsMidiFile(f.toString(0), 1);
                          });
                          

                          Track indexes are not zero-based (super confusing, but it's the MIDI standard) and you need to convert the file object that is passed into the result function to a String containing the full path.

                          @Christoph-Hart I have a project that allows users to drag/drop midi files onto the interface and the plugin plays the files. This looks like what I need to actually save those MIDI files so that when the user saves their project in the DAW and re-opens the project, those MIDI files are still available. Currently, the files disappear on reload of the plugin unless they were compiled with the plugin.

                          Could this be used to save and recall multiple user MIDI files? Then, to recall multiple midi files on init, could setFile be used?

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

                            No if you want a midi player to be restored with the user preset you will have to connect it like a EQ with this:

                            Link Preview Image
                            HISE | Docs

                            favicon

                            (docs.hise.audio)

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

                              @Christoph-Hart So I've built two mini-preset browsers (thanks @Lunacy-Audio!) within the same plug in. I'm basically trying to save an LFO shape using one of the browsers, and then load it into a second LFO using the second browser.

                              Everything works, except that when I save a new .preset file in one browser, and then go into the second browser to load it into the other LFO table, the preset list has not updated to include the new .preset file.

                              So basically I'm looking for a callback function that will fetch all the relevant preset names to populate the list. I'm pretty sure its all in this script, but when I try and load bits into a button callback, I get errors.

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

                              1 Reply Last reply Reply Quote 0
                              • Casey KolbC
                                Casey Kolb
                                last edited by

                                You'll need a timer for this sort of thing where it repopulates the list every so often, like every 2000 ms or something. You could also add a refresh button like the one you describe for which you'll just need to add a button callback and then add the function populatePresetList() to that callback from the original snippet above.

                                The timer approach will require some more testing. I tried this in one of my projects and it would occasionally crash the plugin, but worth a shot!

                                Casey Kolb
                                Founder & CEO of Lunacy Audio
                                Composer | Producer | Software Developer

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

                                  @Lunacy-Audio Yeah I looked at a timer but then realised a callback would be perfect. I tried to use populatePresetList() but kept getting errors.... said it wasn't a function.

                                  inline function onLOAD_LFO1Control(component, value)
                                  {
                                  	TABLEBROWSER1.showControl(1);
                                  	LFOCLOSE1.showControl(1);
                                  	populatePresetList();
                                  		
                                  };
                                  
                                  Content.getComponent("LOAD_LFO1").setControlCallback(onLOAD_LFO1Control);
                                  
                                  

                                  This is the callback on the button which brings up one of the browsers. If it refreshes the list at the same time that solves my problem. It felt a bit crude just sticking in populatePresetList(); and looks like it was :face_with_tears_of_joy:

                                  Interface:! Line 386, column 20: This expression is not a function! {SW50ZXJmYWNlfHwxMjQwOXwzODZ8MjA=}
                                  

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

                                  1 Reply Last reply Reply Quote 0
                                  • Casey KolbC
                                    Casey Kolb
                                    last edited by

                                    Ah, I forgot to mention you just need to include the namespace that encapsulates the function, so PresetBrowser.populatePresetList();. Anything outside the PresetBrowser namespace doesn't know what that function is.

                                    Casey Kolb
                                    Founder & CEO of Lunacy Audio
                                    Composer | Producer | Software Developer

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

                                      @Lunacy-Audio Brilliant thank you!

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

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

                                      49

                                      Online

                                      1.7k

                                      Users

                                      11.7k

                                      Topics

                                      102.2k

                                      Posts