-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow using numpy arrays for mapping Grids and Arcs #11
Comments
Hey @ambv, thanks for the suggestion. For pymonome and especially aiosc I would rather avoid having heavyweight external dependencies though. Does it not work for you if you initialize GridBuffer once (e.g. in on_grid_ready callback)? |
Oh, I see. You problem is allocating the OSC message itself, sorry. I've never experienced any delays in refreshing grid at 30 fps myself (I have a 256), could you share the sample code that exposes the issue? |
I understand you don't want to add
Not really because the |
If the buffer would be a 1-dimensional list would that improve performance without introducing an optional numpy dependency? |
If you really don't want to make
We'd still maintain:
I think allowing numpy arrays would be better because numpy's it's the fastest option and it's got a lot of mindshare in Python. The changes to Making Buffer instances work with Making Buffer instances use single-dimensional Here's my testing code: The latest revision uses numpy. The previous revision uses pure Python data routines that created buffers with every frame. The numpy version is butter smooth on Python 3.11.1. The previous revision has occasional stutters of a few frames. I can't see it on the Grid, but it's more obvious to me on the Arc because the pixels are much closer together and so smooth movement look like solid motion while stuttery movement breaks the illusion. |
Yep, array.array is a cool idea. I'd happily pull the change to the repo. As for numpy arrays - is it a viable option for for your use-case to convert numpy array to bytes at the application level? |
Yes, if you supported passing bytes directly to |
|
I haven't tested that. It just seems wasteful to me because I'd be unpacking the bytes unnecessarily on one end only to repack them again one-by-one on the other end. |
Right, but also bytes->blob is a pretty straightforward type mapping in the current arrays (numpy or lists) can be converted to OSC in more than one way on the other hand, and your initial proposal is about having It should be also possible to work around the conversion entirely by generating raw OSC completely in your drawing methods and using |
There is no hurry in developing the API well here. I personally care about making things efficient by default so that |
Sure thing, I care about efficiency as well. But I'd argue that pymonome is quite efficient for practical usage already :) My live setup is also a grid + arc (sometimes 2 grids + arc) with a lot of bidirectional OSC traffic going between serialosc, the controller/sequencer scripts and the audio engine. There's a lot of grid redrawing going on constantly with several off-screen (off-grid) buffers. Not so much animations on the arc, but the rings react very well to user input. There's a noticeable CPU overhead in the entire controller app since I've switched to asyncio, likely related to a lot of i/o polling happening under the hood, but I'm getting it with or without rendering. I also rarely (if ever) do zeroing of the LED buffers. Instead, the rendering loop body typically fills the entire buffer in most of my scripts. That said, extra optimization would never hurt. With the solution above I have some doubts though - it's a bit hackish, and it's a really neat hack! But it caters to a rather specific way of concatenating a numpy array to the rest of the arguments (breaking the consistency of 1:1 mapping of I'm glad to discuss this or other approaches further to solve the original issue of course. FWIW, here's the output of your test script I'm getting with regular Python lists and uvloop, visibly things are smooth:
|
Thanks for the awesome asyncio-first library. Works really well.
I was able to get Grid + Arc consistently output at 30fps with ~90fps logic updates without stuttering. To achieve this, I had to switch from using
GridBuffer
andArcBuffer
which allocate the entire map every frame. Instead, I used a numpy array that I simply zeroed between frames, which is measurably faster.To make this work, I had to make two changes:
Add
grid.led_level_map_raw
andarc.ring_map_raw
methods that don't unpack*data
but simply passdata
directly to OSC.In
aiosc
, I added support for numpy arrays inpack_message
without importing numpy by doing this:With those changes, numpy arrays passed to the new methods allow reusing the same memory buffer and are very efficiently translated to bytes entirely in C land (with
arg.tobytes()
above).Would you be interested in pull requests to upstream my changes?
The text was updated successfully, but these errors were encountered: