How many oscillators can I run?

Hello everyone,

I am working on designing a subtractive synth and was trying to see if I could run polyphony with independent LFO’s for each stage. I know this is not the typical synth architecture but I wanted to experiment with what kind of sounds I could make with that kind of layout. So each voice requires the following:

6 oscillators (2 vco square, 4 lfo triangle – I am fine with avoiding expensive sine calculations for now)
white noise
5 envelopes
1 moog ladder filter

Since the voices are all 100% independent from each other that means each additional voice of polyphony supported multiplies all of these numbers. I can run three voices (18 oscillators) all responding to a MIDI keyboard along with delay and reverb, but the output stops dead when I try to add a fourth (24 oscillators). There is nothing, just silence. Removing the delay and reverb doesn’t help all that much. I know that I need to add some CPU utilization metering to track what’s going on, and that’s probably my next task, but I was wondering if anyone had a kind of ball park estimate on whether this seems like too much for the Daisy processor or whether it really should be able to run dozens of oscillators just fine and I might have something else wrong with my code.

I can always revert to the more standard 2 LFO’s for the entire synth type of situation if it’s just not going to be possible – but thought I’d see if someone had some experience with how much the chip can reasonably be expected to handle.

Thanks!

-Kenji

Hi Kenji!

It’s cool to hear that you’re pushing Daisy to its limit!

CPU metering will definitely help you keep track of where the CPU load is. The load could even be from non-audio related things in the code.
If you don’t mind, feel free to post the code as it could be something else other than the oscillators.

Krakenpine’s Daisy Harmoniqs might be a good reference for you. It’s a “Ten voice additive oscillator synth. Every voice is comprised of 8 sine wave…”. And the CPU load when playing all ten voice is on average about 26% (the load is mostly from printing bunch of stuff to serial port). I think the block size was 32. And it’s still being optimized today.

It could be fun to ask in the Discord what’s the farthest anyone has pushed Daisy! Feel free to join and ask that. I’ll update this post if there’s a general consensus.

Oh wow. If they can run 80 sine waves with that kind of load then it doesn’t sound like it’s the oscillators causing the problem. My source code is below. Reverb and delay are re-enabled in this version of the code:

I am using it with a Daisy Pod. For some reason when I increase the voices to 4 it seems to be either dropping frames or crashing/hanging or something. I also get frame dropping if I try to move the reverb to SDRAM. Changing # of voices is on line 18 of KiwiModular.cpp:

const int NUM_VOICES = 3;

I’m going to work on performance monitoring, but I am starting to suspect that that’s not what’s causing the problem.

It does sound like the best course of action is to start scaling back while monitoring the CPU in order to find the culprit of the load. That’s typically how I deal with mitigating CPU overloading right after doing a quick prototype session.

I’ll have a closer look at the code and let you know if something is jumping at me.

I created a test app to see how many oscillators can run if they are all processing for each sample.

Here are the results:


WAVE_TRI: 99% capacity reached at 105 oscillators.

WAVE_SQUARE: 95% capacity reached at 120 oscillators.

WAVE_SIN: 96% capacity reached at 47 oscillators.

WAVE_SAW: 95% capacity reached at 116 oscillators.

WAVE_RAMP: 95% capacity reached at 117 oscillators.

WAVE_POLYBLEP_TRI: 95% capacity reached at 43 oscillators.

WAVE_POLYBLEP_SQUARE: 96% capacity reached at 46 oscillators.

WAVE_POLYBLEP_SAW: 95% capacity reached at 92 oscillators.

1 Like

I did the monitoring and scaling back thing and it looks like the MoogLadder filter was doing a lot of the damage. Here is how it effects the processor load:

MoogLadder: 98% capacity reached at 20 filters.

That makes it more than twice as expensive as the most expensive oscillator. My problem was that I was running two per voice to run it in stereo, but the signal wasn’t stereo. I cut half of the MoogLadder filters and things seem a bit better. If I want further optimization I might have to reconsider running a separate filter for each voice or just using a cheaper filter. For now though I have four voices running with delay and reverb with a max in the upper 80’s.

1 Like

The current code used in DaisySP for the moog ladder filter is very inefficient. I rebuilt DaisySP using the improved moog ladder filter code suggested by ndonald2 (Nick @Infrasonic_Audio), and saw an immediate improvement in processor load, stability, and sound (particularly when using high resonance settings).
Here is a link if you want to test it out.
Improved Moog Ladder Filter for DaisySP - Huovilainen New Moog derivation ported from Teensy Audio Library · GitHub

2 Likes

That sounds great! I will try it out. Do you know which header file this is referring to in moogladder.cpp?

#include <Utility/dsp.h>

I don’t see it in the Teensy audio library, and nothing in the Teensy library’s filter_ladder.cpp points me in the right direction either.

EDIT: If I replace that line with #include “daisysp.h” it seems to compile fine. I will try that for now.

This new one seems about 40% faster. Very cool.

infrasonic::MoogLadder: 95% capacity reached at 28 oscillators.

-Kenji

Okay I added it to my synth code now. The switch shaved off about 15% total utilization (enough to an additional voice in my case) and also sounds great. The DaisySP implementation has pretty big volume swings across the filter. This one is much smoother level-wise, in addition to the high resonance issues you mention. Thanks a bunch!!!

You’re welcome! It is a shame that electro-smith won’t update DaisySP with this improved code. Most people will not want to tamper with the original DaisySP code, but for me, I had no other option. I gained 3 voices by using this code in my 8-voice VA Synth project.
Thanks to Nick @ Infrasonic_Audio for porting the teensy code over to the Daisy platform!

Oh, I just added the files to my own source code instead of updating the library. It only required two changes to the files to work:

  1. Change #include <Utility/dsp.h> to #include “daisysp.h” in moogladder.cpp
  2. Wrap the code in a “infrasonic” namespace in both moogladder.cpp and moogladder.h so that I could specify this ladder filter instead of the default one in my code using infrasonic::MoogLadder.

With that I didn’t have to do any alter or recompile of the Daisy libraries. That seemed a little more straightforward to me.

-k

1 Like