28class InterpolatorTests final :
public UnitTest
32 : UnitTest (
"InterpolatorTests", UnitTestCategories::audio)
37 template <
typename InterpolatorType>
38 void runInterplatorTests (
const String& interpolatorName)
40 auto createGaussian = [] (std::vector<float>& destination,
float scale,
float centreInSamples,
float width)
42 for (
size_t i = 0; i < destination.size(); ++i)
44 auto x = (((float) i) - centreInSamples) * width;
45 destination[i] = std::exp (-(x * x));
48 FloatVectorOperations::multiply (destination.data(), scale, (
int) destination.size());
51 auto findGaussianPeak = [] (
const std::vector<float>& input) ->
float
53 auto max = std::max_element (std::begin (input), std::end (input));
54 auto maxPrev = max - 1;
55 jassert (maxPrev >= std::begin (input));
56 auto maxNext = max + 1;
57 jassert (maxNext < std::end (input));
58 auto quadraticMaxLoc = (*maxPrev - *maxNext) / (2.0f * ((*maxNext + *maxPrev) - (2.0f * *max)));
59 return quadraticMaxLoc + (float) std::distance (std::begin (input), max);
62 auto expectAllElementsWithin = [
this] (
const std::vector<float>& v1,
const std::vector<float>& v2,
float tolerance)
64 expectEquals ((
int) v1.size(), (
int) v2.size());
66 for (
size_t i = 0; i < v1.size(); ++i)
67 expectWithinAbsoluteError (v1[i], v2[i], tolerance);
70 InterpolatorType interpolator;
72 constexpr size_t inputSize = 1001;
73 static_assert (inputSize > 800 + InterpolatorType::getBaseLatency(),
74 "The test InterpolatorTests input buffer is too small");
76 std::vector<float> input (inputSize);
77 constexpr auto inputGaussianMidpoint = (float) (inputSize - 1) / 2.0f;
78 constexpr auto inputGaussianValueAtEnds = 0.000001f;
79 const auto inputGaussianWidth = std::sqrt (-std::log (inputGaussianValueAtEnds)) / inputGaussianMidpoint;
81 createGaussian (input, 1.0f, inputGaussianMidpoint, inputGaussianWidth);
83 for (
auto speedRatio : { 0.4, 0.8263, 1.0, 1.05, 1.2384, 1.6 })
85 const auto expectedGaussianMidpoint = (inputGaussianMidpoint + InterpolatorType::getBaseLatency()) / (
float) speedRatio;
86 const auto expectedGaussianWidth = inputGaussianWidth * (float) speedRatio;
88 const auto outputBufferSize = (size_t) std::floor ((
float) input.size() / speedRatio);
90 for (
int numBlocks : { 1, 5 })
92 const auto inputBlockSize = (float) input.size() / (float) numBlocks;
93 const auto outputBlockSize = (int) std::floor (inputBlockSize / speedRatio);
95 std::vector<float> output (outputBufferSize, std::numeric_limits<float>::min());
97 beginTest (interpolatorName +
" process " + String (numBlocks) +
" blocks ratio " + String (speedRatio));
102 auto* inputPtr = input.data();
103 auto* outputPtr = output.data();
105 for (
int i = 0; i < numBlocks; ++i)
107 auto numInputSamplesRead = interpolator.process (speedRatio, inputPtr, outputPtr, outputBlockSize);
108 inputPtr += numInputSamplesRead;
109 outputPtr += outputBlockSize;
113 expectWithinAbsoluteError (findGaussianPeak (output), expectedGaussianMidpoint, 0.1f);
115 std::vector<float> expectedOutput (output.size());
116 createGaussian (expectedOutput, 1.0f, expectedGaussianMidpoint, expectedGaussianWidth);
118 expectAllElementsWithin (output, expectedOutput, 0.02f);
120 beginTest (interpolatorName +
" process adding " + String (numBlocks) +
" blocks ratio " + String (speedRatio));
122 interpolator.reset();
124 constexpr float addingGain = 0.7384f;
127 auto* inputPtr = input.data();
128 auto* outputPtr = output.data();
130 for (
int i = 0; i < numBlocks; ++i)
132 auto numInputSamplesRead = interpolator.processAdding (speedRatio, inputPtr, outputPtr, outputBlockSize, addingGain);
133 inputPtr += numInputSamplesRead;
134 outputPtr += outputBlockSize;
138 expectWithinAbsoluteError (findGaussianPeak (output), expectedGaussianMidpoint, 0.1f);
140 std::vector<float> additionalOutput (output.size());
141 createGaussian (additionalOutput, addingGain, expectedGaussianMidpoint, expectedGaussianWidth);
142 FloatVectorOperations::add (expectedOutput.data(), additionalOutput.data(), (
int) additionalOutput.size());
144 expectAllElementsWithin (output, expectedOutput, 0.02f);
147 beginTest (interpolatorName +
" process wrap 0 ratio " + String (speedRatio));
149 std::vector<float> doubleLengthOutput (2 * outputBufferSize, std::numeric_limits<float>::min());
151 interpolator.reset();
152 interpolator.process (speedRatio, input.data(), doubleLengthOutput.data(), (
int) doubleLengthOutput.size(),
153 (
int) input.size(), 0);
155 std::vector<float> expectedDoubleLengthOutput (doubleLengthOutput.size());
156 createGaussian (expectedDoubleLengthOutput, 1.0f, expectedGaussianMidpoint, expectedGaussianWidth);
158 expectAllElementsWithin (doubleLengthOutput, expectedDoubleLengthOutput, 0.02f);
160 beginTest (interpolatorName +
" process wrap double ratio " + String (speedRatio));
162 interpolator.reset();
163 interpolator.process (speedRatio, input.data(), doubleLengthOutput.data(), (
int) doubleLengthOutput.size(),
164 (
int) input.size(), (
int) input.size());
166 std::vector<float> secondGaussian (doubleLengthOutput.size());
167 createGaussian (secondGaussian, 1.0f, expectedGaussianMidpoint + (
float) outputBufferSize, expectedGaussianWidth);
168 FloatVectorOperations::add (expectedDoubleLengthOutput.data(), secondGaussian.data(), (
int) expectedDoubleLengthOutput.size());
170 expectAllElementsWithin (doubleLengthOutput, expectedDoubleLengthOutput, 0.02f);
175 void runTest()
override
177 runInterplatorTests<WindowedSincInterpolator> (
"WindowedSincInterpolator");
178 runInterplatorTests<LagrangeInterpolator> (
"LagrangeInterpolator");
179 runInterplatorTests<CatmullRomInterpolator> (
"CatmullRomInterpolator");
180 runInterplatorTests<LinearInterpolator> (
"LinearInterpolator");
184static InterpolatorTests interpolatorTests;