Something’s amiss with my convolver.
It’s producing a noise burst the first time it renders audio.
using namespace dsp;
struct Spatializer
{
dsp::Convolution convolver;
AudioBuffer<float> outBuf;
Spatializer(int toneme) {
std::ostringstream ss;
ss << "ir_" << std::setw(2) << std::setfill('0') << toneme << "_wav";
String resourceName = ss.str();
int size = 0;
const void* data = BinaryData::getNamedResource(resourceName.getCharPointer(), size);
dsp::ProcessSpec spec;
spec.sampleRate = 44100;
spec.maximumBlockSize = 4096;
spec.numChannels = 2;
convolver.prepare(spec);
convolver.loadImpulseResponse(
data,
(size_t)size,
dsp::Convolution::Stereo::yes,
dsp::Convolution::Trim::no,
(size_t)0, // size (0 is original size)
dsp::Convolution::Normalise::no
);
//convolver.reset();
}
void setBufferSize(int nSamps) {
outBuf.setSize(2, nSamps);
//outBuf.clear();
}
auto getOutBlock() {
return dsp::AudioBlock<float>(outBuf);
}
void feed(const dsp::AudioBlock<float> in_mono)
{
// const not needed
const float* pointers[] = {
in_mono.getChannelPointer(0),
in_mono.getChannelPointer(0)
};
// float** works too
AudioBlock<float>tmpBlk((float * const *)&pointers, 2, (int)in_mono.getNumSamples());
auto outBlock = getOutBlock();
juce::dsp::ProcessContextNonReplacing<float> ctx(tmpBlk, outBlock);
convolver.process(ctx);
}
};
Attempts to .reset
the Convolution
instance, and/or to initially .clear
my wrapper’s output buffer (just in case convolver.process(ctx)
might be internally adding to the output buffer, of which I see no evidence) both fail to shake it loose.
The issue is definitely in this Convolver
object. If I remove it from the pipeline, I don’t get the noiseburst:
// works
auto& note = *notes[prefs.spiral_midi_lowest];
outBlock.getSingleChannelBlock(0).add(note.getOutBlock());
// fails
auto& note = *notes[prefs.spiral_midi_lowest];
auto& spatializer = *spatializers[prefs.spiral_midi_lowest];
spatializer.feed(note.getOutBlock());
outBlock.add(spatializer.getOutBlock());
What DOES work is to “warm it up” by feeding in a boatload of zeros initially:
void audioDeviceAboutToStart (AudioIODevice* pDevice) override {
int N = pDevice->getCurrentBufferSizeSamples();
for(auto p : notes)
p->setBufferSize(N);
for(auto p : spatializers) {
p->setBufferSize(N);
// 🔴 I had to add all this
auto buf = AudioBuffer<float>(1, N);
buf.clear();
auto blk = AudioBlock<float>(buf);
for(int i=0; i<32; ++i) // low numbers like 4, I still get some noiseburst
p->feed(blk);
}
}
… but this is ugly and imprecise – how many zeros should I initially feed it?
One FFT frame’s worth? Without digging into the internals, no way to know.
Has anyone else encountered trouble with this component?
I suspect it may be failing to internally zero its own buffers.