Cabbage Logo
Back to Cabbage Site

Ideas for saving generic data in DAW sessions

Following from this discussion, I’ve started working on a system for saving generic data whenever a plugin is saved as part of a DAW session. We declare as JSON widget:

json channel("jsonData")
form ...

That channel’s data will be written to the plugin state memory whenever a session is saved. To make it easy to write and write to that string I’ve started writing a few utility opcodes. Here is an example of how they work.

instr WriteJSON
    //overwrite existing data
    iRes writeJSONToChannel 0, "jsonData", "{ \"happy\": true, \"pi\": 3.141}"

    if iRes == -1 then
        prints "Couldn't write JSON data"

instr UpdateJSON
    //updated existing data
    iRes writeJSONToChannel 1, "jsonData", {{
        "happy": true, "pi": 1.141, "test": 12

    if iRes == -1 then
        prints "Couldn't write JSON data"


instr ShowJSON
    prints chnget:S("jsonData")

instr GetJSONFloatValue
    kVal getJSONFloatValue "jsonData", "pi"
    printk2 kVal

I just wonder if the opcodes names are a little long? Note these opcodes will only be accessible in Cabbage. They’ll be baked into the code-base. I will add string, and array getters too. I’m just putting it out there now so we can decide on opcodes names and other use case I may have overlooked. I prefer to use of camelCase naming because a) it differs from the majority of Csound opcodes, which helps make it clear that these don’t belong to Csound, and b) I find them easier to read

Let me know what you think. .

Let me introduce a new set of Cabbage opcodes that will let users save generic data across DAW sessions.

Basic read/write opcodes
These opcodes perform basic reading and writing of ‘flat’ JSON object.

iRes writeStateData iMode, SJSONData

Will write JSON data to the plugins internal state if it saved in a DAW session. It lets you overwrite the existing data, or update it.

SData readStateData
Returns a string that containing all current state data

Value reading/writing
These opcodes let you read write and access values from the JSON data structure. While writeStateData (see above) lets you write chunks of JSON data in one go, it also requires you to construct your JSON data in Csound which is a little cumbersome. These opcodes are probably better for filling the data structure.

iRes setStateValue SKeyName, SData
kRes setStateValue SKeyName, kData
iRes setStateValue SKeyName, iData
iRes setStateValue SKeyName, SData[]
kRes setStateValue SKeyName, kData[]

iRes will return -1 one if there were any errors.

iVal getStateValue SKeyName
kVale getStateValue SKeyName
SVal getStateValue SKeyName
iVal[] getStateValue SKeyName
kVal[] getStateValue SKeyName
SVal[] getStateValue SKeyName

There are available in the latest beta build. Note they are only useful if saving session data within a DAW. I’ve also added a simple JSONOpcodes.csd file to the Misc examples folder.

Hey Rory,
It’s really cool that storing data within the DAW session is now possible. It’s actually necessary for the sampler-ish plugin I’m programming.
But I’m coming across some issues with recalling string values. Actually I need to recall a whole array of strings containing file paths of the individual samples loaded into the plugin.

First there is the problem that in order for the string to be stored/recalled (not sure where the problem occurs) the string has to be set into double quotes. So I need to use something like sprintfk “”%s"", String to make it happen and that I can’t do with an array at once. So I need to store them individually as I load them.
I would probably do it like that anyway, but an issue occurs when I try to recall the data singly back into an/the array in a while loop. When ever I left a blank “sample slot” the getStateValue returns nothing and the String from the last successful read gets assigned again to the next “sample slot/s” which are actually supposed to be empty or “”. I hope I’m making sense here!

I’ve attached a sample csd file of the issue and a video of what’s happening with it in the DAW.
You can see that the unsuccessful reads are reported in the cSound output. It would be good to somehow get this returned from the opcode to handle “empty slots” in the code.

Another bug seems to be that the very first string always get cut short, but only the first time it’s read. Not sure if I’m using the right terminology here, but it’s also shown in the video.
GetSetState.csd (3.5 KB)

btw: How do you get the codes displayed so nicely in this forum? When I use the </> button and copy paste from my code it gets randomly formatted and not formatted.

I guess I could do a workaround and create a boolean array which just holds information about IF a index was loaded with a sample, store that and then recall it before I recall any samples to only read the ones that were actually in the session.
Still, do you think it could be possible to get a “nil” return or something, if the json data isn’t available?
The first-read-cut-short-issue I work around by just reading the data twice with a bit of a delay. That actually works.

That sounds like something that might get extremely annoying over time! I think I should sort that!

Thanks, I’ll take a look at get back to you when I have an update.

Let me know when you fix this. I worked my way around it by first adding the quotes for storing and then removing them after recall.
Programming the recalling procedure was extremely annoying until I found out what works with iVars and not with kVars and the other way around. But [drumroll] this works:

 instr restorePaths
     icnt        init 0
     SArray[]    init 26
     while icnt < 26 do
         SKey            sprintfk "filepath(%d)",icnt
         SArray[icnt]    sprintfk "%s",getStateValue:S(SKey) ;temporary array just to be able to read json data
         icnt            = icnt + 1
     kcnt        init 0
     while kcnt < 26 do
         if(gkSampleSize[kcnt] != 0)then                     ;can only be checked with k-vars
             kLength         strlenk     SArray[kcnt]
             gSArray[kcnt]   strsubk     SArray[kcnt], 1, kLength-1  ;assigning temp. array to path-array and cut quotes
         kcnt            = kcnt + 1
 ;printarray  gSArray

I have an array of the sizes of my samples that I store now in order to select the paths for recall. Have to do this to avoid duplication of paths when the getStateValue opcode doesn’t return anything and the prior read would get assigned again. Have to do it in two loops though because it seems that i can’t check my k-var array for the sample sizes in an i-var loop. I’m using a lot of k-rate stuff to work with the sample size throughout my plugin, so i need it to be k-rate. Anyway, blabla, works this way. Just let me know when you change the double quote issue.

I’m not seeing any issues with double strings? Can you test this simplified .csd file?

CabbagePlugin.csd (1.4 KB)

I found the reason for this. It was working for me because all of my strings were the same length. The same thing started happening when I tried strings of various lengths. It’s fixed now in git. And note that I’ve also updated the name of these opcode so they start with a ‘cabbage’. It just makes it easier to see they are unique to Cabbage. I don’t want to confuse general Csound users!