Cabbage Logo
Back to Cabbage Site

cabbageChannelStateSave relative file paths?

Is there a way to make file refs relative (same schema as the dedicated channels) instead of absolute - for portability?

They should already accept relative paths. For example, if I do this, it will save the file in a directory two up from the current dir:

kOk = cabbageChannelStateSave:k("../../preset.pres")

Is this not working for you? I just tested here.

I’m referring to the actual data stored in the json…
All of the file paths are absolute and system specific.

So a combobox path reference is stored as, for example:
/Users/username/Music/Folder/App/Effects/FilterVerb.orc

Is there a way to store this as
~/Music/Folder/App/Effects/FilterVerb.orc

Yes, that’s because all comboboxes internally convert relative paths to absolute ones. Not just comboboxes, but all widgets that deal with paths. It’s the same with the native preset system. It would be quite a job to rewrite all of that code to use relative paths.

This isn’t actually a relative path, as you know it’s just a reference to a home directory, which gets converted to an absolute path. If we were to use relative paths it would look more like this:

../../../../MusicFolder/App/Effects/FilterVerb.orc

which would then be completely dependant on where the user is running their application/plugin from. Plus, Windows doesn’t have any such reference to the home dir. So in that case this won’t work either.

What’s the use case here. Are you trying to produce custom presets that store paths in the user’s home directories? And I guess you want to make sure the plugin can find those directories, regardless of the system, or where the plugin is installed? :thinking:

I guess you could simply get the user path when the plugin starts using the reserved channel (chnget:S("USER_MUSIC_DIRECTORY")), then parse the absolute path from the combobox for it’s name (cabbageGetFilename), concat it to the user path and hey presto. It’s a bit of a leap, but that should work on all platforms?

Yeah, as with all of our content, it comes with a batch of presets.
I will try as you suggested… thanks.

@chronopolis I was just thinking about this again. You could run a bash/bat script with your installer that would change all the paths in your preset files to point to the users absolute home directories. So you could develop the presets there, which would all point to ~/Music/Effects/FilterVerb.orc. Then when installing the system the script would replace all instances of ~ for the user’s home path. This would also allow you to move seamlessly between Mac and Windows.

That sounds like an interesting solution…

Not sure what that is - I’m such a phony “developer” :laughing: but will look into it. I can usually hack my way through something like that…

I know you use Python for this kind of stuff at times, but then you need to make sure they have that installed. Bash is available on all Mac system, and .bat processing on Windows. They are the least common denominators for those systems. On the other hand you could write a simple executable application that did the work for you. That would be another option. Either way, I think it might be simpler than screwing with the system you have already implemented.

Cool. So at what stage would this be implemented? I assume we are talking about rewriting the paths in the json (preset) file on installation to correspond with that particular user’s directory structure?

Could I batch rewrite the json on my end (with python) so that the paths are relative (one for OSX and one for Windows), and bundle those with the respective installers?

So for example
OSX json preset :
"EffectList": "~\/Music\/Folder\/App\/Effects\/File.orc"

Windows json preset
"EffectList": "C:\/ProgramData\/Folder\/App\/Effects\/File.orc"

Sort of off-topic… but any recommendations where to store audio content/samples in Windows? Where do most manufacturers put it?

That’s what I was thinking yes. So replace all instances of /Users/Username/ with ~/. Then when installing the system on a target machine, grab the user home dir and replace all instances of ~/ with it.

If you want users to be able to both read and write to a folder on Windows it should really go into the C:/Users/Username/AppData folder somewhere.

Yes. The script should run just after installation, and should touch all the paths in the installed preset JSON files so that each ~/ path gets expanded. I have to say though, it would be nice to only have to prepare one solution for this, rather than potentially having to write a different script for both MacOS and Windows. I’ll think about it further maybe there is a more cross platform solution.

p.s. I know you use Python a bit, are there not ways to generate standalone binaries from python scripts? That would surely be the easiest way. You could then just run the Python application after installation…

Maybe just a simple opcode could do the trick? This is untested and probably syntactically incorrect but this is the idea…

    opcode rewriteFilePath S, SS
         SoriginalPath, SlocalDir xin
         ipos   strrindex SoriginalPath, "/"	;look for the rightmost '/'
         Sfile   strsub    SoriginalPath, ipos+1	;extract the file name
         SnewPath strcat SlocalDir, Sfile
         xout SnewPath 
    endop

instr 1
 kOk = cabbageChannelStateRecall:k(SPresetFilename, SIgnoreChannels)
        ;update channels accordingly
        cabbageSet kTrigRecall, "Sample", rewriteFilePath(chnget:S("Sample"), chnget:S("USER_APPLICATION_DIRECTORY")
endin

Yes, i get the idea. But maybe you should return SoriginalPath if it already contains SlocalDir. Let us know how it goes. It would certainly be simpler than the alternative!

Not sure I understand. SoriginalPath would be from the preset creator’s computer so we can only use the file name from it. LocalDir would be the preset users path so I’m just appending the file name to the new path.

Actually this is turning out to be even easier than I thought… :roll_eyes: at least list boxes apparently don’t need the full path so it’s just a matter of getting the file name.

SoundSelect = cabbageGetFilename(chnget:S("Sample"))
cabbageSetValue "Sample", SoundSelect, kTrigRecall

Nice one. That was a lot simpler than I thought!

Indeed. Drama averted… :laughing:
The built in Cabbage opcodes have everything you need for portable combobox/listbox recall. :beers:

1 Like