# cabbageGetValue in a k-rate loop

**URL:** <https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726>\
**Category:** Cabbage Stew\
**Created:** [24 July 2021 09:02 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726 "2021-07-24T09:02:20Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [24 July 2021 09:02 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/1 "2021-07-24T09:02:20Z")

</div>

I’m getting widget channel names with `cabbageGetWidgetChannels` and I’d like to update a table only when any of the widget values change. This works find if I manually detect value change by spelling out all the widgets like:  
`kVal, kTrig cabbageGetValue "channelName"`,  
but if I try to loop through the channels, `cabbageGetValue` triggers also when value is not changed, presumably due to “banging” it with a k-rate index. I get a similar issue if I use `changed:k(kVal)` instead of kTrig. I am puzzled why changed detects a change while kVal is constant?

Is there a way to scan through the widgets in a loop like below without getting value change triggers all the time?

Example:

```
    <Cabbage>
    form caption("test loop cabbageGetValue") size(330, 290) pluginId("cgv1") colour(0, 0, 0) guiMode("queue")

    rslider bounds(8, 8, 40, 70) range(0, 10, 1, 1, 0.0001) channel("par1") text("Par1") popupText("0") _getMe(1)
    rslider bounds(46, 8, 40, 70) range(0, 10, 2, 1, 0.0001) channel("par2") text("Par2") popupText("0") _getMe(1)
    rslider bounds(86, 8, 40, 70) range(0, 10, 3, 1, 0.0001) channel("par3") text("Par3") popupText("0") _getMe(1)

    </Cabbage>
    <CsoundSynthesizer>
    <CsOptions>

    -n -d -m0d -+rtmidi=NULL 

    </CsOptions>
    <CsInstruments>

    ksmps = 32 

    instr 1
    Sliders[] cabbageGetWidgetChannels "_getMe(1)"
    printarray Sliders, 1

    iN = lenarray(Sliders)
    print iN

    kind = 0
    until kind == iN do
       kVal, kTrig cabbageGetValue Sliders[kind]
    
       if kTrig == 1 then
          printk 1, kVal
       endif

       kind += 1
    od

    endin

    </CsInstruments>
    <CsScore>
    f0 z
    i 1 0 -1
    </CsScore>
    </CsoundSynthesizer>
```

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [24 July 2021 09:21 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/2 "2021-07-24T09:21:19Z")

</div>

You can call `cabbageGetValue` without the trigger arg, it’s optional?

[edit] just reading this a little more closely now. Yes, I am not sure if one can loop through the opcodes like this for changes. If the same problem happens with a `changed` opcode, I think you may need a different approach. Let me know try some things…

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [24 July 2021 09:33 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/3 "2021-07-24T09:33:35Z")

</div>

Yeah, it’s as I thought, if you try this one would expect the kCombinedTrig to be above 0 each time one changes a slider, but that’s not the case 🤔

```
instr 1
    Sliders[] cabbageGetWidgetChannels "_getMe(1)"
    printarray Sliders, 1

    iN = lenarray(Sliders)
    print iN

    kind = 0
    kCombinedTrigger = 0
    until kind == iN do
       kVal, kTrig cabbageGetValue Sliders[kind]
       kCombinedTrigger+=kTrig
       kind += 1
    od

    printk2 kCombinedTrigger
   
endin

```

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [24 July 2021 09:40 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/4 "2021-07-24T09:40:52Z")

</div>

Ah yes, this is the reason I wrote the array variants of [`chnget/chnset`](https://github.com/csound/csound/pull/1232) for Csound. They will do the job fine here. Here is an example:

```
instr 1
    Sliders[] cabbageGetWidgetChannels "_getMe(1)"
    printarray Sliders, 1

    iN = lenarray(Sliders)
    print iN

    kValues[] chngetk Sliders
    
    if changed2(kValues) == 1 then
        printks "Hello\n", 1
    endif
endin

```

Might be worth adding the same to the cabbageGet opcodes. I have a good example to test with at least 😉

---

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [24 July 2021 10:20 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/5 "2021-07-24T10:20:43Z")

</div>

Interesting, I was not aware of the `chngetk` opcode. Doesn’t seem to be documented?  
I could update the entire table with this.

But how could I detect which slider was changed?  
The example below seems to have the same issue of constantly detecting changes.

```
kind = 0
until kind == iN do
if changed2:k(kValues[kind])==1 then
printk 1, kind
endif
kind += 1
od

```

[edit]  
I actually came across this issue before and realized that I have to do something like below instead of looping - to have triggers in an array ready to use in a loop:

```
kSaveONTrig[] fillarray \
trigger(cabbageGetValue:k("IO_SavePar1"),0.5,0),\ ;0->1
trigger(cabbageGetValue:k("IO_SavePar2"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar3"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar4"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar5"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar6"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar7"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar8"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar9"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar10"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar11"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar12"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar13"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar14"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar15"),0.5,0),\
trigger(cabbageGetValue:k("IO_SavePar16"),0.5,0)

```

It would be great if there are other opcodes to deal with triggers which I don’t know yet?

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [24 July 2021 10:33 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/6 "2021-07-24T10:33:56Z")

</div>

Why not something like this:

```
ksmps = 32 

opcode IndexOfChanged, k,k[]
    kIncomingValues[] xin
    kCurrentValues[] init lenarray(kIncomingValues)
    kIndex = 0
    kChangedIndex init 0
    while kIndex < lenarray(kIncomingValues) do
        if (kIncomingValues[kIndex] != kCurrentValues[kIndex]) then
            kChangedIndex = kIndex
        endif
        kIndex += 1
    od

    kCurrentValues = kIncomingValues

    xout kChangedIndex
endop

instr 1
    Sliders[] cabbageGetWidgetChannels "_getMe(1)"
    printarray Sliders, 1
    iN = lenarray(Sliders)
    kValues[] chngetk Sliders    
    k1 IndexOfChanged kValues
    printk2 k1
endin

```

Those opcodes are documented, but on the same page as the regular [channel](https://csound.com/docs/manual/chnget.html) opcodes.

---

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [24 July 2021 10:47 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/7 "2021-07-24T10:47:50Z")

</div>

That is useful! Thanks!  
But seems a bit expensive?  
I could live with that though 🙂

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [24 July 2021 12:28 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/8 "2021-07-24T12:28:09Z")

</div>

It shouldn’t be too expensive in this instance. But with dozens of channels it might get that way. I could write an opcode that accepts an array of channels, and returns the channel that has changed, or an array of channels that have changed 🤔

---

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [24 July 2021 14:01 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/9 "2021-07-24T14:01:41Z")

</div>

Of course I have many channels 🙂  
I think such opcodes could be useful. Both index or sorted array could be useful - Matlab style 🙂

In combo with the new `cabbageGetWidgetChannels` this could be very useful, making bookkeeping really elegant.

Another issue I have is with triggering when crossing threshold value. Maybe I got into a blind road, but I’d like to have a trigger type opcode which could scan an array, but that is probably more of a Csound wish and I don’t know if it is feasible. I tried modifying your code above with the condition:  
`kCurrentValues[kind] <= iThresh && kIncomingValues[kind] > iThresh`  
to detect crossing over iThresh value, but I’d also need it to send out a “reset” message (maybe a negative index) kind of like the trigger which return to 0 after the k-cycle. Hmmmm… maybe index is not enough and a “bang” message is needed as well…?

---

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [24 July 2021 16:45 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/10 "2021-07-24T16:45:17Z")

</div>

Just a comment on CPU load. Testing with 100 sliders, it seems that

`kValues[] chngetk Sliders`

is notably faster than

```
kValues[] init iN
kind = 0
until kind == iN do
kValues[kind] = cabbageGetValue:k(Sliders[kind])
kind += 1
od

```

which is probably not surprising due to lower level background code…?  
So for my purpose, it might be cheaper to copy the entire array to function table when any widget changes instead of copying selected widget value to table:

```
iTable ftgen 0, 0, -iN, -2, 0
copya2ftab kValues, iTable

```

I guess there is no other more direct way of getting channel data into function tables?

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [24 July 2021 18:36 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/11 "2021-07-24T18:36:18Z")

</div>

> [@Samo](#):
>
> which is probably not surprising due to lower level background code…?

Yes, it’s not at all surprising. I could add an array variant of cabbageGetValue, something like

`kValues cabbageGetValue SChannels`

That might be useful too.

> [@Samo](#):
>
> Another issue I have is with triggering when crossing threshold value. Maybe I got into a blind road, but I’d like to have a trigger type opcode which could scan an array, but that is probably more of a Csound wish and I don’t know if it is feasible. I tried modifying your code above with the condition:  
> `kCurrentValues[kind] <= iThresh && kIncomingValues[kind] > iThresh`  
> to detect crossing over iThresh value, but I’d also need it to send out a “reset” message (maybe a negative index) kind of like the trigger which return to 0 after the k-cycle. Hmmmm… maybe index is not enough and a “bang” message is needed as well…?

This is all starting to sound a little complex 🤔 I wonder if you couldn’t simplify things?

---

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [24 July 2021 19:21 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/12 "2021-07-24T19:21:10Z")

</div>

Yes, I could simplify it 🙂 As usually, it helps to have a chat with a friend here 😄  
I’m saving channel values to a subset of a table depending on the trigger button (think of it like saving slots). The entire table is then my collection of presets. I know you have introduced cool new ways of saving presets, but I haven’t tried it all out yet and I like to do it this way because I can then change presets (sub-presets) on the fly with a MIDI controller mapped to buttons (preset slots). One use case could be to have elements (modes) of a generative composition all saved in one preset collection (one song) and traverse those presets in an improvised setting.

However, I often use triggers on momentary buttons, I find them useful to detect threshold crossings. But they don’t work in a loop.

> [@rorywalsh](#):
>
> I could add an array variant of cabbageGetValue

That’s great! Thanks!

---

<div class="post-metadata">

**Author:** ![mjmogo](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/mjmogo/32/3522_2.png) [@mjmogo](https://forum.cabbageaudio.com/u/mjmogo)\
**Post date:** [24 July 2021 21:39 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/13 "2021-07-24T21:39:48Z")

</div>

> [@rorywalsh](#):
>
> kValues **cabbageGetValue** SChannels

Will this also include a set of Triggers?

`kValues[], kTrig[] cabbageGetValue SChannels[]`

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [26 July 2021 12:46 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/14 "2021-07-26T12:46:07Z")

</div>

I won’t get a chance to write this for a few days, but I guess it could, should?

---

<div class="post-metadata">

**Author:** ![mjmogo](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/mjmogo/32/3522_2.png) [@mjmogo](https://forum.cabbageaudio.com/u/mjmogo)\
**Post date:** [26 July 2021 15:58 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/15 "2021-07-26T15:58:44Z")

</div>

Thanks.

---

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [26 July 2021 18:31 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/16 "2021-07-26T18:31:17Z")

</div>

> [@rorywalsh](#):
>
> should?

If we can’t detect a change in a loop (as discussed above), it might be very useful. And maybe it can be more efficient than the UDO with internal copy of the array?

My dream would be to get even a Cabbage trigger opcode for arrays, but since there is no (?) trigger for arrays in Csound it might be unreasonable to wish something like that in Cabbage?

---

<div class="post-metadata">

**Author:** ![rorywalsh](https://forum.cabbageaudio.com/user_avatar/forum.cabbageaudio.com/rorywalsh/32/165_2.png) [@rorywalsh](https://forum.cabbageaudio.com/u/rorywalsh)\
**Post date:** [26 July 2021 18:33 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/17 "2021-07-26T18:33:20Z")

</div>

> [@Samo](#):
>
> My dream would be to get even a Cabbage trigger opcode for arrays, but since there is no (?) trigger for arrays in Csound it might be unreasonable to wish something like that in Cabbage?

Au contraire. If it’s not in Csound, it might as well be in Cabbage 👍

---

<div class="post-metadata">

**Author:** ![Samo](https://forum.cabbageaudio.com/letter_avatar_proxy/v4/letter/s/71c47a/32.png) [@Samo](https://forum.cabbageaudio.com/u/Samo)\
**Post date:** [26 July 2021 18:34 UTC](https://forum.cabbageaudio.com/t/cabbagegetvalue-in-a-k-rate-loop/2726/18 "2021-07-26T18:34:56Z")

</div>

Very exciting! 😋
