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.

358 lines
8.4KB

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