Cool! But it seem unconventional? Or maybe it is more common then I’d like it to be?
New cabbageChanged opcode
In the sense that it is overloaded? What would you rather?
I was just wandering about consistency, and now it actually makes good sense like that since we probably won’t need both the index and the name at the same time. I’m drifting out of phase after a long day here, but at the moment it seem ideal to have kTrig, [kIndex, SChannel], latter two as optional, or kTrig would not be even needed if kIndex would be negative whenever is not changed.
just because you would need to use 3 outputs if you want to access the channel name. Seems clunky to me, but tbh, we’re probably just splitting hairs at the meta level now! It would be best to admit that we are bought absolutely 100% correct in syntactic assessment, and leave it at that
btw, my tendency to overload opcodes might cause issues at some point, especially with strings. The cabbageSetValue
opcodes that handle strings at k-rate need to be explicitly told the string are k-rate. Therefore the strings have to be wrapped in a sprintfk
opcode. The alternative was to create cabbageSetValuek
and cabbageSetValuei
opcodes which I find rather ugly. The problem is that all strings are actually i-rate by definition, but they can be updated at k-rate using k-rate string opcodes.
Nice.
@Samo, I’ve added an optional argument to the cabbageChanged
opcode. If added, a trigger will only be output each time the channel hits this target value. In the example below, the triggers only fire when a button is turned on, as opposed to firing whenever it changes between on and off,
<Cabbage>
form caption("Radio") size(400, 300), guiMode("queue") pluginId("def1")
button bounds(10, 10, 80, 30), latched(1) channel("button1"), radioGroup(10)
button bounds(100, 10, 80, 30), latched(1) channel("button2"), radioGroup(10)
button bounds(200, 10, 80, 30), latched(1) channel("button3"), radioGroup(10)
button bounds(300, 10, 80, 30), latched(1) channel("button4"), radioGroup(10)
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d
</CsOptions>
<CsInstruments>
; Initialize the global variables.
ksmps = 32
nchnls = 2
0dbfs = 1
instr 1
SChans[] cabbageGetWidgetChannels "radioGroup(10)"
SChannel, kTrig cabbageChanged SChans, 1
printf SChannel, kTrig
endin
</CsInstruments>
<CsScore>
i1 0 [60*60*24*7]
</CsScore>
</CsoundSynthesizer>
Sounds great! Looking forward to start implementing the new trigger.
I suppose this will trigger also for sliders when they cross the target value but in both directions (from higher to lower and lower to higher), right?
Yes, correct. Let me think about this. We could add an optional trigger-esque mode parameter?
That’s what I had in mind all along!
I’ve updated this so the additional parameters behave like the trigger opcode. I modified the original post here so that it contains a description of the most current version. Need testing, but seem to mimic the Csound trigger opcode now, albeit with channel array input.
Fantastic! I think this addition will be very useful! And it now beats the Csound (non) alternatives even by a larger margin. Thanks! I’ll get on with it tonight.
[edit] I hope the stew will be ready soon …
MacOS stew is available, just click into the pipeline. Steinberg are doing maintenance on their servers at the moment which means the ASIO SKD is not currently available. This is stopping the Windows builds from completing for now. I hope it will be sorted shortly.
I did some tests and it doesn’t seem to work as I expected. Or maybe I am doing something wrong?
-
the new trigger-esque options don’t seem to have any effect at all, e.g. sliders are triggering all the time, tried with i-rate and k-rate option values (how are they supposed to be set?)
-
radioGroup
-ed buttons don’t trigger when going back and forth between any two buttons in a group
Here is my testing playground (please comment/uncomment parts of it).
<Cabbage>
form caption("Cabbage Changed") size(430, 290) pluginId("tl01") guiMode("queue")
rslider bounds(10, 10, 100, 100), channel("slider1") _isSlider(1)
rslider bounds(110, 10, 100, 100), channel("slider2") _isSlider(1)
rslider bounds(210, 10, 100, 100), channel("slider3") _isSlider(1)
rslider bounds(310, 10, 100, 100), channel("slider4") _isSlider(1)
combobox bounds(20, 118, 80, 20) channel("combo1"), channelType("string") _isCombo(1)
combobox bounds(120, 118, 80, 20) channel("combo2"), channelType("string") _isCombo(1)
combobox bounds(220, 118, 80, 20) channel("combo3"), channelType("string") _isCombo(1)
combobox bounds(320, 118, 80, 20) channel("combo4"), channelType("string") value("1") _isCombo(1)
label bounds(8, 158, 412, 21) channel("label1"), align("left"), fontColour(0, 0, 0, 255) text("Most recently changed widget:")
image bounds(6, 234, 412, 41) channel("image15")
button bounds(20, 246, 80, 20) channel("RG1") text("1", "1") radioGroup("RG") colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _isGrouped(1)
button bounds(120, 246, 80, 20) channel("RG2") text("2", "2") radioGroup("RG") colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _isGrouped(1)
button bounds(220, 246, 80, 20) channel("RG3") text("3", "3") radioGroup("RG") colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _isGrouped(1)
button bounds(320, 246, 80, 20) channel("RG4") text("4", "4") radioGroup("RG") colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _isGrouped(1)
button bounds(20, 198, 80, 20) channel("NonLatched1") text("X", "X") latched(0) colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _latched(0)
button bounds(120, 198, 80, 20) channel("NonLatched2") text("Y", "Y") latched(0) colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _latched(0)
button bounds(220, 198, 80, 20) channel("NonLatched3") text("Z", "Z") latched(0) colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _latched(0)
button bounds(320, 198, 80, 20) channel("NonLatched4") text("W", "W") latched(0) colour:1(255, 255, 0, 255) fontColour:1(160, 0, 0, 255) _latched(0)
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -m0d -+rtmidi=NULL
</CsOptions>
<CsInstruments>
ksmps = 32
instr 1
;SWidgetChannels[] cabbageGetWidgetChannels "_isSlider(1)"
;SWidgetChannels[] cabbageGetWidgetChannels "_latched(0)"
SWidgetChannels[] cabbageGetWidgetChannels "_isGrouped(1)"
;prints SWidgetChannels[0]
;SUpdatedChannel, kTrig cabbageChanged SWidgetChannels
;cabbageSet kTrig, "label1", sprintfk("text(\"Last updated widget: %s\n\")", SUpdatedChannel)
;kIndex, kTrig cabbageChanged SWidgetChannels
;cabbageSet kTrig, "label1", sprintfk("text(\"Last updated widget: %s\n\")", SWidgetChannels[kIndex])
;printk2 kIndex
kIndex, kTrig cabbageChanged SWidgetChannels, k(0.5), k(0)
if kTrig == 1 then
printk 0, kIndex
endif
endin
</CsInstruments>
<CsScore>
i1 0 z
</CsScore>
</CsoundSynthesizer>
I’d like it to do something like this (comment one of the fillarray
blocks)
kON[] fillarray \
trigger(cabbageGetValue:k("NonLatched1"),0.5,0),\
trigger(cabbageGetValue:k("NonLatched2"),0.5,0),\
trigger(cabbageGetValue:k("NonLatched3"),0.5,0),\
trigger(cabbageGetValue:k("NonLatched4"),0.5,0)
kON[] fillarray \
trigger(cabbageGetValue:k("RG1"),0.5,0),\
trigger(cabbageGetValue:k("RG2"),0.5,0),\
trigger(cabbageGetValue:k("RG3"),0.5,0),\
trigger(cabbageGetValue:k("RG4"),0.5,0)
kind = 0
until kind == 4 do
if kON[kind] == 1 then
printk 0, kind
endif
kind += 1
od
My bad, seems I only added it to the version:
SChannel, kTrig cabbageChanged ...
I’ll update the
kIndex, kTrig cabbageChanged ...
now. Give me a sec…
The slider now works 50%. Could you please check my code for all 3 types of widgets.
-
the kIndex doesn’t change?
-
radioGroup doesn’t work - still seems the same as I noted before
Maybe you could consider replicating this behaviour if possible - instead of printing in the until loop I’d of course do more interesting things with the index.
It’s working for me 100% of the time. I tested with the trigger opcode in Csound and they both seem to behave the same?
Sorry, my fault That’s fixed now
The problem is that when clicking on a radio group, two buttons change state at the same time, or thereabouts. This means that we intermittently miss one. Looks like there is little we can do in this case because it’s not a single channel changing but two.
One possible way around this would be to build your own radiogroup using a slider and some images. Each time you update a button(image) in the group it would send an update to the slider. That way you only have to keep track of the slider position? Here is n example:
<Cabbage>
form caption("Cabbage Changed") size(430, 390) pluginId("tl01") guiMode("queue")
image bounds(10, 296, 90, 30) channel("radioImage1"), value(1), colour("black"), _isGrouped(1)
image bounds(110, 296, 90, 30) channel("radioImage2"), value(1), _isGrouped(1)
image bounds(210, 296, 90, 30) channel("radioImage3"), value(1), _isGrouped(1)
image bounds(310, 296, 90, 30) channel("radioImage4"), value(1), _isGrouped(1)
hslider bounds(-1000, 310, 90, 20), alpha(0), popupText(0), channel("radioGroup1"), range(0, 3, 0, 1, 1)
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -m0d -+rtmidi=NULL
</CsOptions>
<CsInstruments>
ksmps = 32
opcode Radio, 0,SS[]i
SSliderChannel, SChannels[], iIndex xin
kIndex, kTrig cabbageChanged SChannels
kCnt = 0
printf "Changed:%d", kTrig, kIndex
if kTrig == 1 then
while kCnt < 4 do
cabbageSet kTrig, SChannels[kCnt], (kCnt == kIndex ? "colour(255, 0, 0)" : "colour(255, 255, 255)")
kCnt+=1
od
cabbageSetValue SSliderChannel, kIndex
endif
endop
instr 1
SWidgetChannels[] cabbageGetWidgetChannels "_isGrouped(1)"
Radio "RadioGroup1", SWidgetChannels, 1
kIndex, kTrig cabbageGetValue "RadioGroup1"
printf "RadioGroupIndex:%d", kTrig, kIndex
endin
</CsInstruments>
<CsScore>
i1 0 z
</CsScore>
</CsoundSynthesizer>
You might want to make each one of those image interactive(0)
so they don’t confuse users in a DAW. In fact, I wonder can you just use a slider with your current setup too? Let me take a look…
I guess you could do this:
kIndex, kTrig cabbageChanged SWidgetChannels, k(0.5), k(0)
kCurrentRadio init 0
if kTrig == 1 then
kCnt = 0
while kCnt < 4 do
if cabbageGetValue:k(SWidgetChannels[kCnt]) == 1 then
kCurrentRadio = kCnt
endif
kCnt += 1
od
endif
printk2 kCurrentRadio
Until radioGroups behave like a single object I think we might be stuck with some kind of hybrid solution
Thank you very much for explanations and examples! Very helpful!
Not sure what you mean, but a slider would constrain changes to be monotonic? What about a sequence of jumps like 1 4 2 5 1?
The idea was to make it less taxing on CPU. I’m wandering if this isn’t going to be more expensive?