|  | #include <assert.h>
#include <iostream>
#include "MultiModOsc.h"
#include "AudioMath.h"
#include "SawOscillator.h"
#include "TestSignal.h"
using namespace std;
// do objects exist?
template<typename T>
static void testSaw1()
{
    SawOscillatorParams<T> params;
    SawOscillator<T, false>::setFrequency(params, (T(.1)));
    SawOscillatorState<T> state;
    SawOscillator<T, false>::runSaw(state, params);
    using osc = MultiModOsc<T, 4, 3>;
    typename osc::State mstate;
    typename osc::Params mparams;
    T output[3];
    osc::run(output, mstate, mparams);
}
/**
 * Does parameter calculation do anything?
 */
template<typename T>
static void testSaw2()
{
    SawOscillatorParams<T> params;
    assert(params.phaseIncrement == 0);
    SawOscillator<T, false>::setFrequency(params, (T(.1)));
    assert(params.phaseIncrement > 0);
}
/**
 * Does something come out?
 */
template<typename T>
static void testSaw3()
{
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, (T(.2)));
    SawOscillatorState<T> state;
    SawOscillator<T, true>::runSaw(state, params);
    const T out = SawOscillator<T, true>::runSaw(state, params);
    assert(out > 0);
    assert(out < 1);
}
/**
* Does something come out?
*/
template<typename T>
static void testTri3()
{
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, (T(.2)));
    SawOscillatorState<T> state;
    SawOscillator<T, true>::runSaw(state, params);
    const T out = SawOscillator<T, true>::runTri(state, params);
    assert(out > 0);
    assert(out < 1);
}
/**
* Does something come out?
*/
template<typename T>
static void testMulti3()
{
    using osc = MultiModOsc<T, 4, 3>;
    typename osc::State state;
    typename osc::Params params;
    T output[3] = {0, 0, 0};
    T output2[3] = {0, 0, 0};
    osc::run(output, state, params);
    osc::run(output, state, params);
    osc::run(output2, state, params);
    for (int i = 0; i < 3; ++i) {
        assert(output[i] != 0);
        assert(output2[i] != 0);
        assert(output[i] != output2[i]);
        if (i > 0) {
            assert(output[i] != output[i - 1]);
            assert(output2[i] != output2[i - 1]);
        }
    }
}
/**
 * Does it look like a triangle?
 */
template<typename T>
static void testTri4()
{
    const T freq = T(.1);     // was .01
    const T delta = 2 * freq;
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, (T(.01)));
    SawOscillatorState<T> state;
    T last = -freq;
    bool increasing = true;
    for (int i = 0; i < 1000; ++i) {
        const T output = SawOscillator<T, true>::runTri(state, params);
        assert(output >= -1);
        assert(output <= 1);
        if (increasing) {
            if (output > last) {
                // still increasing
            } else {
                // started decreasing
                assert(AudioMath::closeTo(output, 1, delta));
                increasing = false;
            }
        } else {
            if (output < last) {
                // still decreasing
            } else {
                // started increasing
                assert(AudioMath::closeTo(output, -1, delta));
                increasing = true;
            }
        }
        last = output;
    }
}
/**
* Does it look like a saw?
*/
template<typename T>
static void testSaw4()
{
    const T freq = T(.01);
    const T delta = freq / 1000;
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, (T(.01)));
    SawOscillatorState<T> state;
    T last = 0;
    for (int i = 0; i < 1000; ++i) {
        const T output = SawOscillator<T, true>::runSaw(state, params);
        assert(output >= 0);
        assert(output < 1);
        if (output < last) {
            assert(last > .99);
            assert(output < .01);
        } else {
            assert(output < (last + freq + delta));
        }
        last = output;
    }
}
/**
* Is the quadrature really 90 out of phase?
*/
template<typename T>
static void testSaw5()
{
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, (T(.01)));
    SawOscillatorState<T> state;
    T output;
    T quadratureOutput;
    for (int i = 0; i < 1000; ++i) {
        SawOscillator<T, true>::runQuadrature(output, quadratureOutput, state, params);
        // normalize output (unwrap)
        if (quadratureOutput < output) {
            quadratureOutput += 1;
        }
        assert(quadratureOutput = (output + T(.25)));
    }
}
/**
* Does it look like a negative saw?
*/
template<typename T>
static void testSaw6()
{
    const T freq = T(-.01);
    const T delta = freq / 1000;
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, freq);
    SawOscillatorState<T> state;
    T last = 0;
    for (int i = 0; i < 1000; ++i) {
        const T output = SawOscillator<T, true>::runSaw(state, params);
        assert(output >= 0);
        assert(output < 1);
        if (output > last) {
            // wrap case - did we more or less wrap?
            assert(last < .01);
            assert(output > .98);
        } else {
            // no-wrap - are we decreasing
            assert(output > (last + freq + delta));
        }
        last = output;
    }
}
/**
 * IS the RMS for triangle as expected?
 */
template <typename T>
static void testTri7()
{
    const int div = 1024;
    const T freq = T(1.0 / T(div));
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, freq);
    SawOscillatorState<T> state;
    double amplitude = TestSignal<T>::measureOutput(div, [&state, ¶ms]() {
        return SawOscillator<T, true>::runTri(state, params);
        });
    // RMS of tri wave is 1 / cube root 3
    assert(AudioMath::closeTo(amplitude, 0.57735, .0001));
}
template <typename T>
static void testSaw7()
{
    const int div = 1024;
    const T freq = T(1.0 / T(div));
    SawOscillatorParams<T> params;
    SawOscillator<T, true>::setFrequency(params, freq);
    SawOscillatorState<T> state;
    double amplitude = TestSignal<T>::measureOutput(div * 16, [&state, ¶ms]() {
        // normalize to 1V pp
        return 2 * SawOscillator<T, true>::runSaw(state, params) - 1;
        });
    // RMS of saw wave is 1 / cube root 3
    assert(AudioMath::closeTo(amplitude, 0.57735, .0001));
}
template <typename T>
static void testSawT()
{
    testSaw1<T>();
    testSaw2<T>();
    testSaw3<T>();
    testTri3<T>();
    testMulti3<T>();
    testSaw4<T>();
    testTri4<T>();
    testSaw5<T>();
    testSaw6<T>();
    testTri7<T>();
    testSaw7<T>();
}
void testSaw()
{
    testSawT<float>();
    testSawT<double>();
}
 |