Cabbage Logo
Back to Cabbage Site

Saving Variables/Arrays in a DAW

I’m making a sequencer using arrays, and I’m running into an issue with saving sequences. If you load a Cabbage plugin in a DAW, then change some parameters, the parameters will be saved the next time you open the same project in the DAW (I assume that this happens on the DAW side, not the Csound side). If you have a variable that isn’t on screen, though, the DAW doesn’t save it (I’m also assuming that this is the case for arrays, too). Is there a way to have a certain variable/array stored this way without saving a file or having it be reflected on the screen? I’m making a sequencer using arrays, and if there’s a way to do this, it would make it a ton easier to save sequences. If not, what do you suggest? I realize that this may be completely uncontrollable in Cabbage, but I thought I’d ask. Also, I only know that this applies to variables because it’s the only thing I’ve tested so far. Thank you!

You’re right, certain data gets written to the plugin’s internal state by the DAW when things are saved. But the state of every variable is not. Have you considered writing the stuff you need to a file on disk? Csound has a few different ways of reading and writing text files. You’ll need to roll your own, but it shouldn’t be too tricky.

Let me know if you get stuck. :+1:

Okay, thank you! I think I will just write a file to the system. I looked into it a while ago, but I decided to see if there was an easier way because I’m using 64 sequences with variable length, and while I have some ideas for writing and reading this to a single file, I don’t know if my idea is very efficient. I’ll let you know if I have any problems, but I’ll try my idea for now. (My idea is basically getting the length of all the arrays, then putting them into a single array with a specific flag number in between them. I could then save that to a file. Loading the file, I could just move it to the individual arrays in order, stopping when it gets to a flag character.) Like I said, this idea might be more complicated than it needs to be, so let me know if you can think of something better. Thanks again!

That sounds reasonable. I’d say set a maximum size for each of the sequences, and use the first index of each one to set the number of used slots. That way you can write everything as a single sequence of X numbers. This should make reading and writing very straightforward.

That makes sense, and should be fairly easy to implement since I’m already storing the length of the sequence in a variable. Thanks!

Another option (tho not good for your case with quite this many variables…) I sometimes use invisible cabbage widgets to store values.

I haven’t really tested too extensively, so I might run into problems later… but so far I haven’t noticed issues. :thinking:

I hadn’t thought of that! That’ll be useful for other projects or even just storing some extra stuff I don’t want to write to the file. I think I could even store the numbers of the name of the file so that it automatically loads the file/restores the sequence. The only issue I could see arising is that some DAWs may be able to access and change the invisible variables through automation. (For example DAWs that let you select automation parameters from a list of all the parameters of a plugin). I’m not sure if that’s the case, though. I’ll definitely use this for future projects. Thank you!

Yes, I’ve been occasionally using this to store things like table numbers and gui settings behind the scenes. It seems to work pretty well, but honestly I haven’t done a whole lot of testing exported in a daw, just the basics.

Here’s an idea tho:

Rory recently added the automatable flag, so we can set a widget to automatable(0) and the daw shouldn’t see it as available. That’s the part I haven’t really tested too much as far as saving and loading in actual projects tho. So YMMV, just brain storming.

At the moment I don’t have cabbage running on my system to test any of this with, but I’ll probably dual boot over and give it a shot tonight.

I had forgotten I implemented this :rofl: Yeah, definitely use non-automatable parameters. It will make things run better as they won’t get polled on every k-boundary.

It would be possible to add some kind of persistent state stuff; so long as a users saves the plugin state via the DAW. Just thinking out loud here, but we could define a data ‘widget’, although it would be completely abstract:

data channel("sequences"), text("1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1")

We can read and write to that channel throughout the session. And have Cabbage save it along with all the other parameter data when a session is saved in the DAW? Hmm, even nicer again would be a set of simple key/value opcodes for easily reading and writing to the channel. :thinking:

@t_grey, @jason11892 I’ve added some new state saving plugins for saving data across DAW sessions. You can read about there here. Let me know if they work Ok for you.

Those look perfect! I’ll try it sometime in the next few days and get back to you.

I tried the setStateValue and getStateValue and I couldn’t get them to work. There’s a 99% chance I’m just doing something wrong, though. I’m fairly new to Cabbage, so that’s probably the case. Here’s the code I’m using as a test. I’m trying to save kVal in between daw sessions. (This version of the file doesn’t have the new opcodes in it.)

instr 1

kapply chnget "apply"

if kapply == 1 then
 kVal chnget "val"
endif
printk 1, kVal

endin

I’m just using a button for apply and a knob for the value. How would you use the opcodes to save kVal between daw sessions? Thank you!

Wow, this looks really cool @rorywalsh, especially the ability to work with arrays! I can’t test at the moment either… but assuming it works as expected, I can see a ton of utility in this!

I don’t think this quite replaces the way I was using/abusing invis widgets… but maybe that’s just because I’m doing strange things for even stranger reasons. Once I’m back running cabbage regularly again, I’ll take a closer look. Maybe I just need to change how I’m thinking about stuff on the backend.

Well you would need to set the value of kVal somewhere. Check this simple example, where ‘apply’ is a slider:

instr 99
    kApply getStateValue "applyHalf"
    printk2 kApply
endin

instr 1
    kapply chnget "apply"
    kRes setStateValue, "applyHalf", kapply/2
endin

When this code is loaded, instr 99 will return the last known value of ‘applyHalf’. You can write to the JSON data at performance time. There is no real overhead. If you like, you can use then in place of channels. I hadn’t though of that. But they wrap a global data structure. However, it would mean your code is less accessible in other Csound environments.

Now, while we’re on the subject, I’ve also included two more utility opcodes that you might also find useful. channelStateSave and channelStateRecall. These provide a single op writing of all channel data to a file, and a restoring of channel data at any point in the future. You can read more about them here. The only drawback is that they create an actual file. On the other hand, they automatically save ALL channels. I wrote these so that people could roll their own preset managers with minimal fuss.