Serializing file references in a platform independent manner

We’re adding preset loading/saving support to an audio plugin, and the presets contain references to a number of audio files. We would like all presets to work across platforms, of course, so we would need to store the file references in a platform independent format.

Is there already something in JUCE that takes care of this, or will we have to roll our own solution?

It feels like it would be a pretty common problem for plugin developers to solve. :slight_smile:

Yep, check out File::getSpecialLocation. :slight_smile:

As mentioned, the File class provides methods for defining your filepaths in a cross-platform manner, and then you can use something like the XmlElement or ValueTree class to store the data as XML, or the DynamicObject and var classes to store the data as JSON.

I thought I remembered seeing a tutorial or example project that included presets, but I’m not seeing one after a quick search. The DemoRunner app in JUCE’s “examples” folder has XML and JSON examples, though.

Thank you for the replies!

Yes, I’m aware of the special locations, they are really useful for determining the base directory!

What I’m thinking of is the path string itself, that I’m guessing will use either ‘/’ or ‘\’ as file separator depending on which OS the user was running when they saved the patch. I want to ensure that a patch created on Windows can be opened without problems on macOS and vice versa. :slight_smile:

So I think I will just “normalize” all path separators to ‘/’ and make sure they’re converted back to ‘\’ when loading the state on Windows.

The stored file paths will mostly be relative (since an absolute path is almost sure to break when changing platforms).

There will be a “factory sound bank” that ships with the plugin, so I will probably handle that path specifically. So if a user loads a sample from that directory it will be a distinct “reference type”, something like “{presets}/Samples/AAA.wav”, or <location=“presets” path=“Samples/AAA.wav”>.

For the case where the audio file exists in the same directory or in a subdirectory of the patch location, we can just use relative paths.

For the case where the user loaded a sample from a completely different folder or even another disk, I’m not so sure. Either we store the absolute path, making the patch basically impossible to export, or we copy the audio files…

The “safest” way would probably be to always store the audio files with the patch, in a zip archive or something like that, but the files can be very, very long so I’m not sure it’s something that users would appreciate…

That’s what the juce::File class does internally anyway afaik :slight_smile:
You can see in Projucer, where you can set paths even for windows using \ and / interchangeably.

Also helpful for the use case of relative paths is getRelativePathFrom (juce::File& rootToBeRelativeTo).

1 Like

I used both of the these approaches myself, perhaps there is a better way, but this seemed so obvious and fairly safe. The only thing I came up against was if the need to change paths in more than one place crops up it’s worthwhile creating a static method to do the conversions to them so that you’re not duplicating code and creating possible bugs in the future by forgetting to change all the occurrences if needed.

My approach here was to just store the absolute path by default, but also offer a “collect and save” option that would copy the referenced files and preset to the user specified location, the path would then be stored as {base_folder}/sample.wav and replaced based on where the preset was loaded from on the other machine.

Thanks for these tips!

A “Collect & Save” option sounds great!
I guess this is something that’s best presented in the save dialog box? But that means I can no longer use the standard OS file chooser, right?

I guess absolute paths for “non-factory” sounds are unavoidable, especially if the user relies on the DAW to remember the state rather than saving a patch.

I just did it as a separate option in my preset menu, so I have options for Load, Save, Save As and Collect and Save, then I can just use the OS file chooser for all but the Save option (which doesn’t need any kind of prompting for where).