Cabbage Logo
Back to Cabbage Site

Mouse Grid

Here’s a new version with the ‘cabbageGet/Set’ redundancy added back: performance is again ‘somewhat flaky’, but I think this is the way to go:

  • I can initialize a different grid state through the nsliders
  • I can call the grid independently from any mouse activity.

Also, note the delay at launch before the init state is set.
GridAuto11.csd (5.0 KB)

Actually, I want to make the instrument faster (krate) but only when using the mouse –– on a side question (though related, I think –– I’m still wrapping my head around i-time vs. k-time!): will performance be affected depending on the following proposed examples?

Example 1 (what we have currently)

UDO
(ksmps set to a low/different value)
if MouseDown == yes then
perform query

Example 2

Instr 1
if MouseDown == yes then
call UDO

Example 3

Instr 1
if MouseDown == yes then
call Instr 2 (via event)

Instr 2
Call UDO

Score:
i1 only

I did a quick test exporting this patch to a VST3 plugin, just out of curiosity, and I’m happy to report that performance is MUCH better, quite snappy actually; there’s only a tiny delay for the init state to kick in, but even this is quicker/much better.

That’s good to know.

With ksmps = 32 it’s running at over 1000 frames per second. Considering the standard screen refresh rate is about 60 frames per second, I can’t see any reason for wanting this to be faster?

AH, so it’s quite the reverse of what I thought perhaps? I just don’t understand why if there’s some kind of fast gesture mouse movement, why my UDO wouldn’t pick that up (perhaps it’s ‘jumping’ to to another ‘frame’ and hence the skipping?) Anyway, the behavior on the VST was really straight forward (no funny visual business, which is what we’re looking for ultimately). Will do more experimenting as I move forward :wink:

1 Like

Well this seems to have cut the CPU usage in half (BTW, I couldn’t really set the ksmps locally: either the UDO doesn’t accept it or Csound doesn’t like that I’m passing global variables around; either way I’d get INIT errors, whether declaring inside the UDO or on the ‘GetColumn’ instr)…

opcode GetColumn,  0,  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
        if  kCurrentValue !=  int((kmy-iposy)/isize) then
            cabbageSetValue sprintfk("g%dc%d", id, icol), int((kmy-iposy)/isize)
            kCurrentValue = int((kmy-iposy)/isize)
        endif
    endif
    kPos cabbageGetValue sprintfk("g%dc%d", id, icol)
    cabbageSet 1, SGButChannel, "bounds", iposx+(isize*(icol-1)), iposy+(isize*kPos), isize, isize
endop

instr GUI
    kms     chnget "MOUSE_DOWN_LEFT"
    kmx     chnget "MOUSE_X"
    kmy     chnget "MOUSE_Y"
    
    MouseGridDraw   gig1cols, gig1rows, gig1size, gig1posx, gig1posy, gig1id, gig1init
    
    cabbageSetValue "g1c1", gig1init
    cabbageSetValue "g1c2", gig1init
    cabbageSetValue "g1c3", gig1init
    cabbageSetValue "g1c4", gig1init
    cabbageSetValue "g1c5", gig1init
    cabbageSetValue "g1c6", gig1init
    
    GetColumn   1, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
    GetColumn   2, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
    GetColumn   3, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
    GetColumn   4, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
    GetColumn   5, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
    GetColumn   6, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
endin

instr 1
    kms     chnget "MOUSE_DOWN_LEFT"
    kmx     chnget "MOUSE_X"
    kmy     chnget "MOUSE_Y"
    
    if kms == 1 then
        GetColumn   1, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
        GetColumn   2, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
        GetColumn   3, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
        GetColumn   4, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
        GetColumn   5, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
        GetColumn   6, gig1rows, gig1posx, gig1posy, gig1size, gig1id, kms, kmx, kmy
    endif
endin

///////////////////////////////////////////////////////////// INSTRUMENTS /////////////////////////////////////////////////////////////

instr 2
    kc1 cabbageGetValue "g1c1"
    kc2 cabbageGetValue "g1c2"
    kc3 cabbageGetValue "g1c3"
    kc4 cabbageGetValue "g1c4"
    kc5 cabbageGetValue "g1c5"
    kc6 cabbageGetValue "g1c6"
    
    cabbageSetValue "g2c1", kc1
    cabbageSetValue "g2c2", kc2
    cabbageSetValue "g2c3", kc3
    cabbageSetValue "g2c4", kc4
    cabbageSetValue "g2c5", kc5
    cabbageSetValue "g2c6", kc6
endin

</CsInstruments>
<CsScore>
i   "GUI" 0 .1
i   1 0 z
i   2 0 z

Nice. I haven’t had a chance to look over the code in any depth yet, but that’s nice work. You’re taking to this pretty quickly, for a Max/MSP guy :rofl:

1 Like

Haha, thanks! I had Dr. B as my teacher in college, so some of the Csound stuff is coming back :slight_smile: Still, I have a ways to go when it comes to programming! Learning a lot (and THANKS for all the help, forum & tutorials included). And yes, once you get past the ‘coding’ fear, it can be so much easier (AND powerful). Can’t wait to start developing instruments and musical ideas!

