Cabbage Logo
Back to Cabbage Site

Mouse Grid

It’s best to keep them in so that the host can access their values. Even if they are hidden.

Something like this is cleaner, but you should still probably check the mouse position better:

opcode MouseGrid, 0, iiiiiikkki
    icols, irows, isize, iposx, iposy, id, kms, kmx, kmy, iId    xin
    icnt    init    0

    kIndex = int((kmx)/isize)
  

    if kms == 1 then
            if  kmy > iposy && kmy < iposy+(isize*irows) then
                SGButChannel sprintfk "gbut%d%d", id, kIndex-1
                kPos = int((kmy-iposy)/isize)*isize                
                cabbageSetValue sprintfk("g%dc%d", iId, kIndex), int((kmy-iposy)/isize)*isize
                cabbageSet 1, SGButChannel, "bounds", iposx+(isize*(kIndex-1)), iposy+kPos, isize, isize
            endif       
    endif

endop

Rather than having all these global vars I would just create an image widget and use it as the background for the entire grid. Then query its position when you need to check things. I’ll put together an example.

It looks like you are creating 142 bgd images? That seems a little excessive?

[edit] sorry, that’s incorrect, I was reading the number on the channel name as a digit. I’m still looking :male_detective:

I came up with this alternative, what do you think? Instead of polling the entire grid, I created an UDO to check on each individual column. Performance seems to be much better (though perhaps I notice something similar re: the first click –– I tested it getting rid of the UDO and putting the code right in the instrument but that didn’t seem to make much of a difference).

GridAuto07.csd (4.8 KB)

Well technically it would be 42 bgd images for the first grid (+ 1 for a frame). The point of doing it this way was so one doesn’t have to redesign the whole ‘widget’ each time (but rather plug a few numbers and you get any kind of grid you wish for), but if it does make a difference in performance, no problem: I can just have one background (and as many image ‘buttons’ as I need).

However…

If you see this last example, notice that the GUI instrument (that draws all the individual cells) is called independently and only lasts 0.1 sec. So my question is: does all this ‘pre-calling’ still affect the overall performance? And if yes, I’m curious to know why (though I’ll understand if the answer is too complicated and beyond the scope of this forum).

Also, another newbie question :slight_smile:: Does it make a difference in performance if I shift all the code inside the last ‘if’ statement? (the same would apply for the returned output: kco staying inside the last ‘if’ statement)?

opcode GetColumn, k, iiiiiikkk
icol, irows, iposx, iposy, isize, id, kms, kmx, kmy xin

if  kmx > iposx+(isize*(icol-1)) && kmx < iposx+(isize*icol) && kmy > iposy && kmy < iposy+(isize*irows) then
    if kms == 1 then
        SGButChannel sprintfk "gbut%d%d", id, icol-1
        kPos = int((kmy-iposy)/isize)*isize

No, it doesn’t. And it wouldn’t make any difference if this instrument was running indefinitely as all the code in it is i-time only. This code is a little OTT:

cabbageSetValue sprintfk("g%dc%d", id, icol), int((kmy-iposy)/isize)
cabbageSet 1, SGButChannel, "bounds", iposx+(isize*(icol-1)), iposy+kPos, isize, isize
kco cabbageGetValue sprintfk("g%dc%d", id, icol)
xout kco

You already know the value you are setting that widget to, so just return that instead:

    if kms == 1 then
        cabbageSetValue sprintfk("g%dc%d", id, icol), int((kmy-iposy)/isize)
        cabbageSet 1, SGButChannel, "bounds", iposx+(isize*(icol-1)), iposy+kPos, isize, isize
        xout int((kmy-iposy)/isize)
    endif

That saves a call to cabbageGetValue. It’s cabbageSetValue that seems to be slowing things down. I will look into that. FWIW, I still think you might be wasting CPU cycles here. In the following code the cabbageSet opcodes gets called whenever kms is pressed. But they should only be called when one moves to a new cell?

if  kmx > iposx+(isize*(icol-1)) && kmx < iposx+(isize*icol) && kmy > iposy && kmy < iposy+(isize*irows) then
    SGButChannel sprintfk "gbut%d%d", id, icol-1
    kPos = int((kmy-iposy)/isize)*isize
    if kms == 1 then
        cabbageSetValue sprintfk("g%dc%d", id, icol), int((kmy-iposy)/isize), metro(10)
        cabbageSet 1, SGButChannel, "bounds", iposx+(isize*(icol-1)), iposy+kPos, isize, isize
        xout int((kmy-iposy)/isize)
    endif
