ASIO issue - buffer sizes not being correctly updated

Whilst providing feedback on my RTL Utility app, RME asked if I could improve the handling of buffer size changes. They also mentioned that their ASIO drivers only allow the buffer size to be changed in their control panel and only show the current buffer size in the list of available buffer sizes. Apparently this is according to the ASIO spec and has been historically confirmed by Steinberg.

Repro & current behaviour (with RME ASIO devices):

  • Instantiate an AudioDeviceSelectorComponent
  • User opens the ASIO device control panel (either via the button provided by AudioDeviceSelectorComponent or directly)
  • User chooses a different buffer size
  • juce::ASIOAudioIODevice responds to the kAsioResetRequest and changes to the new buffer size
  • However, AudioDeviceSelectorComponent displays a blank value in the Audio Buffer Size combo box

This is because the set of buffer sizes has not been properly updated, and the new buffer size is not a member of the previous set. As can be seen from the code below, refreshBufferSizes() updates the min, max, preferred & granularity parameters - but it does not update the bufferSizes member.

modules\juce_audio_devices\native\juce_win32_ASIO.cpp, lines 822-825:

	long refreshBufferSizes()
	{
		return asioObject->getBufferSize (&minBufferSize, &maxBufferSize, &preferredBufferSize, &bufferGranularity);
	}

Here’s a patch to fix this issue:

long refreshBufferSizes()
{
    const auto err = asioObject->getBufferSize (&minBufferSize, &maxBufferSize, &preferredBufferSize, &bufferGranularity);
    if (err == ASE_OK)
    {
        bufferSizes.clear();
        addBufferSizes(minBufferSize, maxBufferSize, preferredBufferSize, bufferGranularity);
    }
    return err;
}

This seems to work flawlessly on my system with an RME Fireface 800.

1 Like

That seems like a sensible addition, thanks. We’ll get that added to the develop branch.

1 Like

Thanks for adding this @ed95, but now I’ve found another one. Again seen with RME devices, when you change to a double or quad sample rate (e.g. 192K) then the buffer size needs to change. Similar to the above issue, the new buffer size would actually take hold, but the device manager goes blank.

I’ve tracked this down to the fact that the buffer sizes are read before setSampleRate() is called in the open() method. Simply moving a couple of lines to after the setSampleRate() call fixes it up. Here’s the diff (thought the dark theme makes it hard to read!).

diff --git a/modules/juce_audio_devices/native/juce_win32_ASIO.cpp b/modules/juce_audio_devices/native/juce_win32_ASIO.cpp
index cb8f6c5db..336224384 100644
--- a/modules/juce_audio_devices/native/juce_win32_ASIO.cpp
+++ b/modules/juce_audio_devices/native/juce_win32_ASIO.cpp
@@ -415,11 +415,8 @@ public:
         auto err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans);
         jassert (err == ASE_OK);

-        bufferSizeSamples = readBufferSizes (bufferSizeSamples);
-
         auto sampleRate = sr;
         currentSampleRate = sampleRate;
-        currentBlockSizeSamples = bufferSizeSamples;
         currentChansOut.clear();
         currentChansIn.clear();

@@ -441,6 +438,8 @@ public:
         buffersCreated = false;

         setSampleRate (sampleRate);
+        bufferSizeSamples = readBufferSizes (bufferSizeSamples);^M
+        currentBlockSizeSamples = bufferSizeSamples;^M

         // (need to get this again in case a sample rate change affected the channel count)
         err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans);

None of the buffer size variables are referenced by anything between their current location and the setSampleRate() call, so I think it is quite safe to move them. Works like a dream for me!

Great, thanks. I’ve added that and the max buffer size suggestion (Request - can we allow block sizes of up to 32768 for ASIO?) and they will be on the develop branch shortly.

Awesome, thanks again Ed!