Home › Forums › General › Programming › Arpeggiator
Tagged: component, drawRect, fillRect, Rectangle(), setBounds
- This topic has 16 replies, 4 voices, and was last updated 3 years, 8 months ago by Tedjuh.
-
AuthorPosts
-
August 21, 2020 at 1:37 pm #119460
For my panel I need up to 512 blocks to be painted. They should be named block1,block2, block2,etc. because they need to be able to vary in size. In the init file I create the block1. Block1=(). In the paint file I do block1:setBounds() and to draw the rectangle I do: block1:drawRect(). I see the block. So far, so good.
But how to generate 512 of them when iterating? When I do: string.format(“block%s:setBounds()”,i), the block returns nil. Same with g:drawRect(string.format(“block%s”,i),1)). Tried the toFloat.. but to no avail. Tried a table, again nil. Is there someone that can tell me what I’m missing here?
August 21, 2020 at 2:12 pm #119461a={} for i=1 , 512 do a = "block"..i.."=()" end
a[9] –> block9=()
August 21, 2020 at 2:25 pm #119462a={} for i=1 , 512 do a = "block"..i.."=()" end for k,v in ipairs(a) do print (v) end
August 21, 2020 at 3:01 pm #119466Behind the “a” that follows the word “for” , there have to be rectangular brackets surrounding i.
I am unable to show these in code in WordPressAugust 21, 2020 at 8:38 pm #119468Thank you for the input but you are creating a table as far as I can tell. But in the paint script I can’t do something like a[9]:setBounds(). It will return nil.
But first let me try to create 512 rectangles like: block1 = Rectangle(). Something is wrong with my syntax or way of thinking how to do it.
For i = 1,512 do string.format(“block%d = Rectangle()”,i) end
Returns nil, probably because it’s a string.
But block..i.. = Rectangle() gives an error telling me there can’t be concatenation before =.Bit at a loss here, is it possible at all to do it with a for loop?
August 21, 2020 at 10:29 pm #119469I don’t see exactly what you want to do. Why do you want to add =Rectangle() to the variable? Couldn’t you do something like i=Rectangle() and i being Block1 to Block512?
Edit: no of course that won’t work either… Maybe if we now exactly what you want to do then it would be easier to make some suggestions. E.g. when you draw some graphics, do you use the uiCustomComponent? Probably. You would need to set coordinates for the rectangle otherwise they will all draw over themselves. Or do you use a dedicated uiCustomComponent for each rectangle? Probably not, that would make the panel too complex.
- This reply was modified 3 years, 8 months ago by Possemo.
August 22, 2020 at 10:43 am #119477Warning, very long post:
To get an idea of what I’m working at, see attached picture 1. The GUI is still work in progress.
— On top: comboBox that controls the number of steps (1-32). (Working)
— At the bottom: Vertical bars to set the velocity (0-127) for each selected note. (Partially working)
— To the left: A slider to be able to scroll: (Working)
— In the middle: PianoBar (Black and white blocks) from C-1 to G9 (127 notes) (Now on middle octave)
— To the Right: NoteBar (White and grey Rows) to set the position of the note in steps (1-32)Everything except the comboBox and Slider are separate uiCustomComponents. Later to be made as one big uiCustomComponent. But for starters..
What’s working for now:
Sysex, generated with mouse events. Synthesizer accepts it and plays it the right way.
— The Sysex is also used to paint the blocks. The paint script iterates over the Sysex to define the note (0-127), which position (1,32), the width (1,32) and last but not least the velocity (1,127) to be painted.
— By double-clicking on the piano bar, the note bar gets emptied.
— When I click on a row, a red block gets painted on mouseDown.
— Blocks are deleted when double-clicking at them.
— No overlapping of blocks possible if the Sysex is correct.
— When I mouse over a block, you are able to drag it to become wider or smaller.But when I dragged one of the blocks, they all became wider or smaller. I figured that it had something to do with not naming different blocks. In the Juce Graphics Class I can call a Rectangle like:
void Graphics::drawRect (Rectangle< int >rectangle,int lineThickness = 1 ) constSo I figured, create different named blocks. Tried that with the following codes:
In the init file the block gets created:block1 = Rectangle()
In the paint script I do:
(x,y,w,h and l are all set)if arp1:getByte(1) > 0 and arp1:getByte(1) < 128 then g:setColour(Colour(0xFFFF0000)) block1:setBounds(x,y,w[width],h) g:drawRect(block1,l) end
Read something about square brackets not being shown on this forum. At some mouse events there’s some calculation done that gives a value that is being read from a table with x[1] and w[width]. x = position of the block in height, w is the width of the block.
I am able to set different colors, widths, heights and so on for the blocks when I add more blocks to the init file and call them in the paint script with block1, block2, etc. (See picture 2.) I can even paint blocks on different notes. (Disabled for now). That is all working.. it’s just the naming convention for the graphics class that’s bugging me.
According to the Sysex implementation I can select 16 different notes with 32 positions each. So, a max of 16×32 = 512 “possible” blocks. Now I don’t mind some coding but.. that would mean a hell lot of code. Just to create 512 Rectangles, let alone do the same for the code above for 512 different rectangles. So, first I want to be able to create 512 blocks/ rectangles, to be able to call them separate from each other in the paint script. But I can’t even seem to do that..
For instance if I want to number different modulators I do:
for i = 1,512
panel:getModulatorByName(string.format(“block%s”,i)):getComponent()
endIt’s working because the modulatorName is a string. But I’m not adding a modulator, right?
for i = 1,512 do string.format(“block%s:Rectangle()”,i) end (Doesn’t work, string)
for i = 1,512 do block..i..= Rectangle() end (Doesn’t work, gives error no “..” allowed before “=”)
Creating a table..
bRectangle = {}
for i = 1,512 do
bRectangle = “block[“..i..”] = Rectangle()”
endDoesn’t work either because I can’t call:
bRectangle[1]:setBounds() or
g:drawRect(bRectangle[1],1)
in the paint script. Both return nil.Anyone? 🙁
Attachments:
You must be logged in to view attached files.August 22, 2020 at 11:03 am #119483He Tedjuh,
Does
for i=1,512 do _G["block"..i]=Rectangle() end
work?
Note: When posting iterators you can’t use [i] because it is interpreted as BBCode for italic formatting, therefore the unclosed [i]text[/i] is deleted, so you need to substitute something like [j]
August 22, 2020 at 12:22 pm #119490This code seems to work!
paintc = function(--[[ CtrlrComponent --]] comp --[[ CtrlrComponent --]], g) local x, y, w, h = 20, 30, comp:getWidth(), comp:getHeight() backdrop = 0xff99ccff g:fillAll(Colour(backdrop)) g:setColour(Colour(0xff000000)) for i = 1, 512 do _G["block" .. i] = Rectangle() end g:setColour(Colour(0xff000000)) block502:setBounds(x + 20, y + 20, (w / 2) + 20, (h / 2) + 20) g:setColour(Colour(0xffffff00)) g:fillRect(block502) block500:setBounds(x, y, w / 2, h / 2) g:setColour(Colour(0xff000000)) g:drawRect(block500, 2.5) block501:setBounds(x + 10, y + 10, (w / 2) + 10, (h / 2) + 10) g:setColour(Colour(0xff000000)) g:drawRect(block501, 2.5) end
Attachments:
You must be logged in to view attached files.August 22, 2020 at 12:49 pm #119492I’m going to try the code you gave Dnaldoog. Looks promising. I swear I found the _G[] thing in some old forum posts from human fly but I got the wrong syntax doing _G[block ..i.. ], without the ” “. So close, argh.
Just one question. Is it possible to do the same to the g:setBounds() or g:fillRect() ? Like _G[“block” ..i]:setBounds() ?
I could try this myself. Was just wondering :). But thank you already. Like so many times before.
August 22, 2020 at 2:05 pm #119493Hi Tedjuh!
_G["block" ..i]:setBounds()
would work as long as you have already declared an object `_G[“block” ..i]:Rectangle(). so I guess they could be included in the same loop:paintc = function(--[[ CtrlrComponent --]] comp --[[ CtrlrComponent --]], g) local x, y, w, h = 20, 30, comp:getWidth(), comp:getHeight() backdrop = 0xff99ccff g:fillAll(Colour(backdrop)) g:setColour(Colour(0xff000000)) for i = 1, 512 do _G["block" .. i] = Rectangle() _G["block"..i]:setBounds(x,y,w,h) end g:setColour(Colour(0xff000000)) -- block502:setBounds(x + 20, y + 20, (w / 2) + 20, (h / 2) + 20) g:setColour(Colour(0xffffff00)) g:fillRect(block502) -- block500:setBounds(x, y, w / 2, h / 2) g:setColour(Colour(0xff000000)) g:drawRect(block500, 2.5) -- block501:setBounds(x + 10, y + 10, (w / 2) + 10, (h / 2) + 10) g:setColour(Colour(0xff000000)) g:drawRect(block501, 2.5) end
You could then dynamically change the x,y positioning within the loop
Regards,
John
August 22, 2020 at 6:27 pm #119498Why not generate the renctangles on the fly according to the mouse position? You have to query the mouse position anyway, don’t you? Instead of selecting a predefined rectangle when a mouse x and y is within a specific range, just draw the rectangle. You will have to calculate x and y – well I don’t know but I guess there must be an elegant way to do this. Hmm, ok when I look at your pictures you probably want to be able to shift the rectangles when you move to higher or lower note range… and you will have to be able to clear them when you click an already drawn rectangle again.. quite some coding work. Well yes, maybe it is easier to predefine all rectangles. It will be interesting to see if this works.
August 22, 2020 at 10:31 pm #119500Why not generate the renctangles on the fly according to the mouse position?
Because there is no viewport class imported to ctrlr (There is one in juce though.), I need to do some trickery to create the sense of a viewport.
So when I scroll up or down, all coordinates for the black and white lines are read from a table. Later, the Sysex is being read and paints the rectangles. Because the Sysex are 16 different MemoryBlocks, one for each note, I’m even able to do the repaint per note instead of repainting the whole component.
Elegant? Maybe not. There is indeed a lot of calculation going on in the background. Lots of if else then statements on the mouse events. Lots of getByte and setByte. Lots of repaint. But it is almost working as intended.
With the Rectangle class being up to date or a viewport class, it could have been more elegant but unfortunately that isn’t the case. No Biggie but it means a lot more code than needed, yes.
Gonna give your code a try now, Dnaldoog. You’ll hear from me soon.
August 23, 2020 at 12:03 pm #119502Hi Tedjuh,
I got to thinking that Possemo’s suggestion of on the fly mouse creation was excellent.
You can avoid those cumbersome loops and probably super complex code.
Here is a panel that creates a `fillRect’ on the grid where the mouse was clicked. Instead of generating vertical and horizontal lines, you could have a mock png image in a different layer as backdrop.
You would then have to move the image according to your scrolling modulator or alternatively redraw the graphics lines in the component and offset the mouseclick y coordinate. It’s probably not too difficult finding the new coordinates that way although I haven’t got that far yet.
Here is the code. ※ Variables
mpX
andmpY
are mouseUp coordinates. (see below)paintMe2 = function(--[[ CtrlrComponent --]] comp --[[ CtrlrComponent --]], g) g:setColour(Colour(0xff000000)) local height = comp:getHeight() local width = comp:getWidth() local x, y = 0, 0 local wDiv = width / 32 local hDiv = height / 16 --************************************ --draw surrounding area g:drawVerticalLine(width - 1, 0, height) g:drawVerticalLine(0, 0, height) g:drawHorizontalLine(0, 0, width) g:drawHorizontalLine(height - 1, 0, width) -- end draw surrounding area --************************************ local verticalCoords = {0} local horizontalCoords = {0} for i = 1, 32 do g:drawVerticalLine(wDiv * i, 0, height) table.insert(verticalCoords, (wDiv * i)) end -- loop 32 horizontal for i = 1, 16 do g:drawHorizontalLine(hDiv * i, 0, width) table.insert(horizontalCoords, (hDiv * i)) end -- loop 32 horizontal for j = 1, #verticalCoords do if verticalCoords[j] > mpX then x = verticalCoords[j - 1] break end end for j = 1, #horizontalCoords do if horizontalCoords[j] > mpY then y = horizontalCoords[j - 1] break end end local rec = Rectangle(x, y, wDiv, hDiv) g:setColour(Colour(0xff0000ff)) g:fillRect(rec) end -- function
Other functions:
mouseUp = function(--[[ CtrlrComponent --]] comp, --[[ MouseEvent --]] event) repaint_component() end mouseMove = function(--[[ CtrlrComponent --]] comp, --[[ MouseEvent --]] event) mpX = event.x mpY = event.y end repaint_component = function(--[[ CtrlrModulator --]] mod, --[[ number --]] value, --[[ number --]] source) panel:getComponent("c"):repaint() end
This code must be lean, because when doing debug prints of the tables to console(), it doesn’t slow down the program much!
- This reply was modified 3 years, 8 months ago by dnaldoog. Reason: fixed missing [i]
Attachments:
You must be logged in to view attached files.August 23, 2020 at 8:10 pm #119508Appreciate the work you put into this Dnaldoog. Funny thing is, I already wrote most of the code like you did but “with” the scrolling part. I never got the IMG to work so I did it all with painting.
The thing I’m not doing (yet) is creating rectangles on the fly because I wanted to avoid the inserting and deleting values in tables.
It’s hard to explain the way I do it now and I promise to send you a mail later with the panel. But I discovered a major f*ck up. I discovered ctrlr overwrote my old save while I thought it was saving to a new version.
Actually it is. Even I’m opening arpbuild4.. when I save it, it says it’s saving to arpbuild3. Great.. give me some time to rewrite some code and I’ll send you the new version later.
August 24, 2020 at 11:11 am #119513Ok, after giving Possemo and dnaldoog’s advice some thoughts. I think it’s a better idea to separate the Sysex and the building of the rectangles in the arpeggiator. It should mean some rewriting of the code but that is not a big deal. Dnaldoog gave me a headstart.
In other words, thank you for the advice.
August 25, 2020 at 1:56 am #119519Getting there. See animated gif.
Lots of things to finetune. Also need to get the velocity bar at the bottom to work. Make it switch velocities on mousedown according to the note that is selected. But getting there.
Thank you all.
Attachments:
You must be logged in to view attached files. -
AuthorPosts
- The forum ‘Programming’ is closed to new topics and replies.