#include #include #include "MultiModOsc.h" #include "AudioMath.h" #include "SawOscillator.h" #include "TestSignal.h" using namespace std; // do objects exist? template static void testSaw1() { SawOscillatorParams params; SawOscillator::setFrequency(params, (T(.1))); SawOscillatorState state; SawOscillator::runSaw(state, params); using osc = MultiModOsc; typename osc::State mstate; typename osc::Params mparams; T output[3]; osc::run(output, mstate, mparams); } /** * Does parameter calculation do anything? */ template static void testSaw2() { SawOscillatorParams params; assert(params.phaseIncrement == 0); SawOscillator::setFrequency(params, (T(.1))); assert(params.phaseIncrement > 0); } /** * Does something come out? */ template static void testSaw3() { SawOscillatorParams params; SawOscillator::setFrequency(params, (T(.2))); SawOscillatorState state; SawOscillator::runSaw(state, params); const T out = SawOscillator::runSaw(state, params); assert(out > 0); assert(out < 1); } /** * Does something come out? */ template static void testTri3() { SawOscillatorParams params; SawOscillator::setFrequency(params, (T(.2))); SawOscillatorState state; SawOscillator::runSaw(state, params); const T out = SawOscillator::runTri(state, params); assert(out > 0); assert(out < 1); } /** * Does something come out? */ template static void testMulti3() { using osc = MultiModOsc; 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 static void testTri4() { const T freq = T(.1); // was .01 const T delta = 2 * freq; SawOscillatorParams params; SawOscillator::setFrequency(params, (T(.01))); SawOscillatorState state; T last = -freq; bool increasing = true; for (int i = 0; i < 1000; ++i) { const T output = SawOscillator::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 static void testSaw4() { const T freq = T(.01); const T delta = freq / 1000; SawOscillatorParams params; SawOscillator::setFrequency(params, (T(.01))); SawOscillatorState state; T last = 0; for (int i = 0; i < 1000; ++i) { const T output = SawOscillator::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 static void testSaw5() { SawOscillatorParams params; SawOscillator::setFrequency(params, (T(.01))); SawOscillatorState state; T output; T quadratureOutput; for (int i = 0; i < 1000; ++i) { SawOscillator::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 static void testSaw6() { const T freq = T(-.01); const T delta = freq / 1000; SawOscillatorParams params; SawOscillator::setFrequency(params, freq); SawOscillatorState state; T last = 0; for (int i = 0; i < 1000; ++i) { const T output = SawOscillator::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 static void testTri7() { const int div = 1024; const T freq = T(1.0 / T(div)); SawOscillatorParams params; SawOscillator::setFrequency(params, freq); SawOscillatorState state; double amplitude = TestSignal::measureOutput(div, [&state, ¶ms]() { return SawOscillator::runTri(state, params); }); // RMS of tri wave is 1 / cube root 3 assert(AudioMath::closeTo(amplitude, 0.57735, .0001)); } template static void testSaw7() { const int div = 1024; const T freq = T(1.0 / T(div)); SawOscillatorParams params; SawOscillator::setFrequency(params, freq); SawOscillatorState state; double amplitude = TestSignal::measureOutput(div * 16, [&state, ¶ms]() { // normalize to 1V pp return 2 * SawOscillator::runSaw(state, params) - 1; }); // RMS of saw wave is 1 / cube root 3 assert(AudioMath::closeTo(amplitude, 0.57735, .0001)); } template static void testSawT() { testSaw1(); testSaw2(); testSaw3(); testTri3(); testMulti3(); testSaw4(); testTri4(); testSaw5(); testSaw6(); testTri7(); testSaw7(); } void testSaw() { testSawT(); testSawT(); }