Cabbage Logo
Back to Cabbage Site

Saving the text in texteditor

I use a number of text editors to hold series of numbers as a comma separated list. It seems the contents of the texteditor is not saved with the DAW project (using Reaper). Is it supposed to work, and there is something I’m doing wrong? Haven’t tried using Cabbage presets yet, as the host preset saving generally covers what I need. Would I need to make Cabbage presets to enable saving texteditor contents?

all best
Øyvind

It’s been a long time since I looked at the text editors, but I’m not sure there were ever set up to save contents. You have a few options though. You can use the cabbageSetStateValue, or you can use the cabbageStateSave opcode. Let me know if you come unstuck :+1:

Thanks for the pointer.
I had to modify the manual example slightly as there was some error with the path and finding the saved file (I think). Now it recalls the values, but it does not update the texteditor widget to display the values. Is there an attribute to the texteditor to set the displayed text? (Then I could perhaps use cabbageSet). Tried with text(“1,2,3”), but it does not seem to do anything.

Here’s my code modified from the manual

instr 10
SFilename, kTrig cabbageGetValue “recallCombo”
SPath = chnget:S(“CSD_PATH”)
if kTrig == 1 then
SIgnoreChannels[] init 2
SIgnoreChannels[0] = “triggerSave”
SIgnoreChannels[1] = “recallCombo”
SFilenam = sprintfk:S("%s\%s.pre", SPath, SFilename)
kOk = cabbageChannelStateRecall:k(SFilenam, SIgnoreChannels)
cabbageSetValue “programs_1”, cabbageGetValue:k(“programs_1”)
cabbageSetValue “programs_2”, cabbageGetValue:k(“programs_2”)
endif
kFileNumber chnget “filenumber”
if changed:k(chnget:k(“triggerSave”)) == 1 then
SFilename = sprintfk:S("%s\PresetTest%d.pre", SPath, kFileNumber)
printks “%s”, 0, SFilename
kOk = cabbageChannelStateSave:k(SFilename)
kFileNumber+=1
chnset kFileNumber, “filenumber”
cabbageSet 1, “recallCombo”, “refreshFiles(1)”
endif
endin

And the texteditor code:

texteditor bounds(33, 80, 130, 20) fontSize(16), channel(“programs_1”), fontColour(255, 255, 255), colour(0, 0, 0), caretColour(“white”), fontSize(14)

This works for me:

<Cabbage>
form size(500, 300), caption("Untitled"), guiMode("queue")
texteditor bounds(71, 66, 180, 60) channel("texteditor1")
</Cabbage>

<CsoundSynthesizer>
<CsOptions>
-n -d
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 16
nchnls = 2
0dbfs = 1



instr 1
  cabbageSet "texteditor1", "text(\"hello world\")"
endin       

</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
;starts instrument 1 and runs it for a week
i1 0 z
</CsScore>
</CsoundSynthesizer>

It will be cabbageSet rather than cabbageSetValue. Do you have guiMode("queue") set?

Great. The teteditor updates nicely with your
cabbageSet “texteditor1”, “text(“hello world”)”

But I’m confused as to what I get from
kOk = cabbageChannelStateRecall:k(SFilenam, SIgnoreChannels)
… as this
Stest sprintfk “test %s”, cabbageGetValue:k(“programs_2”)
gives
INIT ERROR in instr 10 (opcode sprintfk) line 193: sprintfk: Not string type for %%s

Is it not a string that is returned from cabbageChannelStateRecall?
My .pre file contains the line
“programs_2”: “9,11”,

all best
Øyvind

Isn’t this just a syntax error? you’re trying to format a value as a string? Should you not be using %d or %f? Also, i’d use cabbageSetStateValue rather than the channel one. Not sure, but I think it will be easier as you’re only tracking a single value?

mmm, the value I would like to read is the list of two numbers in this case (“9,11”), so I thought I would have to read it as a string (?)

If you want “9, 11”. You need to do:

Stest sprintfk “%d, %d”, k1, k2

where k1 and k2 are 9 and 11? Or am I missing something fundamental here?

I won’t know how many numbers I have… sometimes 1, sometimes many…

In the saved preset file, I see the texteditor item contents saved as a string.

“programs_1”: “4”,
“programs_2”: “9,11”,
“programs_3”: “1,3,5,12,15”,
“programs_4”: “7,4”,

Here’s an example of how to write the contents of an array to a state variable, and load it when next you launch your session. This may need to be manually loaded after your session loads, but it’s very simple and you can save any data you like:

<Cabbage>
form caption("State Save") size(370, 380), guiMode("queue") pluginId("MPre")
button bounds(210, 8, 109, 27) channel("writeState"), text("Update Text")
button bounds(10, 8, 115, 30) channel("loadState"), text("Load state")

csoundoutput bounds(12, 48, 355, 319) channel("csoundoutput10002")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d 
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
;sr is set by the host
ksmps = 32
nchnls = 2
0dbfs = 1

instr 1

    kStateWrite, kStateWriteTrig cabbageGetValue "writeState"
    if(kStateWriteTrig) == 1 then
        event "i", 2, 0, 0.1
    endif 
    
    kStateLoad, kStateLoadTrig cabbageGetValue "loadState"
    if(kStateLoadTrig) == 1 then
        event "i", 3, 0, 0.1
    endif 
    
endin


instr 2

    SArr[] init 16
    SString init ""
    iIndex = 0
    while iIndex < 16 do
        SArr[iIndex] = random:i(0, 100)
        SString strcat SString, SArr[iIndex]
        iIndex += 1
    od
    printarray SArr
    cabbageSetStateValue "stringOfNumbers", SArr
    
endin

instr 3
    prints "Reading data"
    SData[] cabbageGetStateValue "stringOfNumbers"
    printarray SData    
endin
</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
i1 0 z
</CsScore>
</CsoundSynthesizer>

p.s. I’m not sure why I used a string array here, numbers would have been simpler…

Thanks, I see. There’s some nitpicking with encoding and decoding the strings back and forth. I’ll see if I can come up with a simpler solution. I also write the values to tables, so perhaps just save the table data separately.

Yes, saving and writing to a table also seems like a simple solution.