FourOscPlugin's renderNextBlock()

I have a curiosity about this function because FourOsc is not performing well for me. When there’s lots of midi notes in harmony it begins to stutter and slow down playback.

    using MPESynthesiserVoice::renderNextBlock;
    void renderNextBlock (juce::AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override

In the course of debugging on a dumb hunch I tried something like this and my playback problems immediately went away:

        if (samplesLastBlock != numSamples)
        {
            samplesLastBlock = numSamples;
            updateParams (numSamples);
        }

Anecdotally I only found that the numSamples value was changing if there was a change in sample rate, and while I haven’t done the profiling work yet, the contents of tracktion::engine::FourOscVoice::updateParams() seem heavy to be run 1000+ times a second for each voice when mostly nothing changes. I’m about to embark on my due diligence journey of making sense of these classes and what’s really happening under the hood, but…

What’s the context here? Why might you call updateParams() so often? Is it plausible expect slow down here?

Can I just double check you’re profiling release performance?

There are some serious slowdowns in debug mode we’re aware of due to some juce assertions.

I just want to make sure you’re not seeing that first.

1 Like

The issue is present in release mode I’m afraid.

You can’t call updateParams (numSamples); only if the block size changes though, that’s the whole state of the synth, envelopes, lfos etc.

There might be stuff that can be trimmed but I’d need to see a profile for that.

What are you getting for numSamples?
I can’t remember the details but I believe this is chunked by the MIDI message position down to a minimum value (that should be about 16 samples I think).

I’m getting 32 samples per block at a sample rate 44.1k Hz.
I’ll keep debugging to try to determine the more proximate source of my slowdown.

Can I also just double check you’re running a profiler on this to see the hotspots?

Looks like those smoothed values are pretty spicy, according to the Performance CPU Profiler.

Isn’t that profile saying that only ~3% of the 4OSC process block is spent in the value smoother?

I think that’s 3% of all CPU used during profiling the application for the given range of time. As in “of all of the CPU used by the application 3% of it was used by FourOsc::applyToBuffer()”.

This also seems to be a realtime issue, if I render the track it sounds good.

I meant the value smoother is 3% of the applyToBuffer call.
applyToBuffer is 2.7% of the total CPU time.

So the value smoother is 0.46% of total CPU time.
Which doesn’t feel like a hot spot to me?

I’m not sure that the issue is CPU slowdown, just that on a high level something in updateParams() is causing playback to stutter. I’ll keep debugging.

If it’s only occasional dropouts, you need to profile but pinpoint when the dropouts happen and look at the profile for just that time period.

On macOS we use Signposts to do this nicely in Instruments.
Not sure what the equivalent is on Windows.

Visual Studio does allow you to look at data for a given time.

When you start debugging you get a general graph represented currently in green.

image

And then if you hit [ :red_circle: Record CPU Profile ] it’ll collect data for a specified range of time (seen in blue), and then you can further select a time range using the non-linear editor.

image

During this first spike I can learn the following things:

  • that juce audio device stuff seems to be using about 25% of the CPU:

  • that processing the FourOsc node uses about 30% of the CPU.

  • that about 10% of the total cpu gets used by updateParams() in this time range.

I hope that’s illuminating in some way.