endif

I think your UDO might return an error is the xout is inside an if-statement?

This one only calls the cabbage opcodes if there is a change to the active cell in the column:

opcode GetColumn,  k,  iiiiiikkk
    icol, irows, iposx, iposy, isize, id, kms, kmx, kmy xin
    kCurrentValue init 0
    if  kmx > iposx+(isize*(icol-1)) && kmx < iposx+(isize*icol) && kmy > iposy && kmy < iposy+(isize*irows) then
        SGButChannel sprintfk "gbut%d%d", id, icol-1
        kPos = int((kmy-iposy)/isize)*isize
        
        if kms == 1 && kCurrentValue !=  int((kmy-iposy)/isize) then
            cabbageSetValue sprintfk("g%dc%d", id, icol), int((kmy-iposy)/isize)
            cabbageSet 1, SGButChannel, "bounds", iposx+(isize*(icol-1)), iposy+kPos, isize, isize
            xout int((kmy-iposy)/isize)
            kCurrentValue = int((kmy-iposy)/isize)
        endif
    endif
endop

There is still something up with the setValue opcode. I will take a look.

Mm, it works in this last version (attached) –– I haven’t yet looked into the idea of checking ‘only new cells’ (that’ll be next!)

GridAuto08.csd (4.8 KB)

Thanks for this! Yes (it seems to me), it’s much better already. Just a couple of dangling questions:

  • Just to confirm: do you think then that this new version is OK with creating individual bgd cells ––or–– do you still think it will be better to create one bgd image for the entire grid (and, in this case, 6 button images)?
  • When testing out the GUI performance I only found some random lags: either at the very beginning (with the first click) or if left the plugin running (not a vst, just the Cabbage runtime) – went to some other app and then switched back to Cabbage. Eventually (and rather quickly), things got ‘snappy’ as expected –– would this have to do with the SetValue issues you mentioned?
  • I wonder if it would help slowing down the rate of the “MOUSE_X/Y” (going into the kmx/kmy variables)? I noticed that if I moved too quickly, some of the cells would not update, but if I dragged ––to the rhythm of my own age–– nice and slow, the response was great.

Yes, could wrap all the code in instr 1 in a metro loop:

if metro(10) then
...
endif 

I think this is new version is fine.

To be honest, I don’t know. I’m going to spend some time on this as I’m not happy with the slow starts!

I tried this, it does the opposite actually (I guess there’s no way around a fast trackpad!).

Thanks for all your help!

I remember now why the redundant GetValue calls (which will segue into yet one more question, hehe): it would be great if also one could set an initial state for the grid, so in fact perhaps the grid buttons are defined by the nsliders (and the mouse state sets the nsliders if that makes sense?).

Perhaps one could also call grid states independently of the mouse (either by calling a preset or say adding a sequencer that triggers grid changes at some musical rate, etc.).

The update rates of the mouse values are dependant on ksmps. If you wish you can create a UDO with a higher ksmps (use setksmps) rate and call the mouse channels in that.

Ah!, Cool will try that :slight_smile: (though I’m happy to compromise the GUI if it’s better not to complicate things!)

This is possible. Anything is possible really. It’s just a matter of finding the right design.

Agreed! Will keep working on it (and keep you posted)!

I tried adding it right after the ‘if kms/currentValue’ and it seems work out nicely…

opcode GetColumn, k, iiiiiikkk

icol, irows, iposx, iposy, isize, id, kms, kmx, kmy xin
kCurrentValue init 0
if  kmx > iposx+(isize*(icol-1)) && kmx < iposx+(isize*icol) && kmy > iposy && kmy < iposy+(isize*irows) then
    SGButChannel sprintfk "gbut%d%d", id, icol-1
    kPos = int((kmy-iposy)/isize)*isize
    
    if  kms == 1 && kCurrentValue !=  int((kmy-iposy)/isize) then
        setksmps    16

It doesn’t matter where you call it as it only runs at i-time. But if you want to slow things down, then you need to make it higher as it sets the number of audio samples per k cycle. The higher this is, the less k-cycles per second, and the slow the UI will update.

1 Like