Long question incoming, buckle up!
MacOS: Ventura 13.5.1
Logic Pro X: 10.7.9
I have been working on a guitar amp simulation plugin consisting of a few waveshapers, gains, EQ’s and an IR convolver. The plugin works great for the most part however there is a problem in Logic where as soon as I record some guitar audio and try to play it back, the sound disappears. If I just load the plugin and play through it using input monitoring, everything works fine. The disappearing audio output seems to come and go but extends to the Loop Browser. Any loop I preview will output silence. MIDI instruments (Kontakt, Serum, etc.) also suffer this issue even though I can see the level meter on each track moving, there is no audio regardless of if I record MIDI and play it back or just play live using the keyboard.
The extra weird part is that this issue will also extend to other programs such as Firefox. I can play a YouTube video I was just watching with no issues but the audio disappears once I open a project with my plugin in it. Once the project is closed, all audio comes back for the other apps. I have checked my audio device settings and they are as I believe they should be. This problem does NOT extend to other Logic projects that do not contain my plugin. I downloaded REAPER to test whether this is a Logic issue and it seems to be the case as my plugin and MIDI instruments function perfectly there.
I previously had Big Sur as my OS version and Logic Pro X 10.6.1 which I thought could have been the issue, therefore I upgraded to the versions I provided at the top of this post, however this did not fix the issue. I also updated to JUCE v7.0.7 which I believe is the newest. I have reset the SMC and PRAM on my Mac in an attempt to fix but this didn’t work either.
I am genuinely at a loss for what could be issue and I’m unsure if it is anything I am doing wrong as the exact same AU component works perfectly in REAPER. This is my second guitar amp sim plugin and the first one (while a little simpler) also has all the DSP widgets mentioned above and works perfectly fine with none of these issues.
Any help would be appreciated as I am losing my mind about this. I want to start using my plugin in my own music and distribute it to others ASAP however this bug is the only functional hurdle I still have to get over.
Thanks so much!
Don’t know if this is related, but when I’m debugging my JUCE plug-in and hit a breakpoint in the audio thread, all other audio on the system stops too until I resume execution. Something similar might be happening in your case.
On macOS, this can happen if samples with very large magnitudes or even inf or nan value are sent to an audio driver. They have internal filters that can become unstable and sometimes never recover unless you do a reboot or switch to a different audio interface. One bad sample can be enough and can for instance come from a division with a very low value.
Make sure your plugin does not produce bad sample values and you’ll probably be fine.
If it works in Reaper then that probably just means Reaper has a guard in place before audio is sent to drivers. Good values are -1 to 1 and no nan and no inf. -100 to 100 is probably still also ok. Huge samples are a problem.
After getting similar reports occasionally from customers I realized that this can also easily happen to any IIR filter in my plugins if the previous plugins output bad values.
I ended up adding a guard to my plugin input to filter out all inf, nan and values with large magnitudes so I know what my code works with is safe.
Very interesting, I didn’t think I could be outputting huge sample values however I do have a bunch of IIR filters in my plugin so that might well be what’s happening. I’ll check it out and report back. Thanks so much for the advice!
You can call this little utility function at the end of processBlock to get rid of invalid audio samples:
void removeNansAndInfs(juce::AudioBuffer<float>& audio)
for (auto ch = 0; ch < audio.getNumChannels(); ++ch)
if (auto* buffer = audio.getWritePointer(ch))
for (auto i = 0; i < audio.getNumSamples(); ++i)
if (std::isnan(buffer[i]) || std::isinf(buffer[i]))
buffer[i] = 0.0f;
Yes, I have something similar, but be aware that if --fast-math is enabled, isnan and isinf won’t work correctly on the latest compilers.
Typically production code should never ever produce these in the first place. So removing them is not a fix at all and actually shadows the root cause. Better have a couple of utility functions that detect this and throw an assertion. Have those in the output permanently (in Debug builds), and drop them anywhere when debugging to find out where your NaNs come from.
That’s what I thought as well and in debug builds there definitely should be a mechanism to make sure your own code doesn’t produce bad values.
I had to learn the hard way that nan/inf/huge values might come from other plugins earlier in the chain and people might still blame your product. The problem only shows up in the first plugin that uses IIR filters after bad values are in the signal.
Filtering them out is easy and cheap and if it prevents people from requiring a reboot, it’s probably justified. In a way it’s just making sure your code can handle any input - which includes invalid input.
Of course ideally the OS itself would filter such values in the audio driver and not require restarting to recover, but it seems this is not happening on macOS.
Good point about other plugins feeding bad stuff to the input. In that case it makes sense to clean the input first just to be sure, and apart from that try to be one of the plugins that doesn’t generate kabooms.
From my experience, on macOS such issues typically don’t require a restart and typically e.g. restarting a sequencer gets rid of it. But it might depend on the specific audio interface and driver, for example when there’s some EQ thing in the output that’s not protected against NaNs?
Thanks everyone for the lively discussion and advice! After doing a little bit of debugging it would appear that the issue is not values <-1 or >1 BUT I am getting a bunch of NAN values! Now to figure out exactly where they are coming from… Based on what everyone was saying, I’m guessing it is from the multitude of IIR filters. I will report back when I have done some more investigating.