#pragma once #include #include /** * Utilities for generating and analyzing test signals. * * All test signals are +-1volt unless otherwise specified */ template class TestSignal { public: TestSignal() = delete; // we are only static // freq is normalized f / sr static void generateSin(T * output, int numSamples, T freq); static double getRMS(const T * signal, int numSamples); /** * Measure the gain of a processing lambda at a specificed frequency */ static T measureGain(T freq, std::function func); /** * Measure the RMS output of a generator lambda */ static double measureOutput(int samples, std::function func); }; template inline void TestSignal::generateSin(T * output, int numSamples, T freq) { assert(freq < .5); assert(freq > 0); double phase = 0; for (int i = 0; i < numSamples; ++i) { const double phi = phase * 2 * AudioMath::Pi; output[i] = T(std::sin(phi)); phase += freq; // should we normalize the phase here, instead of letting it grow? } } template inline double TestSignal::getRMS(const T * signal, int numSamples) { assert(numSamples > 0); double sumSq = 0; for (int i = 0; i < numSamples; ++i) { //printf("getRMS, i=%d, samp=%d\n") sumSq += double(signal[i]) * signal[i]; } return std::sqrt(sumSq / numSamples); } template inline T TestSignal::measureGain(T freq, std::function func) { const int size = 60000; T input[size]; T output[size]; //generateSin(T * output, int numSamples, T freq); TestSignal::generateSin(input, size, freq); for (int i = 0; i < size; ++i) { output[i] = func(input[i]); } T vo = T(TestSignal::getRMS(output, size)); T vi = T(TestSignal::getRMS(input, size)); return vo / vi; } template inline double TestSignal::measureOutput(int numSamples, std::function func) { //std::unique_ptr buffer(new T[numSamples]); std::vector buffer(numSamples); for (int i = 0; i < numSamples; ++i) { buffer[i] = func(); } return getRMS(buffer.data(), numSamples); }