1 Like

So I think I’m giving up on the ‘mouse grid’ idea after all :pensive: …as I started getting a bit fancy with it, implementing multiple grids etc., setting and calling values became just too expensive on the CPU. I made this next version CB07.csd (7.7 KB) the traditional way, using check boxes, and it seems much cleaner. It would be great if we could just keep the mouse pressed as we drag through the screen (so much easier/quicker to operate for the user!), but if it’s going to have a high price tag on the CPU, not that important/worth it IMO (though perhaps using the “CURRENT_WIDGET” channel there might be a solution that’s not so expensive?).

Let me try some things when I get a chance. There might be way of creating this kind of behaviour.

1 Like

Btw, I just now pushed some changes to the cabbageGetValue opcode. It should perform much better now. You might want to see if it improves your original code. In the meantime, I’m still think about how best to realise your idea.

1 Like

Ok (thanks!!). Will download now and will give it a try when I get a chance (my interaction with the forum will be more sporadic this coming month as I’ll be traveling). BTW, in the Azure platform, should I be minding the various symbols under the various deployed versions (“running, success, etc.”)? I downloaded the 2nd to last release for now, just to be safe.

Thank you!

If there is an artifact at all it means the build was successful. But I just pushed another update now which fixes an issue in the last build. I think I have a workable solution for you. It’s kind of outside the box, but I’ll know before the end of the day if it will work.

So here’s what I did:

  • placed together several vsliders beside each other in a row.
  • then placed a simple transparent image on top of them all to prevent mouse interactions
  • created a filmstrip image that makes up an 8-cell column (code is here. Easier to code this than do it in an image editor) and added them to each slider
  • wrote a simple routine to update the current slider under the mouse.

This is the result, and it seems blindingly fast.

But it does mean you have to generate the grid images yourself in advance. On the other hand, the code is far more succinct and you won’t have to worry about keeping track of each column, as each is basically a native slider underneath it all.

Note: This uses the very latest build which I just triggered.

Here’s the bits and pieces.
SlidersGrid.csd (1.8 KB)
gridVSlider (4 KB)

Looks great! I’m away from my computer now but will check both latest update + codes when I get a chance :slight_smile: thanks!!

Can I ask, is there a special reason to set no. of cols & rows via chnset & chnget besides sending this init data between instruments? Would it be the same as setting global variables at ‘instrument zero’ (e.g. giCols & giRows) and if not, why would you prefer to do chnset/chnget instead?

I started working on it, BTW, and I’m tweaking a few things which I’ll share soon (also will look into creating horizontal grids as opposed to vertical ones).

Thanks!

Yes. It would be the same. I’m just not a fan of global variables even though channels are global in their own way too.

Can I ask why you’re not such a fan of global variables? And is it just more efficient to use chnset and chnget to pass data globally?

This is a 2nd edit for this post: I had encounter some “funny behavior” when using a filmstrip image for the horizontal grid and then learned that the filmstrip image is always ‘vertical’, hence: I have to work some more to create the appropriate code for both creating images and for creating a horizontal grid on the Cabbage GUI. I’m also looking to update the original patch you suggested so it reflects the same direction as a regular vSlider (min - max : bottom - top), a bit tricky since mouse movements are tracked in the other direction, but I think it’s possible!

Thanks!

It’s just personal choice, but I find they reduce modularity in a program. I don’t think chnset or chnget are any more efficient.

Just because the filmstrips have to be aligned vertically doesn’t mean you can’t create hslider with filmstrips. Check out the Knobman examples that ships with Cabbage. It has vertical, horizontal and rotary sliders that each use filmstrips.

Ok, thanks! I tweaked your original suggestion into two versions, a vertical & a horizontal grid.

BTW, I have another question related with regards to commenting etiquette –– I’m still kinda new working along with a community and just want to know what the common standards are: I left your credits as you wrote them in honor of your original code, but I moved the comments to the top of the file (is that OK?); can I / should I add my own (“adapted by…” or something of that sort) and place it say right below yours?

I started working on these following examples before my last question, so they implement global variables, but they’ll make it simple to understand init parameters etc. I also moved the code into an UDO so that one can have multiple independent grids in one same GUI.

Here are the codes for generating the filmstrip images in the p5.js editor: vertical & horizontal. I also adapted these so that image frames, h/v sliders, and mouse movements are all now aligned in the same direction, following the sliders’ original order as reference.

Below you’ll find the .csd files (hope these are useful!):

vSliderGrid3.csd (3.6 KB) vGridSlider7
hSliderGrid2.csd (3.6 KB) hGridSlider6

You can do as you like. CC-0 means that I specifically waive all rights to any credit. You are free to use it as you wish, I was merely implementing an idea that you brought to the table :wink: Although it’s not stated anywhere, I think code that is posted to the forum is public domain unless the author specifically states otherwise.

You’re excused :rofl:

Thanks for sharing these. I think it’s a pretty nice way of generating filmstrips.

These work very well. They are really quite fast. I wonder how well do scale. Have you tried some kind giant virtual Monome yet?