Reliable folder for shipping presets with a plugin

Hi everyone,

This is the first plugin I am shipping with presets and the loading and saving are working fine. I am using File::SpecialLocationType::commonApplicationDataDirectory as the directory for my presets. The documentation for this location is sort of vague in the sense that there are expressions like “could be something like” and “depending on the setup”. I would like to ship the plugin with the XML preset files and install them in a location where the plugin can find them reliably. Of course, I know where the commonAppDataDirectory is on my PC but will this be the same for every machine? I have noticed that almost all manufacturers install their presets in that very folder so should I just use this file path in the installer and hope for the best that every machine has it and that it isn’t read-only? So I guess what I am asking is how will I make sure that after the installation the file location where the presets are installed and the location the plugin is searching them from, match? Or should I take a different approach and create the preset files when the plugin is first opened therefore dynamically finding a good file location for each machine? Seems unnecessary to allocate all that memory for each instance of the plugin though. Any advice would be highly appreciated.

The documentation for this location is sort of vague in the sense that there are expressions like “could be something like” and “depending on the setup"

I noted that this week. I wanted to submit a PR to clean this up, as this is a good example of a place where the docs accidentally obscure instead of clarify, resulting in extra homework for every dev.

Of course, I know where the commonAppDataDirectory is on my PC but will this be the same for every machine?

Rabbit holing through the source, we can see Windows maps it as CSIDL_APPDATA

Windows has a couple dozen “Special Folders” and these CSIDL (Constant Special Item ID List) values are a proxy for where those special folders actually are on any version of windows.

Aside: CSIDL is what JUCE 6 uses, but starting with Vista, Windows deprecated these and switched to use KNOWNFOLDERID and calls them “Known Folders.” Not sure how far back JUCE 6/7 supports windows, but these could be updated when XP is no longer supported.

Anyway, the short story is that CSIDL_APPDATA maps to FOLDERID_RoamingAppData which has a “Default” value and a “Legacy” value:

So as of Vista, this means that File::SpecialLocationType::userApplicationDataDirectory will map to C:\Users\username\AppData\Roaming.

So I guess what I am asking is how will I make sure that after the installation the file location where the presets are installed and the location the plugin is searching them from, match? Or should I take a different approach

Even though these folders are pretty standard, it’s also common that people bundle their factory presets into their binary to avoid dealing with… questions like this. In some way it… feels like a bummer to be doing this in 2022, but this is the route I’m taking as well (for the same reason, to avoid needing to do anything fancy in the installer, check for the existence of files, etc). I’m using CMRC to load in folders of preset files in JSON and then storing my user presets in FOLDERID_RoamingAppData.

Whups, looks like I read your post wrong. You were looking for commonApplicationDataDirectory and not userApplicationDataDirectory.

commonApplicationDataDirectory maps to CSIDL_COMMON_APPDATA which maps to FOLDERID_ProgramData

I’m not sure where people are storing factory presets on the file system in Windows, but this seems like a fine candidate to me?

I have a blog post series I’m working on titled “Why are audio plugin presets so janky?” and this has motivated me to try and wrap it up :laughing:

2 Likes

Thank you Sudara for the reply. I’ll have to take a closer look. Bummer these things are always a little bit problematic.

I took a first crack at improving the documentation: Correct and clarify SpecialLocationType documentation by sudara · Pull Request #1058 · juce-framework/JUCE · GitHub

I also want to retain the folder structure for my plugin’s factory presets (user browses presets using popupmenus). I was thinking of adding a .zip of the factory presets folder as a binary resource in projucer, and then unzipping and copying the files on first open to commonDocumentsDirectory and also doing the same whenever the user wants to restore the factory presets (by pressing a button). Is this more or less how you bundled the factory presets into the plugin binary but with CMRC instead? Is there a particular reason you used CMRC over something like a .zip (perhaps I’ve overlooked some obvious flaw)?

This is a pretty common path.

I liked the idea of not bothering with the filesystem at all across platforms. CMRC let me just toss my presets into my /presets folder and then they are available in the binary, no filesystem juggling, no disk access when loading, etc. I have subfolders within presets that auto map to categories.

That being said, my presets are adding up. Theoretically I should feel some pressure around the in-memory binary size slowly ballooning:

➜  presets git:(main) du -h
1.8M	./09 Metals and Perc
1.4M	./02 Pads
2.2M	./03 Leads
1.7M	./05 Pluck
1.8M	./10 FX
1.3M	./07 Bass
1.4M	./06 Slow
308K	./01 Basic Shapes
508K	./04 2 Hands
1.4M	./08 Rhythmic
 14M	.

Ah I see, yes it would be nice to bypass the file system altogether (as long as memory isn’t an issue). Do you facilitate users creating and saving their own presets? If so do you save user-created presets using applicationproperties or something?

I personally use a custom json format via nlohmann (identical to factory but stored on the filesystem).