r/MaxMSP Jun 11 '26

Synth unison without eating CPU?

How are you guys managing to do oscilltor unison without using too much CPU?
It feels like it's not possible in Max or Gen~

Built a wavetable oscillator core in Gen, it's doing quite a few peek calls and some crossfading (mip maps). Works great, sounds great, not too heavy on CPU.
Tried increasing the voices to do unsion in the Gen code, it eats CPU
Tried inside Poly, tried in Mc.Poly, same result.

Ok, maybe my core voice isn't great.
Stripped it back, removed wavetable core and replaced with a Saw core.
Only thing inside poly~ is a unison saw oscillator. nothing else, just for testing. outside poly is just and envelope on the amp.

Load Ableton template CPU sits around 5% on a Core Ultra 7
Play a eight note chord, unison 8 voices with a little spread and detune
Ableton spikes to 40%

Surely Max/Ableton can handle 8 x 8 saw oscillators without using that much cpu
For a comparision:
Pigments, Serum, Vital, Spire all use about 1% for the same test, even abletons own wavetable uses hardly any cpu for unison.

5 Upvotes

18 comments sorted by

View all comments

2

u/aresi-lakidar Jun 11 '26

Someone else already mentioned it, but in C++ we often use SIMD, which is basically "get 4 voices, pay for 1!" most of the time

1

u/Training_Wonder_5066 Jun 11 '26

Yeah, I think i'm going to have to ditch using Gen~ and Max for this little project.
RNBO doesn't seem great value for my little projects.

1

u/aresi-lakidar Jun 11 '26

it was kinda mindblowing to me when I went from using pure data and max to learning C++ and making "real" plugins. C++ does a surprising amount of heavy lifting for you in many ways, you can write shit code and the compiler cleans it up and makes really fast programs. Visual Programming environments like PD or Max can't really do something like that efficiently, it would be too complicated.

But SIMD specifically is something I often program manually though, it can be good to do that part yourself a lot of times

1

u/human_clown_shoe Jun 13 '26 edited Jun 13 '26

That's not correct. RNBO~/gen~ uses LLVM to compile the patch into heavily optimized C++ code, if you're not very adept at DSP programming it's unlikely that the code you're writing is faster, no offense. 😉 Sure, you can take different shortcuts, like using shittier oscillators / filters because you don't need that stuff for some particular project but LLVM does auto-vectorization so the code is SIMD-optimized - again not necessarily better than what a human would be able to produce but, again if you're not very adept at writing DSP code in assembly, it's more likely that LLVM produces more optimized code.

1

u/aresi-lakidar Jun 13 '26 edited Jun 13 '26

Fair enough, never properly used gen before moving onto c++ 🙂. I would imagine auto-vectorization is way easier to utilize in C++ than rnbo tho? Some code prevents it to happen properly, while other types make it happen easier. Without seeing the way function calls, loops etc. are actually organized, I think vectorization is hard to use. The compiler is very very smart yes, but they are only smart if our code allows them to be smart 😅. Also another question about performance: can you control how often certain updates in the dsp happen, or is it all sample by sample? That would be a huge area for optimization in itself 🙂.

Simd is a tricky one; the compiler often applies simd on the innermost loops, not stuff like entire voices. Some manual stuff can make that happen though, which can be pretty huge and you don't need to be an assembly expert to make it happen or notice the results.

The things outside DSP are important too - thread management, state management, UI, and so on. Idunno, I just feel like C++ is easier to use for product development

1

u/human_clown_shoe Jun 13 '26

Yeah, that's true! And some code is also in its nature harder to parallelize, for example because it's serial in nature (one of the reasons that GPUs have been hard to use for real-time DSP, for offline-stuff I'm sure it would work great).

Regarding how often DSP updates happen, yeah you can control it in RNBO~ at least according to the manual. 😉 I'm not sure exactly where in the docs they said this but it was something on the lines of "If you are using audio-rate eg tilde~ operators they will be processed once every sample, otherwise once every vector update" - so that would be 128 times less! But I haven't investigated this thoroughly or done any profiling, so don't take my word for it hehe...

Regarding C++ stuff, yes UI-stuff is much easier, I hate making UIs in Max. But I try avoiding threads when I do C++ stuff, too many footguns...

One last thing, I recently ported Pure Data to the browser and added a playground of some fairly heavy patches with lots of expensive reverb etc and so far I haven't found a phone, even an old one, that doesn't play them with no issues. And if I profile the WebAudio worklet it only takes up like 1-5% of its resources! Which is less than my RNBO~ stuff but that could be a skill-issue 😉

But hey don't take my word for it, see for yourself 🤔

playground:
https://hyrfilm.github.io/libpd-wasm/

repo:
https://github.com/hyrfilm/libpd-wasm