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.

281 lines
6.5KB

  1. #include <assert.h>
  2. #include <iostream>
  3. #include "MultiModOsc.h"
  4. #include "AudioMath.h"
  5. #include "SawOscillator.h"
  6. #include "TestSignal.h"
  7. using namespace std;
  8. // do objects exist?
  9. template<typename T>
  10. static void testSaw1()
  11. {
  12. SawOscillatorParams<T> params;
  13. SawOscillator<T, false>::setFrequency(params, (T(.1)));
  14. SawOscillatorState<T> state;
  15. SawOscillator<T, false>::runSaw(state, params);
  16. using osc = MultiModOsc<T, 4, 3>;
  17. typename osc::State mstate;
  18. typename osc::Params mparams;
  19. T output[3];
  20. osc::run(output, mstate, mparams);
  21. }
  22. /**
  23. * Does parameter calculation do anything?
  24. */
  25. template<typename T>
  26. static void testSaw2()
  27. {
  28. SawOscillatorParams<T> params;
  29. assert(params.phaseIncrement == 0);
  30. SawOscillator<T, false>::setFrequency(params, (T(.1)));
  31. assert(params.phaseIncrement > 0);
  32. }
  33. /**
  34. * Does something come out?
  35. */
  36. template<typename T>
  37. static void testSaw3()
  38. {
  39. SawOscillatorParams<T> params;
  40. SawOscillator<T, true>::setFrequency(params, (T(.2)));
  41. SawOscillatorState<T> state;
  42. SawOscillator<T, true>::runSaw(state, params);
  43. const T out = SawOscillator<T, true>::runSaw(state, params);
  44. assert(out > 0);
  45. assert(out < 1);
  46. }
  47. /**
  48. * Does something come out?
  49. */
  50. template<typename T>
  51. static void testTri3()
  52. {
  53. SawOscillatorParams<T> params;
  54. SawOscillator<T, true>::setFrequency(params, (T(.2)));
  55. SawOscillatorState<T> state;
  56. SawOscillator<T, true>::runSaw(state, params);
  57. const T out = SawOscillator<T, true>::runTri(state, params);
  58. assert(out > 0);
  59. assert(out < 1);
  60. }
  61. /**
  62. * Does something come out?
  63. */
  64. template<typename T>
  65. static void testMulti3()
  66. {
  67. using osc = MultiModOsc<T, 4, 3>;
  68. typename osc::State state;
  69. typename osc::Params params;
  70. T output[3] = {0, 0, 0};
  71. T output2[3] = {0, 0, 0};
  72. osc::run(output, state, params);
  73. osc::run(output, state, params);
  74. osc::run(output2, state, params);
  75. for (int i = 0; i < 3; ++i) {
  76. assert(output[i] != 0);
  77. assert(output2[i] != 0);
  78. assert(output[i] != output2[i]);
  79. if (i > 0) {
  80. assert(output[i] != output[i - 1]);
  81. assert(output2[i] != output2[i - 1]);
  82. }
  83. }
  84. }
  85. /**
  86. * Does it look like a triangle?
  87. */
  88. template<typename T>
  89. static void testTri4()
  90. {
  91. const T freq = T(.1); // was .01
  92. const T delta = 2 * freq;
  93. SawOscillatorParams<T> params;
  94. SawOscillator<T, true>::setFrequency(params, (T(.01)));
  95. SawOscillatorState<T> state;
  96. T last = -freq;
  97. bool increasing = true;
  98. for (int i = 0; i < 1000; ++i) {
  99. const T output = SawOscillator<T, true>::runTri(state, params);
  100. assert(output >= -1);
  101. assert(output <= 1);
  102. if (increasing) {
  103. if (output > last) {
  104. // still increasing
  105. } else {
  106. // started decreasing
  107. assert(AudioMath::closeTo(output, 1, delta));
  108. increasing = false;
  109. }
  110. } else {
  111. if (output < last) {
  112. // still decreasing
  113. } else {
  114. // started increasing
  115. assert(AudioMath::closeTo(output, -1, delta));
  116. increasing = true;
  117. }
  118. }
  119. last = output;
  120. }
  121. }
  122. /**
  123. * Does it look like a saw?
  124. */
  125. template<typename T>
  126. static void testSaw4()
  127. {
  128. const T freq = T(.01);
  129. const T delta = freq / 1000;
  130. SawOscillatorParams<T> params;
  131. SawOscillator<T, true>::setFrequency(params, (T(.01)));
  132. SawOscillatorState<T> state;
  133. T last = 0;
  134. for (int i = 0; i < 1000; ++i) {
  135. const T output = SawOscillator<T, true>::runSaw(state, params);
  136. assert(output >= 0);
  137. assert(output < 1);
  138. if (output < last) {
  139. assert(last > .99);
  140. assert(output < .01);
  141. } else {
  142. assert(output < (last + freq + delta));
  143. }
  144. last = output;
  145. }
  146. }
  147. /**
  148. * Is the quadrature really 90 out of phase?
  149. */
  150. template<typename T>
  151. static void testSaw5()
  152. {
  153. SawOscillatorParams<T> params;
  154. SawOscillator<T, true>::setFrequency(params, (T(.01)));
  155. SawOscillatorState<T> state;
  156. T output;
  157. T quadratureOutput;
  158. for (int i = 0; i < 1000; ++i) {
  159. SawOscillator<T, true>::runQuadrature(output, quadratureOutput, state, params);
  160. // normalize output (unwrap)
  161. if (quadratureOutput < output) {
  162. quadratureOutput += 1;
  163. }
  164. assert(quadratureOutput = (output + T(.25)));
  165. }
  166. }
  167. /**
  168. * Does it look like a negative saw?
  169. */
  170. template<typename T>
  171. static void testSaw6()
  172. {
  173. const T freq = T(-.01);
  174. const T delta = freq / 1000;
  175. SawOscillatorParams<T> params;
  176. SawOscillator<T, true>::setFrequency(params, freq);
  177. SawOscillatorState<T> state;
  178. T last = 0;
  179. for (int i = 0; i < 1000; ++i) {
  180. const T output = SawOscillator<T, true>::runSaw(state, params);
  181. assert(output >= 0);
  182. assert(output < 1);
  183. if (output > last) {
  184. // wrap case - did we more or less wrap?
  185. assert(last < .01);
  186. assert(output > .98);
  187. } else {
  188. // no-wrap - are we decreasing
  189. assert(output > (last + freq + delta));
  190. }
  191. last = output;
  192. }
  193. }
  194. /**
  195. * IS the RMS for triangle as expected?
  196. */
  197. template <typename T>
  198. static void testTri7()
  199. {
  200. const int div = 1024;
  201. const T freq = T(1.0 / T(div));
  202. SawOscillatorParams<T> params;
  203. SawOscillator<T, true>::setFrequency(params, freq);
  204. SawOscillatorState<T> state;
  205. double amplitude = TestSignal<T>::measureOutput(div, [&state, &params]() {
  206. return SawOscillator<T, true>::runTri(state, params);
  207. });
  208. // RMS of tri wave is 1 / cube root 3
  209. assert(AudioMath::closeTo(amplitude, 0.57735, .0001));
  210. }
  211. template <typename T>
  212. static void testSaw7()
  213. {
  214. const int div = 1024;
  215. const T freq = T(1.0 / T(div));
  216. SawOscillatorParams<T> params;
  217. SawOscillator<T, true>::setFrequency(params, freq);
  218. SawOscillatorState<T> state;
  219. double amplitude = TestSignal<T>::measureOutput(div * 16, [&state, &params]() {
  220. // normalize to 1V pp
  221. return 2 * SawOscillator<T, true>::runSaw(state, params) - 1;
  222. });
  223. // RMS of saw wave is 1 / cube root 3
  224. assert(AudioMath::closeTo(amplitude, 0.57735, .0001));
  225. }
  226. template <typename T>
  227. static void testSawT()
  228. {
  229. testSaw1<T>();
  230. testSaw2<T>();
  231. testSaw3<T>();
  232. testTri3<T>();
  233. testMulti3<T>();
  234. testSaw4<T>();
  235. testTri4<T>();
  236. testSaw5<T>();
  237. testSaw6<T>();
  238. testTri7<T>();
  239. testSaw7<T>();
  240. }
  241. void testSaw()
  242. {
  243. testSawT<float>();
  244. testSawT<double>();
  245. }