Cabbage Logo
Back to Cabbage Site

Mono Instruments for 3D audio + ksmps Performance Impact

Hi all hope everyone is well,

Two questions on the following:

  1. Mono vs stereo cabbage instruments for 3D games
  2. Impact of ksmps on performance

Not sure if my intuition is correct so would love to confirm:

In games, it’s common to use mono for 3D audio sources that emit from a single point in the world. So I wondered: when i’m designing my Cabbage instruments that I know are 3D audio sources, should I use ‘nchnls = 1’ instead of ‘nchnls = 2’?

Perhaps there is a reason this is not necessary? I suppose it is forced into mono anyway, on the Audio Source component I have Spatial Blend set to full 3D:

Screenshot 2024-07-15 at 1.02.09 pm

https://docs.unity3d.com/ScriptReference/AudioSource-spatialBlend.html

Haven’t noticed any issues thus far using nchnls = 2 in the instrument. I’m wondering from a CPU performance point of view if it’s better to run the instrument in mono, particularly if there many instances of them and I know the audio sources will never need to blend in between mono and stereo.

Additional question: Will decreasing ksmps improve the CPU performance of multiple instances of the same instrument? Say from 512 ksmps to 16 ksmps, I haven’t noticed any meaningful degradation of the sound, haven’t tested this thoroughly in-game yet to measure performance, just wondering if there is a clear consensus on this.

Thanks all & take care

Using Unity 2022.2.18

@giovannibedetti can probably answer this better than I, but I think using mono is fine. Decreasing ksmps usually leads to increased CPU performance, but better latency. Whatever you chose as the ksmps size, it should be a power of two value.

1 Like

Correct. See here from the Unity forums: “You can use stereo or mono signals, but be aware that most spatializers will just mix the signals before applying spatialization.”
I haven’t tested this in detail, I’ll do some research, but this down mixing could cause some glitches.

Unfortunately using a mono output in Csound won’t reduce CPU usage by half.
I’ll explain why later on.

Unfortunately no. As of CsoundUnity 3.4.3, during initialization sr and kr are set to AudioSettings.outputSampleRate:

Csound6.NativeMethods.csoundSetOption(csound, $"--sample-rate={AudioSettings.outputSampleRate}");
Csound6.NativeMethods.csoundSetOption(csound, $"--control-rate={AudioSettings.outputSampleRate}");
Csound6.NativeMethods.csoundSetOption(csound, $"--ksmps=1");

We found this to be the only way to behave correctly at that time (so different kr values were producing garbage audio output). I’m happy to take a look now to see if it can be done with more recent Unity versions.

So with the above context, I’ll explain a bit how CsoundUnity works so it will be hopefully clearer if the number of channels affects performance and also why we should be able to change the kr:

In the OnAudioFilterRead callback, CsoundUnity receives a block of samples from the Unity AudioSource (usually 1024 per channel).
The number of channels we receive depends on the Default Speaker mode in the Unity Project Audio Settings. Yes it’s a global setting. :sweat:
So if you set that to Mono we receive 1024 samples and numChannels is 1, for Stereo we receive 2048 samples and numChannels is 2. Any other setting (the surround ones) gives back 9182 samples and 8 channels.
The samples come as interleaved meaning that sample[0] = L and sample[1] = R and so on.
We iterate through the samples increasing a counter.
This counter is reset every time a PerformKsmps is executed.
For every tick of the counter, we iterate the channels, for each we set the Input Sample (to Csound) and grab the Output Sample (from Csound) and we write back in the samples array we received with the OnAudioFilterRead callback.
Every time this counter is equal or bigger than ksmps (always 1 as of today), we call PerformKsmps .
This means that, in a stereo scenario, every 2 samples received from Unity, we call PerformKsmps.
So we’re always running at full resolution!
Being able to control ksmps could surely allow us to optimize things.

Instead, apart from avoiding potential glitches caused by the spatializer messing with stereo files, there’s no real gain in using mono output from Csound as we are filling couples of stereo samples with the same mono signal. But yeah I guess on the Csound side it will be less demanding handling one channel instead of two. Thoughts @rorywalsh?

Soon I will have a look at the possibility of changing the sr and kr :+1:

1 Like

Thanks Rory, and Giovanni thank you for the great depth of your answer! Lots of clarity from that. Having the flexibility to set some global resolution for performance would be great if feasible, even if it did come at a cost of quality

Thanks again Rory, just want to confirm i’m understanding this, not sure if I am: I’m reading ‘increased CPU performance, but better latency’ as if it means more work for the CPU and thus worse performance, but better latency as a trade off. Is that what you mean or am I misinterpreting? Conversely this would mean increasing ksmps leads to better performance at the cost of worse latency - that’s the part that feels off to my assumptions, my intuition is: the higher the number of ksmps, the worse performance would be (performance meaning in this case, impact on the frame-rate of the game due to CPU calculations), could be wrong

I made a quick test and it seems to work, I tried to set kr to AudioSettings.outputSampleRate / 10 and AudioSettings.outputSampleRate / 20 and it seems ok.
I will dig into this a bit further!
(and by testing I just discovered that the Granular Synthesis sample is not working on Unity 2022)

1 Like

No it’s the opposite :sweat_smile:

Ksmps is sr / kr so as kr increases up to sr it will go down at 1.
For example if sr is 44100 and kr is 4410 ksmps is 10.
If sr is 44100 and kr is 44100 ksmps is 1.

So there’s no need to set ksmps as it will be determined from the sr and kr setting

1 Like

Aha! Well that’s fine then, very happy to be corrected on that, thanks for the clarity

Alternatively, just set ksmps and leave out kr, Csound will work out the rest :wink:

I tried a quick implementation on this branch:

feature/user-control-on-ksmps

You should be able to test it importing it via the Unity package manager using this url:

https://github.com/rorywalsh/CsoundUnity.git#feature/user-control-on-ksmps

Honestly I don’t see any difference, also setting crazy values. I’m still wondering what is going on, but neither the output audio changes, nor the performance improves or drops.
Csound prints the right values, so I assume it is getting the values for sr and kr.
I tried using csoundSetOption and also SetParams (that crashes in some Unity version so not very safe, but for the purpose of testing). No audible changes, no performance gain.
I’m still baffled as I don’t understand what’s going on :open_mouth:
So if you could try it you could help me understand :wink:

Csound is magic :wink: in not sure why you’re not seeing any issues. But I’m travelling at the moment so won’t get a chance to look into it.

Just noticed that if I set sr and ksmps it works as expected, probably it’s because ksmps is initialized as 1 :sweat_smile:
(so setting sr and kr is not enough to update ksmps apparently)
Will push something soon

1 Like