Cabbage Logo
Back to Cabbage Site

Ideas for saving generic data in DAW sessions

I think I solved the riddle using a prefix for the json identifier that I concat as a global String var at k rate with the actual identifier name for storing changes. In the example I initialise the prefix as “init_” and then I change it to “perform_” in an instrument that gets called with a bit of a delay. The first k-cycle parses the initialised empty array to the identifier with the “init_” prefix and the stored data under the identifier with the “perform_” prefix stays intact. Did it only for Slider2 while Slider1 has the old solution, that doesn’t work anymore.

gkslider1Array[]    init 10 
gkslider2Array[]    init 10

gSprefix    init "init_"

instr 1
    
    kNumber init 0
    
    kNumber = (changed(chnget:k("next")) == 1 && kNumber < 9)? kNumber + 1 : kNumber        // change active index 
    kNumber = (changed(chnget:k("prev")) == 1 && kNumber > 0)? kNumber - 1 : kNumber        // with buttons
   
    if( changed(kNumber) == 1 ) then 
        String          sprintfk    "text(\"%d\")",kNumber              // index
        cabbageSet      1,    "number", String                                                
        cabbageSetValue "slider1",gkslider1Array[kNumber]
        cabbageSetValue "slider2",gkslider2Array[kNumber]
    endif
    
    strset 1,"dummy"
    
    kslider1     chnget "slider1"
    if(changed(kslider1) == 1)then
        gkslider1Array[kNumber] = kslider1
        
        SIdent  sprintfk "%s", "dataSlider1"
        SIdent  strget 1
        
        cabbageSetStateValue SIdent, gkslider1Array
    endif
    
    kslider2, ktrig2     cabbageGetValue "slider2"
    if(changed(kslider2) == 1)then
        gkslider2Array[kNumber] = kslider2
        SIdent  sprintfk "%s_dataSlider2",gSprefix
        cabbageSetStateValue SIdent, gkslider2Array
    endif

    if( changed(chnget:k("print")) == 1) then                                               // call instrument to print the stored data
        event "i","printStoredData",0,0
    endif

endin

instr   printStoredData
    prints "\n\nPrinting using readStateData\n"
    prints cabbageReadStateData:S() 
endin

instr   enablePrefix
    gSprefix    sprintfk "%s","perform_"
endin

and then in the score:

i 1 0 z
i "enablePrefix" 0.1 0.0008

Seems to be working with your current version.
And it’s even shorter than the old solution.

Implemented this method into my plugin and it works perfectly. I think I’m just going to keep it that way. Feels very safe.
So there’s a solution that works, in case you don’t want to break your head over this.

1 Like

Something like this actually works as well:

gkPerform   init 0
instr 1

SIdent  sprintfk "%s", (gkPerform == 0)? "dummy":"dataSlider1"
cabbageSetStateValue SIdent, gkslider1Array

and with a delay:

instr   startStoring
    gkPerform   = 1
endin

Weirdly the init write doesn’t happen on identifier “dummy”, but on “” which means that (gkPerform == 0)? doesn’t get queried in the initialising k-cycle, so SIdent stays NULL. Still the actual identifier doesn’t get overwritten so it works and I only produce one more json array and not one for every array.
Maybe it could be interesting to have a global variable in Cabbage that is set to 1 / true after the init k-cycle. Is that possible?

I guess, but it’s the kind of thing one can easily do in Csound?

Hey Rory,
I was coming across some problems with some serious CPU spikes using the cabbageSetStateValue opcode. I optimised everything to work very efficiently. For example when changing data with a slider I don’t write the state data on every change anymore, but only when I release the mouse button, so I’m not storing state data many many times because I’m moving a slider but only after I made my setting. Or if I’m skipping through different programs (in my case sample slots with individual settings) I set a “skipping” - flag so the sudden changes of all the sliders don’t trigger the storing of state data of every single slider.
I kind of fixed it, but randomly occasionally I still get a CPU spike from the opcode. It’s hard for me to reproduce this in a simple example because it’s likely that it is also connected to the monstrous size of my code. Having had multiple instruments running in parallel contributed, so I had to put some stuff together into one instrument. I can still tell that it is definitely connected to the cabbageSetStateValue opcode, as I don’t get any CPU spikes when I take those out.
Did you come across any issues with CPU load on those opcodes yourself so far? Is there a way you could evaluate / examine this somehow?

The quick answer is no I haven’t, but I haven’t used them much. I’ll go over the code and see if I can optimize it better. I’ll let you know when I have something :+1:

I just had a look through this here. I pushed a small improvement, but I’m not sure there is much else I can do to optimise it. What causes the CPU spike is parsing and updating the JSON data. I would definitely advise against updating on each cycle. That’s why I used changed() in the example code to trigger an update.

When I wrote this opcodes I was thinking of them being used for those rare case where non-widget data would need to be saved. I think you are taking this to the next level?

Thank you for looking into this. I’ll try and see what’s happening. Yes, I guess I’m doing a bit of a stretch here with the individual settings that switch on every sample I play, storing arrays of data with that opcode. I’m using the opcode as sparse as I can now through even only store a change of state data after I lifted the mouse button from the sliders. That seems to be working almost always without getting a CPU spike. At first, when I stored the state data on every slider change, moving the slider was literally holding my CPU meter at 100%. Now when I lift the mouse button after doing a change I get usually just a 1% change. So it works well apart from some very occasional spikes. Also it seems different in different DAWs. Reaper seems to be handling it better that Studio One for example. One interesting thing I noticed that it actually gets better if I set my buffer to 32 samples and below. Decreasing it from higher buffer sizes to 64 samples would have the expected result of it getting worse, but then with 32 and 16 it got better again. I wonder if that could have anything to do with my 32 sample k rate (and maybe having one instrument that runs on ksmps = 1 additionally). Anyway, I’ll manage. Just thought I share my experience with you and I’m curious about your change!

I find the the ksmps is related to the buffer size it usually help performance. I set the default ksmps to 32 because over the years this seemed to give the best overall performance without draining too much CPU.

Just curious what the use case is here in comparison to snapshot saving? As the DAW already recalls all of your cabbage plugin settings.

These are for times you might want to save data that is not associated with a widget. For example, you may have generated a sequence of notes that you want to save when the sessions is saved. Or a particular drum pattern. Anything that isn’t exactly tied to a widget.