|
|
@@ -89,6 +89,19 @@ class ConvolutionTest : public UnitTest |
|
|
|
expect (! std::isnan (block.getSample ((int) channel, (int) sample)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void checkAllChannelsNonZero (const AudioBlock<float>& block)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i != block.getNumChannels(); ++i)
|
|
|
|
{
|
|
|
|
const auto* channel = block.getChannelPointer (i);
|
|
|
|
|
|
|
|
expect (std::any_of (channel, channel + block.getNumSamples(), [] (float sample)
|
|
|
|
{
|
|
|
|
return sample != 0.0f;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void nonAllocatingExpectWithinAbsoluteError (const T& a, const T& b, const T& error)
|
|
|
|
{
|
|
|
@@ -168,16 +181,21 @@ class ConvolutionTest : public UnitTest |
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto time = Time::getMillisecondCounter();
|
|
|
|
|
|
|
|
// Wait 10 seconds to load the impulse response
|
|
|
|
while (Time::getMillisecondCounter() - time < 10'000)
|
|
|
|
// If we load an IR while the convolution is already running, we'll need to wait
|
|
|
|
// for it to be loaded on a background thread
|
|
|
|
if (initSequence == InitSequence::prepareThenLoad)
|
|
|
|
{
|
|
|
|
processBlocksWithDiracImpulse();
|
|
|
|
const auto time = Time::getMillisecondCounter();
|
|
|
|
|
|
|
|
// Wait 10 seconds to load the impulse response
|
|
|
|
while (Time::getMillisecondCounter() - time < 10'000)
|
|
|
|
{
|
|
|
|
processBlocksWithDiracImpulse();
|
|
|
|
|
|
|
|
// Check if the impulse response was loaded
|
|
|
|
if (block.getSample (0, 1) != 0.0f)
|
|
|
|
break;
|
|
|
|
// Check if the impulse response was loaded
|
|
|
|
if (block.getSample (0, 1) != 0.0f)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point, our convolution should be loaded and the current IR size should
|
|
|
@@ -326,6 +344,45 @@ public: |
|
|
|
checkForNans (block);
|
|
|
|
}
|
|
|
|
|
|
|
|
beginTest ("Convolutions can cope with a change in samplerate and blocksize");
|
|
|
|
{
|
|
|
|
Convolution convolution;
|
|
|
|
|
|
|
|
auto copy = impulseData;
|
|
|
|
convolution.loadImpulseResponse (std::move (copy),
|
|
|
|
2000,
|
|
|
|
Convolution::Stereo::yes,
|
|
|
|
Convolution::Trim::no,
|
|
|
|
Convolution::Normalise::yes);
|
|
|
|
|
|
|
|
const dsp::ProcessSpec specs[] = { { 96'000.0, 1024, 2 },
|
|
|
|
{ 48'000.0, 512, 2 },
|
|
|
|
{ 44'100.0, 256, 2 } };
|
|
|
|
|
|
|
|
for (const auto& thisSpec : specs)
|
|
|
|
{
|
|
|
|
convolution.prepare (thisSpec);
|
|
|
|
|
|
|
|
expectWithinAbsoluteError ((double) convolution.getCurrentIRSize(),
|
|
|
|
thisSpec.sampleRate * 0.5,
|
|
|
|
1.0);
|
|
|
|
|
|
|
|
juce::AudioBuffer<float> thisBuffer ((int) thisSpec.numChannels,
|
|
|
|
(int) thisSpec.maximumBlockSize);
|
|
|
|
AudioBlock<float> thisBlock { thisBuffer };
|
|
|
|
ProcessContextReplacing<float> thisContext { thisBlock };
|
|
|
|
|
|
|
|
nTimes (100, [&]
|
|
|
|
{
|
|
|
|
addDiracImpulse (thisBlock);
|
|
|
|
convolution.process (thisContext);
|
|
|
|
|
|
|
|
checkForNans (thisBlock);
|
|
|
|
checkAllChannelsNonZero (thisBlock);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
beginTest ("Short uniform convolutions work");
|
|
|
|
{
|
|
|
|
const auto ramp = makeRamp (static_cast<int> (spec.maximumBlockSize) / 2);
|
|
|
|