Cabbage Logo
Back to Cabbage Site

Mouse Grid

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?

I found a slight mistake in the overlay, it should be this instead (using left/top coordinates instead):

    SCode = sprintf("bounds(%d, %d, %d, %d), channel(\"overlay%d\"), colour(0, 0, 0, 100)", iLeft, iTop, iSize*iCols, iSize*iRows, iId) 
    cabbageCreate "image", SCode
1 Like

Ok!

Haha! Ok :wink:

Yes! It’s a new discovery for me, p5.js. It’s a great way to learn programming as you can map things visually quite easily! Will look into generating ‘proper’ filmstrips as well (not just quantized to a small number but to give the full range to each slider). Have you found some ‘magic’ number of frames to use? Is using MIDI resolution (127 frames) an OK amount or is that overkill (I noticed in some examples there were as much as 30 or so frames for ea. filmstrip image).

Thanks! Yes, agreed! I also did a quick test exporting these to a VST/AU and both: a) having a straight ‘filmstrip’ slider and b) implementing the mouse polling had the same 1-2% dent on the DAW’s CPU meter (running Live on a 2015 Mac laptop).

As to the Monome idea, it sounds like a great plan! But first, I want to start building instruments for the Sensel/Thunder (I started with a M4L MIDI device but I’m thinking more and more of building various sound engines myself on Csound/Cabbage –– perhaps implementing some kind of OSC send/receive protocol to send slider data to other plugins etc. –– I’ve found MIDI implementation for VST/AU quite fuzzy on potentially limiting, this rather from the DAWs point of view –– it seems to me they each impose their own rules about it). For those using the Sensel or if you’re curious, you can check out this video, which documents that work :slight_smile:

I think size is the only real limitation here. The bigger they are the more memory they take up. Note that the number of frames doesn’t affect the slider resolution. It will still move in the smallest possible increments even if the frame has not updated.

The Sensel is really nice. I wish it had been around when I first started messing with MIDI controllers :frowning:

1 Like

Nice. That was the real question to ask :slight_smile: thanks for the answer!

Yes, I’m excited to explore its possibilities –– and those of Csound: it seems to me that the two together are quite a match!

Sorry: as I started implementing these I found more mistakes. Here are the UDOs updated:

opcode GridDraw, 0, iiiiii
    iSize, iCols, iRows, iLeft, iTop, iId    xin
    
    iCount  init    0

    while iCount < iCols do
        SCode   sprintf "bounds(%d, %d, %d, %d) channel(\"g%dc%d\") range(0, %d, 0, 1, 1), filmstrip(\"vGridSlider%d.png\", %d, valueTextBox(\"0\"), popup(\"0\")", iCount*iSize+iLeft, iTop, iSize, iSize*iRows, iId, iCount+1, iRows-1, iRows, iRows
        cabbageCreate "vslider", SCode
        iCount+=1
    od
    
    SCode = sprintf("bounds(%d, %d, %d, %d), channel(\"overlay%d\"), colour(0, 0, 0, 100)", iLeft, iTop, iSize*iCols, iSize*iRows, iId) 
    cabbageCreate "image", SCode
endop

opcode GridCtl, 0, iiii
    iSize, iCols, iRows, iId    xin
    
    kMouseDown  chnget "MOUSE_DOWN_LEFT"
    kMouseX     chnget "MOUSE_X"
    kMouseY     chnget "MOUSE_Y"
    
    SOverlay    sprintf "overlay%d", iId
   
    iOverlay[]  cabbageGet SOverlay, "bounds" 
    iLeft       = iOverlay[0]
    iTop        = iOverlay[1]
    iWidth      = iOverlay[2]
    iHeight     = iOverlay[3] 
   
    if (kMouseX > iLeft && kMouseX < iLeft+iWidth && kMouseY > iTop && kMouseY < iTop + iHeight) then
        kColumn = int(((kMouseX - iLeft) / iSize) + 1)
        kVal    = int(((kMouseY - iTop) * -iRows / iHeight) + iRows)
        
        if kMouseDown == 1 then
            SChannel = sprintfk("g%dc%d", iId, kColumn)
            cabbageSetValue SChannel, kVal
        endif
    endif
endop
1 Like