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.

101 lines
2.5KB

  1. #pragma once
  2. #include <cmath>
  3. #include <vector>
  4. /**
  5. * Utilities for generating and analyzing test signals.
  6. *
  7. * All test signals are +-1volt unless otherwise specified
  8. */
  9. template <typename T>
  10. class TestSignal
  11. {
  12. public:
  13. TestSignal() = delete; // we are only static
  14. // freq is normalized f / sr
  15. static void generateSin(T * output, int numSamples, T freq);
  16. static double getRMS(const T * signal, int numSamples);
  17. static double getDC(const T * signal, int numSamples);
  18. /**
  19. * Measure the gain of a processing lambda at a specificed frequency
  20. */
  21. static T measureGain(T freq, std::function<T(T)> func);
  22. /**
  23. * Measure the RMS output of a generator lambda
  24. */
  25. static double measureOutput(int samples, std::function<T()> func);
  26. };
  27. template <typename T>
  28. inline void TestSignal<T>::generateSin(T * output, int numSamples, T freq)
  29. {
  30. assert(freq < .5);
  31. assert(freq > 0);
  32. double phase = 0;
  33. for (int i = 0; i < numSamples; ++i) {
  34. const double phi = phase * 2 * AudioMath::Pi;
  35. output[i] = T(std::sin(phi));
  36. phase += freq;
  37. // should we normalize the phase here, instead of letting it grow?
  38. }
  39. }
  40. template <typename T>
  41. inline double TestSignal<T>::getRMS(const T * signal, int numSamples)
  42. {
  43. assert(numSamples > 0);
  44. double sumSq = 0;
  45. for (int i = 0; i < numSamples; ++i) {
  46. //printf("getRMS, i=%d, samp=%d\n")
  47. sumSq += double(signal[i]) * signal[i];
  48. }
  49. return std::sqrt(sumSq / numSamples);
  50. }
  51. template <typename T>
  52. inline double TestSignal<T>::getDC(const T * signal, int numSamples)
  53. {
  54. assert(numSamples > 0);
  55. double sum = 0;
  56. for (int i = 0; i < numSamples; ++i) {
  57. sum += signal[i];
  58. }
  59. return sum / numSamples;
  60. }
  61. template <typename T>
  62. inline T TestSignal<T>::measureGain(T freq, std::function<T(T)> func)
  63. {
  64. const int size = 60000;
  65. T input[size];
  66. T output[size];
  67. //generateSin(T * output, int numSamples, T freq);
  68. TestSignal<T>::generateSin(input, size, freq);
  69. for (int i = 0; i < size; ++i) {
  70. output[i] = func(input[i]);
  71. }
  72. T vo = T(TestSignal<T>::getRMS(output, size));
  73. T vi = T(TestSignal<T>::getRMS(input, size));
  74. return vo / vi;
  75. }
  76. template <typename T>
  77. inline double TestSignal<T>::measureOutput(int numSamples, std::function<T()> func)
  78. {
  79. //std::unique_ptr<T> buffer(new T[numSamples]);
  80. std::vector<T> buffer(numSamples);
  81. for (int i = 0; i < numSamples; ++i) {
  82. buffer[i] = func();
  83. }
  84. return getRMS(buffer.data(), numSamples);
  85. }