IIRC g:all(0) is setting every led to brightness 0 so it shouldn’t need to be called for each position on the grid. I’d recommend taking that out of the loop. The g:refresh() call sends the currently dirtied led quadrants to the device so that should normally be called outside the loop after the leds have been set. As is the code is effectively updating an entire quad per grid position.
Without g:all(0) the LEDs stay on. I can probably speed it up by just setting the previous one to 0 - more efficient. In any case, I’m writing a high-level renderer so for now I’m mostly interested in performance testing rather than specific output.
Odd that g:all() causes the problem - I wonder what makes that particularly expensive? (I have the grid serial communication spec. somewhere, so should look it up.)
Sending all(0) with each refresh cycle is essentially marking all four quardants (4x64) as dirty which means that the next call to refresh will send all 256 leds values across the serial bus:
…the implementation of the all function - it is looping over every position in the buffer and setting the led value:
…the implementation of the refresh function:
The expensive part is the result of calling all(0) and refresh() inside of a tight loop because it is forcing the entire 256 leds grid state to be updated (redundantly) for every position in quick succession thus overwhelming the grid’s usb bus. If the goal is to essentially draw a single “pixel” moving over the grid I fairly confident you’ll have much more success:
keeping track of the previously enabled led and turning it off specifically to avoid dirtying every grid quad
using a metro or the new clock system to rate limit calls to refresh() to something under 60Hz (which is about the fastest I’ve seen)
EDIT: The 4th study shows how many/most scripts work by redrawing grid state on demand or periodically (from a metro) when the leds state is known to need updating.
grid should be fine at 30 or even 60 fps with full-frame updates. i think the issue is the test you’ve devised (i believe) doesn’t actually function as a speed-test. it’s doing a fast-as-possible (ie, all-at-once) refresh 128 times in as short of time as possible. (@ngwese explains how the core code is operating above).
here’s maybe a better way to speed test:
while true do
x = (x+15) % 16
and then tune the 1/60 to the desired frame rate.
you can do a fancier animation if you want of course. the only “bandwidth” to the grid via serial (libmonome) is grid.refresh so that’s what should be conditionally called at high speeds. complex drawing is just memory manipulation and should have no real impact on performance.
Yep, I guess what I should be doing for my purposes right now is sleeping at 1/60 between refreshes, and then for my own code measuring whether I’m getting the full 60fps or starting to slow down. Maybe I should write a quick amortized frame rate calculator.
(Btw, this is all for the shado renderer, which I now have partially up and running in Lua.)
True; shado 10 years ago was written in Java and scripted in Python, so there was a definite barrier between the Max world and the JVM world. With the entire environment in Lua, shado is just another norns library and there’s no impedance mismatch for users.
The impedance mismatch for me, on the other hand, is that shado is essentially a scene-graph library so I’m not sure it can benefit from the quadrant optimisations at all, unless I duplicate that machinery at the Lua level, which feels a bit daft. But its performance might be quite acceptable anyway doing full refreshes - certainly, it was when driving monomes from a MacBook over OSC.
As an aside: it would be good to dig out my original m128 and greyscale 64. What are your thoughts on supporting the original on/off models? Is there still a user community for them?
I don’t know the precise nature of the Lua/C interface or the computational complexity of Lua’s data structures (though everything seems to be stack and index based), but it might be that a primitive to blatt out an entire quad at a time from a numerically indexed Lua table is more useful.