#include #include #include "asserts.h" #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 testSawFreq_old(bool neg) { // assert(!neg); const T freq = neg ? T(-.1) : T(.1); SawOscillatorParams params; SawOscillator::setFrequency(params, freq); SawOscillatorState state; T lastValue = neg ? T(-100) : T(100); for (int i = 0; i < 100; ++i) { T saw = SawOscillator::runSaw(state, params); if (!neg) { if (0 == (i % 10)) { assertLT(saw, lastValue); } else { assertGT(saw, lastValue); } } else { #if 0 if (0 == (i % 10)) { assertGT(saw, lastValue); } else { assertLT(saw, lastValue); } #endif printf("i = %d out=%.2f\n", i, saw); fflush(stdout); } lastValue = saw; } } template static void testSawFreq(bool neg) { int period = 10000; if (sizeof(T) > 4) { period *= 1000; } T freq = T(1.0 / period); if (neg) { freq *= -1; } SawOscillatorParams params; SawOscillator::setFrequency(params, freq); SawOscillatorState state; T last = SawOscillator::runSaw(state, params); bool done = false; int count = 0; for (; !done; ++count) { if (count > period + 100) { done = true; assert(false); } T saw = SawOscillator::runSaw(state, params); assertNE(saw, last); bool moreThanLast = saw > last; last = saw; // if saw is turning going back if (moreThanLast == neg) { const int measuredPeriod = count + 1; assertClose(measuredPeriod, period, 1.1); done = true; } } } template static void testSawT() { testSaw1(); testSaw2(); testSaw3(); testTri3(); testMulti3(); testSaw4(); testTri4(); testSaw5(); testSaw6(); testTri7(); testSaw7(); testSawFreq(false); // testSawFreq(true); } void testSaw() { testSawT(); testSawT(); }