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.

225 lines
5.0KB

  1. /**
  2. * THD+Noise tests for various sin generators
  3. */
  4. #include "Analyzer.h"
  5. #include "SinOscillator.h"
  6. #include <functional>
  7. #if 0
  8. const static int numSamples = 16 * 256 * 1024;
  9. //const static int numSamples = 256;
  10. const double sampleRate = 44100.0;
  11. const double sampleTime = 1.0 / sampleRate;
  12. const double testFreq = 700;
  13. static void testOsc(const std::string& title, double freq, std::function<float(void)> osc)
  14. {
  15. FFTDataCpx spectrum(numSamples);
  16. Analyzer::getSpectrum(spectrum, false, osc);
  17. Analyzer::getAndPrintFeatures(spectrum, 3, sampleRate, -180);
  18. double signal = 0;
  19. double noise = 0;
  20. int matches = 0;
  21. for (int i = 0; i < numSamples / 2; ++i) {
  22. const double f = FFT::bin2Freq(i, sampleRate, numSamples);
  23. const double mag = spectrum.getAbs(i);
  24. // if (f > 600 && f < 800) printf("%.2f: %f\n", f, mag);
  25. // if (mag > .00000001) printf("%.2f: %e\n", f, mag);
  26. if (freq == f) {
  27. ++matches;
  28. signal += mag;
  29. } else {
  30. noise += mag;
  31. }
  32. }
  33. assert(matches == 1);
  34. assert(noise > 0);
  35. printf("%s SNR = %f (db)\n", title.c_str(), AudioMath::db(signal / noise));
  36. }
  37. template <typename T>
  38. static void testPhaseAcc()
  39. {
  40. const double f = Analyzer::makeEvenPeriod(testFreq, sampleRate, numSamples);
  41. SinOscillatorParams<T> params;
  42. SinOscillatorState<T> state;
  43. std::string title = (sizeof(T) > 4) ? "double w lookup" : "float w lookup";
  44. SinOscillator<T, true>::setFrequency(params, float(f * sampleTime));
  45. testOsc(title, f, [&state, &params]() {
  46. return (float) SinOscillator<T, true>::run(state, params);
  47. });
  48. }
  49. static void testPhaseAcc2()
  50. {
  51. const double f = Analyzer::makeEvenPeriod(testFreq, sampleRate, numSamples);
  52. std::string title = "phase acc std::sin";
  53. double acc = 0;
  54. testOsc(title, f, [f, &acc]() {
  55. // return SinOscillator<T, true>::run(state, params);
  56. const double inc = f * sampleTime;
  57. acc += inc;
  58. if (acc > 1) {
  59. acc -= 1;
  60. }
  61. return float(std::sin(acc * AudioMath::Pi * 2));
  62. });
  63. }
  64. template <typename T>
  65. class Osc2
  66. {
  67. public:
  68. void setFreq(float t)
  69. {
  70. assert(t > 0 && t < .51);
  71. // orig paper
  72. // tapWeight = t * (1.0 / AudioMath::Pi);
  73. // tapWeight = t * 2;
  74. const T omega = 2.0 * AudioMath::Pi * t;
  75. tapWeight = 2 * sin(omega / 2.0);
  76. // from kvre
  77. //e= 2*sin(omega/2.0); // omega = 2*pi*freq/sr;
  78. }
  79. float run()
  80. {
  81. const T x = zX - tapWeight * zY;
  82. // orig paper
  83. // const T y = (tapWeight * zX) + (1 - tapWeight * tapWeight) * zY;
  84. // smith (seems whack?) but seems to work as well as the above
  85. const T y = (tapWeight * x) + zY;
  86. zX = x;
  87. zY = y;
  88. return float(zX);
  89. }
  90. const double k = sqrt(2);
  91. T zX = 1.200049 / k;
  92. T zY = .747444 / k;
  93. T tapWeight = .1;
  94. };
  95. template <typename T>
  96. class Osc3
  97. {
  98. public:
  99. void setFreq(float t)
  100. {
  101. assert(t > 0 && t < .51);
  102. // tapWeight = t * (1.0 / AudioMath::Pi);
  103. tapWeight = 2 * sin(t);
  104. }
  105. float run()
  106. {
  107. const T x = zX + tapWeight * zY;
  108. const T y = -(tapWeight * x) + zY;
  109. zX = x;
  110. zY = y;
  111. return float(zX);
  112. }
  113. // const double k = sqrt(2);
  114. T zX = 1;
  115. T zY = 1;
  116. T tapWeight = .1;
  117. };
  118. static void testOsc2()
  119. {
  120. const double f = Analyzer::makeEvenPeriod(testFreq, sampleRate, numSamples);
  121. // const double f = sampleRate / 2;
  122. printf("trying osc 2 at %f\n", f);
  123. std::string title = "osc2";
  124. Osc2<double> osc;
  125. osc.setFreq(float(f * sampleTime));
  126. for (int i = 0; i < 1000000; ++i) {
  127. osc.run();
  128. }
  129. testOsc(title, f, [&osc]() {
  130. return osc.run();
  131. });
  132. }
  133. static void testOsc3()
  134. {
  135. const double f = Analyzer::makeEvenPeriod(testFreq, sampleRate, numSamples);
  136. // const double f = sampleRate / 2;
  137. std::string title = "osc3";
  138. Osc3<double> osc;
  139. osc.setFreq(float(f * sampleTime));
  140. for (int i = 0; i < 1000000; ++i) {
  141. osc.run();
  142. }
  143. testOsc(title, f, [&osc]() {
  144. return osc.run();
  145. });
  146. }
  147. static void testOsc2Amp_sub(double freq)
  148. {
  149. const int bufSize = 16 * 1024 * 16;
  150. Osc2<double> osc;
  151. osc.setFreq(float(freq * sampleTime));
  152. for (int i = 0; i < 1000000; ++i) {
  153. osc.run();
  154. }
  155. std::vector<float> data;
  156. data.resize(bufSize);
  157. for (int i = 0; i < bufSize; ++i) {
  158. data[i] = osc.run();
  159. }
  160. auto minMax = AudioMath::getMinMax<float>(data.data(), bufSize);
  161. printf("f= %.2f min/max = %f, %f. z = %f, %f\n", freq, minMax.first, minMax.second, osc.zX, osc.zY);
  162. printf("sqr2 = %f\n", sqrt(2.0));
  163. }
  164. static void testOsc2Amp()
  165. {
  166. testOsc2Amp_sub(1111);
  167. testOsc2Amp_sub(40);
  168. testOsc2Amp_sub(400);
  169. testOsc2Amp_sub(4123);
  170. }
  171. void testSin()
  172. {
  173. // testPhaseAcc<float>();
  174. // testPhaseAcc<double>();
  175. testPhaseAcc2();
  176. // testOsc2();
  177. // testOsc3();
  178. // testOsc2Amp();
  179. }
  180. #endif