I encountered a similar issue trying to reproduce the issue outside of SpatGris. It might be related, as it has to do with buffer size and number of input and output channels, and is not reproducible in JUCE 7.0.2. And the sound of the glitch is the same described in the previous posts. (And fortunately we don’t have to wait one hour for the glitch to appear.)
In the app from the code below, randomly changing the buffer size and toggling on and off inputs and outputs make the glitch happen.
Conditions to reproduce the issue :
- JUCE 7.0.3, 7.0.4 or 7.0.5
- The
AudioDeviceManager has to be initialized with 128 input channels.
- Use an external sound card for audio output.
Setup:
- Use BlackHole (or any 128 channel capable virtual audio device) as audio driver for your DAW. (BlackHole 128 is included in the SpatGris installer (no need to install SpatGris).
- Configure your DAW to send audio to multiple BlackHole channels. Enough to cover your tests (the app only uses the first 2 available input and output channels).
- In the app from the code below, set BlackHole as audio input and an external sound card for audio output.
Thank you @reuk or anyone helping me with this. I know it looks like an edge case, but it is the core design that make SpatGris simple and easy to use on MacOS.
Here’s the code :
MainComponent.h
#pragma once
#include <JuceHeader.h>
//==============================================================================
class MainComponent
: juce::AudioSourcePlayer
, public juce::Component
{
public:
//==============================================================================
MainComponent();
~MainComponent() override;
//==============================================================================
void audioDeviceError(const juce::String & errorMessage) override;
void audioDeviceIOCallbackWithContext(const float * const * inputChannelData,
int totalNumInputChannels,
float * const * outputChannelData,
int totalNumOutputChannels,
int numSamples,
const juce::AudioIODeviceCallbackContext & context) override;
void audioDeviceAboutToStart(juce::AudioIODevice * device) override;
void audioDeviceStopped() override;
//==============================================================================
void paint(juce::Graphics & g) override;
void resized() override;
private:
//==============================================================================
juce::AudioDeviceManager mAudioDeviceManager{};
juce::AudioDeviceSelectorComponent mAudioDeviceSelectorComponent;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent)
};
MainComponent.cpp:
#include "MainComponent.h"
//==============================================================================
MainComponent::MainComponent()
: mAudioDeviceSelectorComponent(mAudioDeviceManager, 0, 128, 0, 128, false, false, false, false)
{
setSize(800, 600);
addAndMakeVisible(mAudioDeviceSelectorComponent);
mAudioDeviceManager.initialise(128, 2, nullptr, true);
mAudioDeviceManager.addAudioCallback(this);
}
//==============================================================================
MainComponent::~MainComponent()
{
mAudioDeviceManager.removeAudioCallback(this);
}
//==============================================================================
void MainComponent::audioDeviceError(const juce::String & errorMessage)
{
jassertfalse;
}
//==============================================================================
void MainComponent::audioDeviceIOCallbackWithContext(const float * const * inputChannelData,
int totalNumInputChannels,
float * const * outputChannelData,
int totalNumOutputChannels,
int numSamples,
const juce::AudioIODeviceCallbackContext & context)
{
std::for_each_n(outputChannelData, totalNumOutputChannels, [numSamples](float * const data) {
std::fill_n(data, numSamples, 0.0f);
});
// directly copy inputChannelData to outputChannelData
auto const numInputChannelsToCopy{ std::min(totalNumInputChannels, 2) };
for (int i{}; i < numInputChannelsToCopy; ++i) {
auto const * sourceData{ inputChannelData[i] };
auto * destinationData{ outputChannelData[i] };
std::copy_n(sourceData, numSamples, destinationData);
}
}
//==============================================================================
void MainComponent::audioDeviceAboutToStart(juce::AudioIODevice * device)
{
std::cout << "audio device about to start" << std::endl;
}
//==============================================================================
void MainComponent::audioDeviceStopped()
{
std::cout << "audio device stopped" << std::endl;
}
//==============================================================================
void MainComponent::paint(juce::Graphics & g)
{
g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
}
//==============================================================================
void MainComponent::resized()
{
mAudioDeviceSelectorComponent.setSize(getWidth(), getHeight());
}