|  | #pragma once
#include <cmath>
#include <vector>
/**
 * Utilities for generating and analyzing test signals.
 *
 * All test signals are +-1volt unless otherwise specified
 */
template <typename T>
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<T(T)> func);
    /**
     * Measure the RMS output of a generator lambda
     */
    static double measureOutput(int samples, std::function<T()> func);
};
template <typename T>
inline void TestSignal<T>::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 <typename T>
inline double TestSignal<T>::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 <typename T>
inline T TestSignal<T>::measureGain(T freq, std::function<T(T)> func)
{
    const int size = 60000;
    T input[size];
    T output[size];
    //generateSin(T * output, int numSamples, T freq);
    TestSignal<T>::generateSin(input, size, freq);
    for (int i = 0; i < size; ++i) {
        output[i] = func(input[i]);
    }
    T vo = T(TestSignal<T>::getRMS(output, size));
    T vi = T(TestSignal<T>::getRMS(input, size));
    return vo / vi;
}
template <typename T>
inline double TestSignal<T>::measureOutput(int numSamples, std::function<T()> func)
{
    //std::unique_ptr<T> buffer(new T[numSamples]);
    std::vector<T> buffer(numSamples);
    for (int i = 0; i < numSamples; ++i) {
        buffer[i] = func();
    }
   
    return getRMS(buffer.data(), numSamples);
}
 |