Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
8.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. #if JUCE_UNIT_TESTS
  21. class InterpolatorTests : public UnitTest
  22. {
  23. public:
  24. InterpolatorTests()
  25. : UnitTest ("InterpolatorTests", UnitTestCategories::audio)
  26. {
  27. }
  28. private:
  29. template<typename InterpolatorType>
  30. void runInterplatorTests (const String& interpolatorName)
  31. {
  32. auto createGaussian = [] (std::vector<float>& destination, float scale, float centreInSamples, float width)
  33. {
  34. for (size_t i = 0; i < destination.size(); ++i)
  35. {
  36. auto x = (((float) i) - centreInSamples) * width;
  37. destination[i] = std::exp (-(x * x));
  38. }
  39. FloatVectorOperations::multiply (destination.data(), scale, (int) destination.size());
  40. };
  41. auto findGaussianPeak = [] (const std::vector<float>& input) -> float
  42. {
  43. auto max = std::max_element (std::begin (input), std::end (input));
  44. auto maxPrev = max - 1;
  45. jassert (maxPrev >= std::begin (input));
  46. auto maxNext = max + 1;
  47. jassert (maxNext < std::end (input));
  48. auto quadraticMaxLoc = (*maxPrev - *maxNext) / (2.0f * ((*maxNext + *maxPrev) - (2.0f * *max)));
  49. return quadraticMaxLoc + (float) std::distance (std::begin (input), max);
  50. };
  51. auto expectAllElementsWithin = [this] (const std::vector<float>& v1, const std::vector<float>& v2, float tolerance)
  52. {
  53. expectEquals ((int) v1.size(), (int) v2.size());
  54. for (size_t i = 0; i < v1.size(); ++i)
  55. expectWithinAbsoluteError (v1[i], v2[i], tolerance);
  56. };
  57. InterpolatorType interpolator;
  58. constexpr size_t inputSize = 1001;
  59. static_assert (inputSize > 800 + InterpolatorType::getBaseLatency(),
  60. "The test InterpolatorTests input buffer is too small");
  61. std::vector<float> input (inputSize);
  62. constexpr auto inputGaussianMidpoint = (float) (inputSize - 1) / 2.0f;
  63. constexpr auto inputGaussianValueAtEnds = 0.000001f;
  64. const auto inputGaussianWidth = std::sqrt (-std::log (inputGaussianValueAtEnds)) / inputGaussianMidpoint;
  65. createGaussian (input, 1.0f, inputGaussianMidpoint, inputGaussianWidth);
  66. for (auto speedRatio : { 0.4, 0.8263, 1.0, 1.05, 1.2384, 1.6 })
  67. {
  68. const auto expectedGaussianMidpoint = (inputGaussianMidpoint + InterpolatorType::getBaseLatency()) / (float) speedRatio;
  69. const auto expectedGaussianWidth = inputGaussianWidth * (float) speedRatio;
  70. const auto outputBufferSize = (size_t) std::floor ((float) input.size() / speedRatio);
  71. for (int numBlocks : { 1, 5 })
  72. {
  73. const auto inputBlockSize = (float) input.size() / (float) numBlocks;
  74. const auto outputBlockSize = (int) std::floor (inputBlockSize / speedRatio);
  75. std::vector<float> output (outputBufferSize, std::numeric_limits<float>::min());
  76. beginTest (interpolatorName + " process " + String (numBlocks) + " blocks ratio " + String (speedRatio));
  77. interpolator.reset();
  78. {
  79. auto* inputPtr = input.data();
  80. auto* outputPtr = output.data();
  81. for (int i = 0; i < numBlocks; ++i)
  82. {
  83. auto numInputSamplesRead = interpolator.process (speedRatio, inputPtr, outputPtr, outputBlockSize);
  84. inputPtr += numInputSamplesRead;
  85. outputPtr += outputBlockSize;
  86. }
  87. }
  88. expectWithinAbsoluteError (findGaussianPeak (output), expectedGaussianMidpoint, 0.1f);
  89. std::vector<float> expectedOutput (output.size());
  90. createGaussian (expectedOutput, 1.0f, expectedGaussianMidpoint, expectedGaussianWidth);
  91. expectAllElementsWithin (output, expectedOutput, 0.02f);
  92. beginTest (interpolatorName + " process adding " + String (numBlocks) + " blocks ratio " + String (speedRatio));
  93. interpolator.reset();
  94. constexpr float addingGain = 0.7384f;
  95. {
  96. auto* inputPtr = input.data();
  97. auto* outputPtr = output.data();
  98. for (int i = 0; i < numBlocks; ++i)
  99. {
  100. auto numInputSamplesRead = interpolator.processAdding (speedRatio, inputPtr, outputPtr, outputBlockSize, addingGain);
  101. inputPtr += numInputSamplesRead;
  102. outputPtr += outputBlockSize;
  103. }
  104. }
  105. expectWithinAbsoluteError (findGaussianPeak (output), expectedGaussianMidpoint, 0.1f);
  106. std::vector<float> additionalOutput (output.size());
  107. createGaussian (additionalOutput, addingGain, expectedGaussianMidpoint, expectedGaussianWidth);
  108. FloatVectorOperations::add (expectedOutput.data(), additionalOutput.data(), (int) additionalOutput.size());
  109. expectAllElementsWithin (output, expectedOutput, 0.02f);
  110. }
  111. beginTest (interpolatorName + " process wrap 0 ratio " + String (speedRatio));
  112. std::vector<float> doubleLengthOutput (2 * outputBufferSize, std::numeric_limits<float>::min());
  113. interpolator.reset();
  114. interpolator.process (speedRatio, input.data(), doubleLengthOutput.data(), (int) doubleLengthOutput.size(),
  115. (int) input.size(), 0);
  116. std::vector<float> expectedDoubleLengthOutput (doubleLengthOutput.size());
  117. createGaussian (expectedDoubleLengthOutput, 1.0f, expectedGaussianMidpoint, expectedGaussianWidth);
  118. expectAllElementsWithin (doubleLengthOutput, expectedDoubleLengthOutput, 0.02f);
  119. beginTest (interpolatorName + " process wrap double ratio " + String (speedRatio));
  120. interpolator.reset();
  121. interpolator.process (speedRatio, input.data(), doubleLengthOutput.data(), (int) doubleLengthOutput.size(),
  122. (int) input.size(), (int) input.size());
  123. std::vector<float> secondGaussian (doubleLengthOutput.size());
  124. createGaussian (secondGaussian, 1.0f, expectedGaussianMidpoint + (float) outputBufferSize, expectedGaussianWidth);
  125. FloatVectorOperations::add (expectedDoubleLengthOutput.data(), secondGaussian.data(), (int) expectedDoubleLengthOutput.size());
  126. expectAllElementsWithin (doubleLengthOutput, expectedDoubleLengthOutput, 0.02f);
  127. }
  128. }
  129. public:
  130. void runTest() override
  131. {
  132. runInterplatorTests<WindowedSincInterpolator> ("WindowedSincInterpolator");
  133. runInterplatorTests<LagrangeInterpolator> ("LagrangeInterpolator");
  134. runInterplatorTests<CatmullRomInterpolator> ("CatmullRomInterpolator");
  135. runInterplatorTests<LinearInterpolator> ("LinearInterpolator");
  136. }
  137. };
  138. static InterpolatorTests interpolatorTests;
  139. #endif
  140. } // namespace juce