JUCE
JUCE copied to clipboard
[Bug]: Cumulating Xruns when changing soundcard settings (Reproduced in AudioPluginHost example)
Detailed steps on how to reproduce the bug
We've been struggling with a strange issue where suddenly there are lots of Xruns when changing the sound card settings. The Xruns keep adding up and there's no recovery.
I happens often but not always. The easiest way to reproduce it has been with Blackhole (virtual sound card https://github.com/ExistentialAudio/BlackHole) in macos. I thought it was a BlackHole issue, but since I was able to reproduce it without, I'm posting this here.
- Tested/Reproduced with Juce
7.0.12on macos Sonoma and windows 11 (debug), macbook M1 - Tested/Reproduced with Juce
8.0.6on macos Sonoma (debug), macbook M1
IMPORTANT DETAILS: So far, I've only been able to reproduce this with virtual soundcards (e.g. Loopback, Parallels sound card,...). There needs to be a certain system/CPU load (e.g. >25%) to reproduce this somewhat consistently. That's why I modified the example reverb and burn some cycles in it with memcpys (see code below) --this gets me to roughly 60% CPU in debug build.
With certain sound card settings, the Xruns start increasing... and never stop, until I switch sound cards again:
Has anybody experienced somehting similar?
I'm able to reproduce it on AudioPluginHost example with minimal modifications:
in extras/AudioPluginHost/Source/UI/MainHostWindow.h
In MainHostWindow class, add this private class instance:
class XrunConsolerLogger : public juce::Timer
{
public:
XrunConsolerLogger(AudioDeviceManager& deviceMgr) : m_deviceMgr(deviceMgr) { startTimer(500); }
void timerCallback() override
{
std::cout << "Xruns: " << m_deviceMgr.getXRunCount() << std::endl;
}
private:
AudioDeviceManager& m_deviceMgr;
} xrunLogger;
in extras/AudioPluginHost/Source/UI/MainHostWindow.cpp
add xrunLogger(deviceManager) to MainHostWindow ctor intitializer list
in extras/AudioPluginHost/Source/Plugins/InternalPlugins.cpp
Add this at the start of ReverbPlugin::processBlock()
// burn cycles with some dummy memcpy
const float* const* in = buffer.getArrayOfReadPointers();
float* const* temp = buffer.getArrayOfWritePointers();
float* const* out = buffer.getArrayOfWritePointers();
// When CPU load is >100%, we get the same behaviour .. Xruns...
int numIterations = 50000;
for (int k=0; k<numIterations; ++k) {
for (int i=0; i<buffer.getNumChannels(); ++i) {
memcpy(temp[i], in[i], buffer.getNumSamples()*sizeof(float));
temp[i][0] += 1e-9f;
memcpy(out[i], temp[i], buffer.getNumSamples()*sizeof(float));
}
}
GIT Patch
Here's a Git Patch for all these changes. JUCE-AddXrunLogger_ReverbLoad.patch
What is the expected behaviour?
I would expect that - if Xruns happen - the system recovers, i.e. drops the frames and the Xruns don't keep increasing.
Operating systems
Windows, macOS
What versions of the operating systems?
This happens on macos 14.7.1 (Sonoma) and Windows 11 for ARM.
Architectures
Arm64/aarch64
Stacktrace
Plug-in formats (if applicable)
No response
Plug-in host applications (DAWs) (if applicable)
AudioPluginHost example with minimal modifications
Testing on the develop branch
I have not tested against the develop branch
Code of Conduct
- [x] I agree to follow the Code of Conduct