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.

270 lines
7.4KB

  1. #include <assert.h>
  2. #include <iostream>
  3. #include "asserts.h"
  4. #include "AudioMath.h"
  5. #include "LookupTable.h"
  6. #include "LookupTableFactory.h"
  7. using namespace std;
  8. // test that we can call all the functions
  9. template<typename T>
  10. static void test0()
  11. {
  12. LookupTableParams<T> p;
  13. const int tableSize = 512;
  14. std::function<double(double)> f = [](double d) {
  15. return 0;
  16. };
  17. LookupTable<T>::init(p, tableSize, 0, 1, f);
  18. LookupTable<T>::lookup(p, 0);
  19. }
  20. // test that simple lookup works
  21. template<typename T>
  22. static void test1()
  23. {
  24. LookupTableParams<T> p;
  25. const int tableSize = 512;
  26. std::function<double(double)> f = [](double d) {
  27. return 100;
  28. };
  29. LookupTable<T>::init(p, tableSize, 0, 1, f);
  30. assert(LookupTable<T>::lookup(p, 0) == 100);
  31. assert(LookupTable<T>::lookup(p, 1) == 100);
  32. assert(LookupTable<T>::lookup(p, T(.342)) == 100);
  33. }
  34. // test that sin works
  35. template<typename T>
  36. static void test2()
  37. {
  38. LookupTableParams<T> p;
  39. const int tableSize = 512;
  40. std::function<double(double)> f = [](double d) {
  41. return std::sin(d);
  42. };
  43. LookupTable<T>::init(p, tableSize, 0, 1, f);
  44. const T tolerance = T(0.000001);
  45. for (double d = 0; d < 1; d += .0001) {
  46. T output = LookupTable<T>::lookup(p, T(d));
  47. const bool t = AudioMath::closeTo(output, std::sin(d), tolerance);
  48. if (!t) {
  49. cout << "failing with expected=" << std::sin(d) << " actual=" << output << " delta=" << std::abs(output - std::sin(d));
  50. assert(false);
  51. }
  52. }
  53. }
  54. // test that sin works on domain 10..32
  55. template<typename T>
  56. static void test3()
  57. {
  58. LookupTableParams<T> p;
  59. const int tableSize = 16;
  60. std::function<double(double)> f = [](double d) {
  61. const double s = (d - 10) / 3;
  62. return std::sin(s);
  63. };
  64. LookupTable<T>::init(p, tableSize, 10, 13, f);
  65. const T tolerance = T(0.01);
  66. for (double d = 10; d < 13; d += .0001) {
  67. const T output = LookupTable<T>::lookup(p, T(d));
  68. const T expected = (T) std::sin((d - 10.0) / 3);
  69. const bool t = AudioMath::closeTo(output, expected, tolerance);
  70. if (!t) {
  71. cout << "failing with d=" << d << " expected=" << expected << " actual=" << output << " delta=" << std::abs(output - std::sin(d));
  72. assert(false);
  73. }
  74. }
  75. }
  76. // test that sin at extremes works
  77. template<typename T>
  78. static void test4()
  79. {
  80. LookupTableParams<T> exponential;
  81. const T xMin = -5;
  82. const T xMax = 5;
  83. std::function<double(double)> expFunc = AudioMath::makeFunc_Exp(-5, 5, 2, 2000);
  84. LookupTable<T>::init(exponential, 128, -5, 5, expFunc);
  85. // Had to loosen tolerance to pass with windows gcc. Is there a problem
  86. // with precision, or is this expected with fast math?
  87. const T tolerance = T(0.0003);
  88. T outputLow = LookupTable<T>::lookup(exponential, xMin);
  89. T outputHigh = LookupTable<T>::lookup(exponential, xMax);
  90. bool t = AudioMath::closeTo(outputLow, 2, tolerance);
  91. if (!t) {
  92. cout << "failing l with expected=" << 2 << " actual=" << outputLow << " delta=" << std::abs(outputLow - 2) << std::endl;
  93. assert(false);
  94. }
  95. t = AudioMath::closeTo(outputHigh, 2000, tolerance);
  96. if (!t) {
  97. cout << "failing h with expected=" << 2000 << " actual=" << outputHigh << " delta=" << std::abs(outputHigh - 2000) << std::endl;
  98. assert(false);
  99. }
  100. }
  101. template<typename T>
  102. static void testDiscrete1()
  103. {
  104. LookupTableParams<T> lookup;
  105. T y[] = {0, 10};
  106. LookupTable<T>::initDiscrete(lookup, 2, y);
  107. assertEQ(LookupTable<T>::lookup(lookup, 0), 0);
  108. assertEQ(LookupTable<T>::lookup(lookup, .5), 5);
  109. assertEQ(LookupTable<T>::lookup(lookup, 1), 10);
  110. assertEQ(LookupTable<T>::lookup(lookup, T(.1)), 1);
  111. assertClose(LookupTable<T>::lookup(lookup, T(.01)), T(.1), .00001);
  112. }
  113. template<typename T>
  114. static void testDiscrete2()
  115. {
  116. LookupTableParams<T> lookup;
  117. T y[] = {100, 100.5, 2000, -10};
  118. LookupTable<T>::initDiscrete(lookup, 4, y);
  119. assertEQ(LookupTable<T>::lookup(lookup, 0), 100);
  120. assertEQ(LookupTable<T>::lookup(lookup, 1), 100.5);
  121. assertEQ(LookupTable<T>::lookup(lookup, 2), 2000);
  122. assertEQ(LookupTable<T>::lookup(lookup, 3), -10);
  123. assertEQ(LookupTable<T>::lookup(lookup, 2.5), 1000 - 5);
  124. }
  125. template<typename T>
  126. static void testExpSimpleLookup()
  127. {
  128. LookupTableParams<T> lookup;
  129. LookupTableFactory<T>::makeExp2(lookup);
  130. const double xMin = LookupTableFactory<T>::expXMin();
  131. const double xMax = LookupTableFactory<T>::expXMax();
  132. assert(5 > xMin);
  133. assert(11 < xMax);
  134. assertClose(LookupTable<T>::lookup(lookup, 5), std::pow(2, 5), .01);
  135. assertClose(LookupTable<T>::lookup(lookup, 11), std::pow(2, 11), 2); // TODO: tighten
  136. }
  137. // test that extreme inputs is clamped
  138. template<typename T>
  139. static void testExpRange()
  140. {
  141. LookupTableParams<T> lookup;
  142. LookupTable<T>::makeExp2(lookup);
  143. auto k1 = LookupTable<T>::lookup(lookup, -1);
  144. auto k2 = LookupTable<T>::lookup(lookup, 11);
  145. assertClose(LookupTable<T>::lookup(lookup, -1), LookupTable<T>::lookup(lookup, 0), .01);
  146. assertClose(LookupTable<T>::lookup(lookup, 11), LookupTable<T>::lookup(lookup, 10), .01);
  147. assertClose(LookupTable<T>::lookup(lookup, -100), LookupTable<T>::lookup(lookup, 0), .01);
  148. assertClose(LookupTable<T>::lookup(lookup, 1100), LookupTable<T>::lookup(lookup, 10), .01);
  149. }
  150. template<typename T>
  151. static void testExpTolerance(T centsTolerance)
  152. {
  153. const T xMin = (T) LookupTableFactory<T>::expXMin();
  154. const T xMax = (T) LookupTableFactory<T>::expXMax();
  155. LookupTableParams<T> table;
  156. LookupTableFactory<T>::makeExp2(table);
  157. for (T x = xMin; x <= xMax; x += T(.0001)) {
  158. T y = LookupTable<T>::lookup(table, x); // and back
  159. double accurate = std::pow(2.0, x);
  160. double errorCents = std::abs(1200.0 * std::log2(y / accurate));
  161. assertClose(errorCents, 0, centsTolerance);
  162. }
  163. }
  164. template <typename T>
  165. static void testBipolarSimpleLookup()
  166. {
  167. LookupTableParams<T> lookup;
  168. LookupTableFactory<T>::makeBipolarAudioTaper(lookup);
  169. assertClose(LookupTable<T>::lookup(lookup, 0), 0, .01);
  170. assertClose(LookupTable<T>::lookup(lookup, 1), 1, .01);
  171. assertClose(LookupTable<T>::lookup(lookup, -1), -1, .01);
  172. }
  173. template <typename T>
  174. static void testBipolarTolerance()
  175. {
  176. LookupTableParams<T> lookup;
  177. LookupTableFactory<T>::makeBipolarAudioTaper(lookup);
  178. const double toleratedError = 1 - AudioMath::gainFromDb(-.1);// let's go for one db.
  179. assert(toleratedError > 0);
  180. auto refFuncPos = AudioMath::makeFunc_AudioTaper(LookupTableFactory<T>::audioTaperKnee());
  181. auto refFuncNeg = [refFuncPos](double x) {
  182. assert(x <= 0);
  183. return -refFuncPos(-x);
  184. };
  185. for (double x = -1; x < 1; x += .001) {
  186. const T test = LookupTable<T>::lookup(lookup, (T) x);
  187. T ref = 1234;
  188. if (x < 0) {
  189. ref = (T) refFuncNeg(x);
  190. } else {
  191. ref = (T) refFuncPos(x);
  192. }
  193. assertClose(test, ref, toleratedError);
  194. }
  195. }
  196. template<typename T>
  197. static void test()
  198. {
  199. test0<T>();
  200. test1<T>();
  201. test2<T>();
  202. test3<T>();
  203. test4<T>();
  204. testDiscrete1<T>();
  205. testDiscrete2<T>();
  206. testExpSimpleLookup<T>();
  207. testExpTolerance<T>(100); // 1 semitone
  208. testExpTolerance<T>(10);
  209. testExpTolerance<T>(1);
  210. testBipolarSimpleLookup<T>();
  211. testBipolarTolerance<T>();
  212. }
  213. void testLookupTable()
  214. {
  215. test<float>();
  216. test<double>();
  217. }