The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

150 lines
5.5KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. template <typename FloatType>
  20. LookupTable<FloatType>::LookupTable()
  21. {
  22. data.resize (1);
  23. }
  24. template <typename FloatType>
  25. LookupTable<FloatType>::LookupTable (const std::function<FloatType (size_t)>& functionToApproximate,
  26. size_t numPointsToUse)
  27. {
  28. initialise (functionToApproximate, numPointsToUse);
  29. }
  30. //==============================================================================
  31. template <typename FloatType>
  32. void LookupTable<FloatType>::initialise (const std::function<FloatType (size_t)>& functionToApproximate,
  33. size_t numPointsToUse)
  34. {
  35. data.resize (static_cast<int> (getRequiredBufferSize (numPointsToUse)));
  36. for (size_t i = 0; i < numPointsToUse; ++i)
  37. {
  38. auto value = functionToApproximate (i);
  39. jassert (! std::isnan (value));
  40. jassert (! std::isinf (value));
  41. // Make sure functionToApproximate returns a sensible value for the entire specified range.
  42. // E.g., this won't work for zero: [] (size_t i) { return 1.0f / i; }
  43. data.getReference (static_cast<int> (i)) = value;
  44. }
  45. prepare();
  46. }
  47. template <typename FloatType>
  48. void LookupTable<FloatType>::prepare() noexcept
  49. {
  50. auto guardIndex = static_cast<int> (getGuardIndex());
  51. data.getReference (guardIndex) = data.getUnchecked (guardIndex - 1);
  52. }
  53. template <typename FloatType>
  54. void LookupTableTransform<FloatType>::initialise (const std::function<FloatType (FloatType)>& functionToApproximate,
  55. FloatType minInputValueToUse,
  56. FloatType maxInputValueToUse,
  57. size_t numPoints)
  58. {
  59. jassert (maxInputValueToUse > minInputValueToUse);
  60. minInputValue = minInputValueToUse;
  61. maxInputValue = maxInputValueToUse;
  62. scaler = FloatType (numPoints - 1) / (maxInputValueToUse - minInputValueToUse);
  63. offset = -minInputValueToUse * scaler;
  64. const auto initFn = [functionToApproximate, minInputValueToUse, maxInputValueToUse, numPoints] (size_t i)
  65. {
  66. return functionToApproximate (
  67. jlimit (
  68. minInputValueToUse, maxInputValueToUse,
  69. jmap (FloatType (i), FloatType (0), FloatType (numPoints - 1), minInputValueToUse, maxInputValueToUse))
  70. );
  71. };
  72. lookupTable.initialise (initFn, numPoints);
  73. }
  74. //==============================================================================
  75. template <typename FloatType>
  76. double LookupTableTransform<FloatType>::calculateMaxRelativeError (const std::function<FloatType (FloatType)>& functionToApproximate,
  77. FloatType minInputValue,
  78. FloatType maxInputValue,
  79. size_t numPoints,
  80. size_t numTestPoints)
  81. {
  82. jassert (maxInputValue > minInputValue);
  83. if (numTestPoints == 0)
  84. numTestPoints = 100 * numPoints; // use default
  85. LookupTableTransform transform (functionToApproximate, minInputValue, maxInputValue, numPoints);
  86. double maxError = 0;
  87. for (size_t i = 0; i < numTestPoints; ++i)
  88. {
  89. auto inputValue = jmap (FloatType (i), FloatType (0), FloatType (numTestPoints - 1), minInputValue, maxInputValue);
  90. auto approximatedOutputValue = transform.processSample (inputValue);
  91. auto referenceOutputValue = functionToApproximate (inputValue);
  92. maxError = jmax (maxError, calculateRelativeDifference ((double) referenceOutputValue, (double) approximatedOutputValue));
  93. }
  94. return maxError;
  95. }
  96. //==============================================================================
  97. template <typename FloatType>
  98. double LookupTableTransform<FloatType>::calculateRelativeDifference (double x, double y) noexcept
  99. {
  100. static const auto eps = std::numeric_limits<double>::min();
  101. auto absX = std::abs (x);
  102. auto absY = std::abs (y);
  103. auto absDiff = std::abs (x - y);
  104. if (absX < eps)
  105. {
  106. if (absY >= eps)
  107. return absDiff / absY;
  108. return absDiff; // return the absolute error if both numbers are too close to zero
  109. }
  110. return absDiff / std::min (absX, absY);
  111. }
  112. //==============================================================================
  113. template class LookupTable<float>;
  114. template class LookupTable<double>;
  115. template class LookupTableTransform<float>;
  116. template class LookupTableTransform<double>;