Cabbage Logo
Back to Cabbage Site

Dynamic quantizing of slider values

Hi,

I’d like to have a slider (rslider) that can be set to different resolution, depending on selecting in another widget. For example to have a combobox with items “1/2”, “1/3”, “1/4”, “1/5” and so on. If I select 1/2, the rslider should snap to multiples of 0.5, if I select 1/3 it should snap to multiples of 1/3.
I can do this by processing the values that come out of the rslider, but it is confusing for the user that the rslider still can reach all of those unquantized values.
I tried to use CabbageSetValue to write the quantized values back to the GUI, but it seems it will not update. I am guessing that it is not updated beecause I am still holding it with the mouse, which makes sense, …but also prevents me from displaying the quantized value. I’m currently displaying it in another nslider, which works but not as nice and intuitive as I would like it to be.
I wondered about inserting a delay before calling cabbageSetValue, so that my last action when releasing the mouse will be updated in the GUI, but it seems like a bit of a hack, and I figured I’d ask if anyone has a better solution.

Here’s an example of what I’m doing now:

<Cabbage> 
form size(200, 100), caption("Quantize test"), pluginId("qtst"), colour(23,38,45), guiMode("queue")
rslider channel("Value"), bounds(5, 5, 70, 70), text("Value"), range(0, 4, 0)
combobox channel("Quantize"), bounds(80, 20, 60, 16), text("off", "1/2", "1/3", "1/4", "1/5", "1/6", "1/7", "1/8", "1/9", "1/10"), value(1)
label bounds(83, 40, 60, 12), text("Quantize"), align("left") channel("label37")
</Cabbage>

<CsoundSynthesizer>
<CsOptions>
-n -d -m0 -+rtmidi=null -M0
</CsOptions>
<CsInstruments>

instr 1
  kquantize chnget "Quantize"
  iQuantize[] fillarray 1,2,3,4,5,6,7,8,9,10
  kquantizeval = iQuantize[kquantize-1]
  kvalue chnget "Value"
  if kquantizeval > 1 then
    kvalue_quantized = floor(kvalue*kquantizeval)/kquantizeval 
  else 
    kvalue_quantized = kvalue
  endif
  printk2 kvalue_quantized 
  cabbageSetValue "Value", kvalue_quantized, changed(kvalue_quantized)
endin

</CsInstruments>
<CsScore>
i1 0 86400 ; gui handling
</CsScore>

</CsoundSynthesizer>

Interesting challenge :slight_smile: So you could overlay slider on top of the master slider, and use it to update the position of the master slider. I’ve attached a proof of concept below. However, there is one issue, and it’s on the Cabbage side, whereby the tracker of the master slider is not showing. I’m not sure why, but I will fix that. But I think this approach should work for you. You might want to use automatable(0) on the overlay slider so it doesn’t show as a parameter in the DAW, or perhaps it should be the master slider? Ha, I’m not sure. I’ll leave it up to you :+1:

<Cabbage> 
form size(200, 100), caption("Quantize test"), pluginId("qtst"), colour(23,38,45), guiMode("queue")
rslider channel("Value"), bounds(5, 5, 70, 70), text("Value"), range(0, 4, 0), trackerColour(255, 0, 0)
rslider channel("ValueShow"), bounds(5, 5, 70, 70), markerColour(255, 0, 0, 0) trackerColour(255, 0, 0, 0) colour(255, 0, 0, 0), text("Value"), range(0, 4, 0). alpha(1)
combobox channel("Quantize"), bounds(80, 20, 60, 16), text("off", "1/2", "1/3", "1/4", "1/5", "1/6", "1/7", "1/8", "1/9", "1/10"), value(1)
label bounds(83, 40, 60, 12), text("Quantize"), align("left") channel("label37")
</Cabbage>

<CsoundSynthesizer>
<CsOptions>
-n -d -m0 -+rtmidi=null -M0
</CsOptions>
<CsInstruments>

instr 1
  kquantize chnget "Quantize"
  iQuantize[] fillarray 1,2,3,4,5,6,7,8,9,10
  kquantizeval = iQuantize[kquantize-1]
  kvalue chnget "ValueShow"
  if kquantizeval > 1 then
    kvalue_quantized = floor(kvalue*kquantizeval)/kquantizeval 
  else 
    kvalue_quantized = kvalue
  endif
  printk2 kvalue_quantized 
  cabbageSetValue "Value", kvalue_quantized, changed(kvalue_quantized)
endin

</CsInstruments>
<CsScore>
i1 0 86400 ; gui handling
</CsScore>

And you could hide the popupText for the sliders, and instead show the quantized value as a label:

<Cabbage> 
form size(200, 100), caption("Quantize test"), pluginId("qtst"), colour(23,38,45), guiMode("queue")
rslider channel("Value"), bounds(5, 5, 70, 70), text("Value"), range(0, 4, 0), trackerColour(255, 0, 0), popupText("0")
rslider channel("ValueShow"), bounds(5, 5, 70, 70), markerColour(255, 0, 0, 0) trackerColour(255, 0, 0, 0) colour(255, 0, 0, 0), text("Value"), range(0, 4, 0). alpha(1), popupText("0")
combobox channel("Quantize"), bounds(80, 20, 60, 16), text("off", "1/2", "1/3", "1/4", "1/5", "1/6", "1/7", "1/8", "1/9", "1/10"), value(1)
label bounds(83, 40, 60, 12), text("Quantize"), align("left") channel("label37")
label bounds(0, 80, 50, 12), text("0.0"), channel("ValueLabel"), align("center")
</Cabbage>

<CsoundSynthesizer>
<CsOptions>
-n -d -m0 -+rtmidi=null -M0
</CsOptions>
<CsInstruments>

instr 1
  kquantize chnget "Quantize"
  iQuantize[] fillarray 1,2,3,4,5,6,7,8,9,10
  kquantizeval = iQuantize[kquantize-1]
  kvalue chnget "ValueShow"
  if kquantizeval > 1 then
    kvalue_quantized = floor(kvalue*kquantizeval)/kquantizeval 
  else 
    kvalue_quantized = kvalue
  endif
  printk2 kvalue_quantized 
  cabbageSetValue "Value", kvalue_quantized, changed(kvalue_quantized)
  
  cabbageSet changed2(kvalue_quantized), "ValueLabel", sprintfk("text(\"%.1f\")", kvalue_quantized)
endin

</CsInstruments>
<CsScore>
i1 0 86400 ; gui handling
</CsScore>

Ah, nice ideas. Thanks to you both. I had already been doing rsliders within rsliders, to display several related values as one combined widget. But I did not think of doing the same here.