I just made it so that TGrains can accommodate any N channel panning algorithm.
If the user creates a custom grain and then uses next_multi_channel as the next function for the grain, they can put dbap or the future vbap implementation inside the function and pan each grain individually around the multi-channel space.
The vbap2d function should be working properly now! Scaling up the math for 3d should be pretty easy but I want to make sure that the 2d implementation is good first.
Also, the fake mouse isn’t working on WSL at the moment, though there must be some reason for this. I can do a bit of tinkering and see if I can’t figure out why. I’m assuming it’s some funky interaction with WSLg? Currently the values jump back to center every time the slider is moved. I don’t think this is a huge deal, I can try to find a workaround and document it.
edit: Actually, the fake mouse is working now? I’m not sure why that was happening but it’s no longer an issue.
edit again: The fake mouse is broken again! No idea what breaks it…
I wonder if this is a timeout issue in python? sometimes the mouse also doesn’t work. i think this is because compilation takes too long and then the mouse startup doesn’t happen.
One solution is to compile the executable separate from running it:
MMMAudio.compile(“MyVBAPExample”, “examples”)
Then when you run it there is no delay for compilation.
Tried to precompile the executable and still no luck. I think this might be a different issue for WSL. My Linux desktop doesn’t have this issue. I don’t think it’s worth the effort to support WSL mouse support out of the box though (assuming that Mojo will eventually come to Windows…). I can make a bandaid fix for myself and then if others are trying to use WSL they can reach out to me and I can make it available.
That seems fine to me. I think MMMAudio probably doesn’t need to provide “mouse” support “out of the box” for any system (there might be other dependencies not needed too). Keeping the necessary dependencies slim might be wise.
The nice thing about mouse support as it currently exists is that there is a dedicated Messenger path to get the mouse value onto the audio thread, but patching a Messenger path is quite straight forward so might not be a big loss.
If one wants to turn on the pyautogui mouse but MMMAudio doesn’t require it as a dependency, I could imagine something like this,
import pyautogui # user needs to install and import it
MMMAudio.pyautogui_mouse(true) # turn it on, or with false, off
Or instead of passing in true a callback function is passed in that gets the x and y position on every update?
That way it’s not on by default, but MMMAudio still has a really slick way to use it.
I really like the idea of passing a callback function in, being able to change the mouse mapping on the python side instead of the mojo side would save some time when making changes. I think requiring the mouse to be turned on or off would fix the weirdness happening on the WSL end as well (I think it’s getting conflicting mouse and GUI info). It could possibly look like this:
vbap2d looks great. i thought it was all messed up, but then i realized i was all messed up and forgot that a right angle is 90 deg not 45.
question - can one essentially get a 3d dbap panner from by interpolating between two dbap rings based on height? one of my students did this with pan_az and it was pretty convincing. obviously, vbap3d has a predefined algorithm, but a faked one with this method would probably be fairly close.
That’s essentially what LBAP (Layer-Based Amplitude Panning) is! It just interpolates between adjacent DBAP “layers”. My plan for LBAP is to allow for an arbitrary number of layers as an array of arrays once dbap3d and vbap3d are in a good spot.
I think for VBAP this sort of approach won’t be as convincing considering 3D VBAP relies on speaker triplets for positioning the source although that’s just a hunch.
It’ll probably be a little bit before I have more time to work on vbap3d. The biggest roadblock at the moment is determining the speaker triplets algorithmically. This isn’t truly necessary, users could define the speaker triplets themselves, but it would be nice to have.
My current thinking is to take the azimuth/height pairs, convert them to UVs, and then use something like Delaunay triangulation to determine the triplets. Unfortunately there isn’t an implementation of Delaunay triangulation in Mojo yet that I can find (meaning I would need to write it…). Any thoughts on this would be welcome!
If you can find a Python package that does it, you might use that inside Mojo. See MMMAudio’s MLP for an example of what that might look like. I would try to keep the PythonObject stuff out of the audio loop if possible, so if you can, use it all in __init__ to get the data wrangled that you need and then be able to just use pure Mojo in the .next.
Let me know if you want a pair of eyes on it or you want to chat through it!
Thanks for the suggestion! I know that scipy has a Delaunay implementation so that would work! Just making sure about the approach, but would the idea be to make a Mojo struct like VBAP3DSpeakerArray and then use the python stuff in that struct’s init? I’ll definitely reach out if I have more questions, thanks so much!
Yes. I’m not 100% sure, but I think I’ve observed that using PythonObject things in Mojo code has a bit of cpu overhead (if only needing to convert the types), so avoiding it is wise. Does @spluta agree?
For somethings (like the PyTorch use in MMMAudio’s MLP struct) it is impossible to avoid using a PythonObject. Take a look at MMMAudio’s PCA and StandardScaler which can be found in Data.mojo. You’ll notice that the internal data for those objects is loaded from disk “through” PythonObjects which then populates data structures that are native Mojo Lists. That way, what is actually used in the audio thread is “Mojo fast” not needing to convert back and forth with PythonObjects.
I thought about doing this for some of the audio analyses as well (since FFT analyses are mostly just linear matrix operations), but I decided to fully port those for reasons.
Using PyTorch in the MLP is cool because you aren’t going to call it 48000 times per second. More like 50. If this is just going in the init function, it is no problem at all. If it is going in the audio loop, that is a different story.
FYI - when I created the FFT, I implemented it with numpy first then made my own FFT. So I would get this working with PythonObject, then see if you need to modify it later.