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.

157 lines
5.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - 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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-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. namespace dsp
  21. {
  22. template <typename FloatType>
  23. LookupTable<FloatType>::LookupTable()
  24. {
  25. data.resize (1);
  26. }
  27. template <typename FloatType>
  28. LookupTable<FloatType>::LookupTable (const std::function<FloatType (size_t)>& functionToApproximate,
  29. size_t numPointsToUse)
  30. {
  31. initialise (functionToApproximate, numPointsToUse);
  32. }
  33. //==============================================================================
  34. template <typename FloatType>
  35. void LookupTable<FloatType>::initialise (const std::function<FloatType (size_t)>& functionToApproximate,
  36. size_t numPointsToUse)
  37. {
  38. data.resize (static_cast<int> (getRequiredBufferSize (numPointsToUse)));
  39. for (size_t i = 0; i < numPointsToUse; ++i)
  40. {
  41. auto value = functionToApproximate (i);
  42. jassert (! std::isnan (value));
  43. jassert (! std::isinf (value));
  44. // Make sure functionToApproximate returns a sensible value for the entire specified range.
  45. // E.g., this won't work for zero: [] (size_t i) { return 1.0f / i; }
  46. data.getReference (static_cast<int> (i)) = value;
  47. }
  48. prepare();
  49. }
  50. template <typename FloatType>
  51. void LookupTable<FloatType>::prepare() noexcept
  52. {
  53. auto guardIndex = static_cast<int> (getGuardIndex());
  54. data.getReference (guardIndex) = data.getUnchecked (guardIndex - 1);
  55. }
  56. template <typename FloatType>
  57. void LookupTableTransform<FloatType>::initialise (const std::function<FloatType (FloatType)>& functionToApproximate,
  58. FloatType minInputValueToUse,
  59. FloatType maxInputValueToUse,
  60. size_t numPoints)
  61. {
  62. jassert (maxInputValueToUse > minInputValueToUse);
  63. minInputValue = minInputValueToUse;
  64. maxInputValue = maxInputValueToUse;
  65. scaler = FloatType (numPoints - 1) / (maxInputValueToUse - minInputValueToUse);
  66. offset = -minInputValueToUse * scaler;
  67. const auto initFn = [functionToApproximate, minInputValueToUse, maxInputValueToUse, numPoints] (size_t i)
  68. {
  69. return functionToApproximate (
  70. jlimit (
  71. minInputValueToUse, maxInputValueToUse,
  72. jmap (FloatType (i), FloatType (0), FloatType (numPoints - 1), minInputValueToUse, maxInputValueToUse))
  73. );
  74. };
  75. lookupTable.initialise (initFn, numPoints);
  76. }
  77. //==============================================================================
  78. template <typename FloatType>
  79. double LookupTableTransform<FloatType>::calculateMaxRelativeError (const std::function<FloatType (FloatType)>& functionToApproximate,
  80. FloatType minInputValue,
  81. FloatType maxInputValue,
  82. size_t numPoints,
  83. size_t numTestPoints)
  84. {
  85. jassert (maxInputValue > minInputValue);
  86. if (numTestPoints == 0)
  87. numTestPoints = 100 * numPoints; // use default
  88. LookupTableTransform transform (functionToApproximate, minInputValue, maxInputValue, numPoints);
  89. double maxError = 0;
  90. for (size_t i = 0; i < numTestPoints; ++i)
  91. {
  92. auto inputValue = jmap (FloatType (i), FloatType (0), FloatType (numTestPoints - 1), minInputValue, maxInputValue);
  93. auto approximatedOutputValue = transform.processSample (inputValue);
  94. auto referenceOutputValue = functionToApproximate (inputValue);
  95. maxError = jmax (maxError, calculateRelativeDifference ((double) referenceOutputValue, (double) approximatedOutputValue));
  96. }
  97. return maxError;
  98. }
  99. //==============================================================================
  100. template <typename FloatType>
  101. double LookupTableTransform<FloatType>::calculateRelativeDifference (double x, double y) noexcept
  102. {
  103. static const auto eps = std::numeric_limits<double>::min();
  104. auto absX = std::abs (x);
  105. auto absY = std::abs (y);
  106. auto absDiff = std::abs (x - y);
  107. if (absX < eps)
  108. {
  109. if (absY >= eps)
  110. return absDiff / absY;
  111. return absDiff; // return the absolute error if both numbers are too close to zero
  112. }
  113. return absDiff / std::min (absX, absY);
  114. }
  115. //==============================================================================
  116. template class LookupTable<float>;
  117. template class LookupTable<double>;
  118. template class LookupTableTransform<float>;
  119. template class LookupTableTransform<double>;
  120. } // namespace dsp
  121. } // namespace juce