| 
							- #include "asserts.h"
 - 
 - 
 - #include "ExtremeTester.h"
 - #include "VocalAnimator.h"
 - #include "TestComposite.h"
 - #include "VocalFilter.h"
 - #include "FormantTables2.h"
 - 
 - using Animator = VocalAnimator<TestComposite>;
 - 
 - /**
 -  * Verify no output with no input.
 -  */
 - static void test0()
 - {
 -     Animator anim;
 -     anim.setSampleRate(44100);
 -     anim.init();
 - 
 -     anim.outputs[Animator::AUDIO_OUTPUT].value = 0;
 -     anim.step();                // prime it
 - 
 -                                 // with no input, should have no output
 -     for (int i = 0; i < 50; ++i) {
 -         anim.step();
 -         assert(anim.outputs[Animator::AUDIO_OUTPUT].value == 0);
 -     }
 - }
 - 
 - /**
 -  * Verify output with input.
 -  */
 - static void test1()
 - {
 -     Animator anim;
 -     anim.setSampleRate(44100);
 -     anim.init();
 - 
 -     anim.outputs[Animator::AUDIO_OUTPUT].value = 0;
 -     anim.inputs[Animator::AUDIO_INPUT].value = 1;
 -     anim.step();                // prime it
 -                                 // with  input, should have  output
 -     for (int i = 0; i < 50; ++i) {
 -         anim.step();
 -         assert(anim.outputs[Animator::AUDIO_OUTPUT].value != 0);
 -     }
 - }
 - 
 - /**
 -  * Verify filter settings with no mod.
 -  */
 - static void test2()
 - {
 -     Animator anim;
 -     anim.setSampleRate(44100);
 -     anim.init();
 -     for (int i = 0; i < 4; ++i) {
 -         float freq = anim.normalizedFilterFreq[i] * 44100;
 -         assertEQ(freq, anim.nominalFilterCenterHz[i]);
 -     }
 - }
 - 
 - /**
 - * Verify filter settings respond to Fc.
 - */
 - static void test3()
 - {
 -     Animator anim;
 -     anim.setSampleRate(44100);
 -     anim.init();
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.step();
 - 
 -     for (int i = 0; i < 4; ++i) {
 -        // assert(anim.filterFrequency[i] == anim.nominalFilterCenter[i]);
 -         float freq = anim.normalizedFilterFreq[i] * 44100;
 -         assertClose(freq, anim.nominalFilterCenterHz[i], 1);
 -     }
 - 
 -     anim.params[anim.FILTER_FC_PARAM].value = 1;
 -     anim.step();
 - 
 - 
 -     // assert that when we shift up, the expected values shift up
 -     for (int i = 0; i < 4; ++i) {
 -         float freq = anim.normalizedFilterFreq[i] * 44100;
 -         //printf("i=%d, freq=%f, nominal=%f\n", i, freq, anim.nominalFilterCenterHz[i]);
 -         if (i == 3) {
 -             assertClose(freq, anim.nominalFilterCenterHz[i], 1);
 -         } else
 -             assert(freq > anim.nominalFilterCenterHz[i]);
 -     }
 - 
 - #if 0
 -     anim.params[anim.FILTER_FC_PARAM].value = -1;
 -     anim.step();
 -     for (int i = 0; i < 4; ++i) {
 -         if (i == 3)
 -             assert(anim.filterFrequency[i] == anim.nominalFilterCenter[i]);
 -         else
 -             assert(anim.filterFrequency[i] < anim.nominalFilterCenter[i]);
 -     }
 - #endif
 - }
 - 
 - static void testScalers()
 - {
 -     Animator anim;
 -     anim.setSampleRate(44100);
 -     anim.init();
 - 
 -     // cv/knob, trim
 - 
 - 
 -     // cases with no CV
 -     assertClose(.5, anim.scale0_1(0, 0, 1), .001);              // knob half, full trim
 -     assertClose(.5, anim.scale0_1(0, 0, -1), .001);             // knob half, full neg trim
 -     assertClose(1, anim.scale0_1(0, 5, 0), .001);               // knob full
 -     assertClose(0, anim.scale0_1(0, -5, 0), .001);              // knob down full
 -     assertClose(.75, anim.scale0_1(0, (5.0f * .5f), 0), .001); // knob 3/4
 - 
 -     // CV, no knob
 -     assertClose(1, anim.scale0_1(5, 0, 1), .001);              // full cv, untrimmed
 -     assertClose(0, anim.scale0_1(-5, 0, 1), .001);              // full cv, untrimmed
 -     assertClose(.25, anim.scale0_1((-5.0f * .5f), 0, 1), .001);       // 3/4 cv, untrimmed
 - 
 -    // assertClose(.75, anim.scale0_1(5, 0, .5f), .001);           // full cv, half trim
 -     assertClose(0, anim.scale0_1(5, 0, -1), .001);              // full cv, full neg trim
 - 
 - }
 - 
 - 
 - #if 0
 - static void dump(const char * msg, const Animator& anim)
 - {
 -     std::cout << "dumping " << msg << "\nfiltFreq"
 -         << " " << std::pow(2, anim.filterFrequencyLog[0])
 -         << " " << std::pow(2, anim.filterFrequencyLog[1])
 -         << " " << std::pow(2, anim.filterFrequencyLog[2])
 -         << " " << std::pow(2, anim.filterFrequencyLog[3])
 -         << std::endl;
 - }
 - 
 - static void x()
 - {
 -     Animator anim;
 -     anim.setSampleRate(44100);
 -     anim.init();
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.step();
 - 
 -     dump("init", anim);
 - 
 -     // TODO: assert here
 -     anim.params[anim.FILTER_FC_PARAM].value = 5;
 -     anim.step();
 -     dump("fc 5", anim);
 - 
 -     anim.params[anim.FILTER_FC_PARAM].value = -5;
 -     anim.step();
 -     dump("fc -5", anim);
 - 
 -     std::cout << "\nabout to modulate up. maxLFO, def depth\n";
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.params[anim.FILTER_MOD_DEPTH_PARAM].value = 0;
 -     anim.jamModForTest = true;
 -     anim.modValueForTest = 5;
 -     anim.step();
 -     dump("max up def", anim);
 - 
 -     std::cout << "\nabout to modulate up. minLFO, def depth\n";
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.params[anim.FILTER_MOD_DEPTH_PARAM].value = 0;
 -     anim.jamModForTest = true;
 -     anim.modValueForTest = -5;
 -     anim.step();
 -     dump("max down def", anim);
 - 
 -     std::cout << "\nabout to modulate up. maxLFO, max depth\n";
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.params[anim.FILTER_MOD_DEPTH_PARAM].value = 5;
 -     anim.jamModForTest = true;
 -     anim.modValueForTest = 5;
 -     anim.step();
 -     dump(" modulate up. maxLFO, max depthf", anim);
 - 
 - 
 -     std::cout << "\nabout to modulate down. minLFO, max depth\n";
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.params[anim.FILTER_MOD_DEPTH_PARAM].value = 5;
 -     anim.jamModForTest = true;
 -     anim.modValueForTest = -5;
 -     anim.step();
 -     dump(" modulate up. maxLFO, max depthf", anim);
 - 
 - 
 - #if 0
 -     // TODO: would be nice to be able to inject an LFO voltage
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.params[anim.FILTER_MOD_DEPTH_PARAM].value = 5;
 -     for (int i = 0; i < 40000; ++i) {
 -         anim.step();
 -     }
 -     dump("fc 0 depth 1", anim);
 - 
 -     std::cout << "about to to depth -\n";
 -     // TODO: would be nice to be able to inject an LFO voltage
 -     anim.params[anim.FILTER_FC_PARAM].value = 0;
 -     anim.params[anim.FILTER_MOD_DEPTH_PARAM].value = -5;
 -     for (int i = 0; i < 4000; ++i) {
 -         anim.step();
 -     }
 -     dump("fc 0 depth -5", anim);
 - #endif
 - }
 - #endif
 - 
 - /**
 - *Interpolates the frequency using lookups
 - * @param model = 0(bass) 1(tenor) 2(countertenor) 3(alto) 4(soprano)
 - * @param index = 0..4 (formant F1..F5)
 - * @param vowel is the continuous index into the per / vowel lookup tables(0..4)
 - * 0 = a, 1 = e, 2 = i, 3 = o 4 = u
 - */
 - //float getLogFrequency(int model, int index, float vowel)
 - static void testFormantTables()
 - {
 -     FormantTables2 ff;
 -     float x = ff.getLogFrequency(0, 0, 0);
 -     assert(x > 0);
 - 
 -     x = ff.getNormalizedBandwidth(0, 0, 0);
 -     assert(x > 0);
 - 
 -     x = ff.getGain(0, 0, 0);
 - #if 1 // store DB, not gain
 -     assert(x <= 0);
 -     assert(x >= -62);
 - #else
 -     assert(x > 0)
 - #endif
 - 
 -     // spot check a few freq
 -     // formant F2 of alto, 'u' 
 -         x = ff.getLogFrequency(3, 1, 4);
 -     assertClose(x, std::log2(700), .0001);
 -     // formant F3 of soprano, 'o' 
 -     x = ff.getLogFrequency(4, 2, 3);
 -     assertClose(x, std::log2(2830), .0001);
 - }
 - 
 - static void testFormantTables2()
 - {
 -     FormantTables2 ff;
 -     for (int model = 0; model < FormantTables2::numModels; ++model) {
 -         for (int formantBand = 0; formantBand < FormantTables2::numFormantBands; ++formantBand) {
 -             for (int vowel = 0; vowel < FormantTables2::numVowels; ++vowel) {
 -                 const float f = ff.getLogFrequency(model, formantBand, float(vowel));
 - 
 -                 // check that the frequencies are possible formants
 -                 assert(std::pow(2, f) > 100);
 -                 assert(std::pow(2, f) < 5500);
 - 
 -                 const float nBw = ff.getNormalizedBandwidth(model, formantBand, float(vowel));
 -                 assert(nBw < .5);
 -                 assert(nBw > .01);
 - 
 -                 // db now
 -                 const float gain = ff.getGain(model, formantBand, float(vowel));
 -                 assertLE(gain, 0);
 -                 assertGT(gain, -70);
 -                // assertLE(gain, 1);
 -               //  assert(gain > 0);
 -             }
 -         }
 -     }
 - }
 - 
 - 
 - static void testVocalFilter()
 - {
 -     VocalFilter<TestComposite> vf;
 -     vf.setSampleRate(44100);
 -     vf.init();
 - 
 -     vf.outputs[VocalFilter<TestComposite>::AUDIO_OUTPUT].value = 0;
 -     vf.inputs[VocalFilter<TestComposite>::AUDIO_INPUT].value = 1;
 -     vf.step();                // prime it
 -                                 // with  input, should have  output
 -     for (int i = 0; i < 50; ++i) {
 -         vf.step();
 -         assert(vf.outputs[VocalFilter<TestComposite>::AUDIO_OUTPUT].value != 0);
 -     }
 - }
 - 
 - static void testInputExtremes()
 - {
 -     VocalAnimator<TestComposite> va;
 -     va.setSampleRate(44100);
 -     va.init();
 - 
 -     using fp = std::pair<float, float>;
 -     std::vector< std::pair<float, float> > paramLimits;
 - 
 -     paramLimits.resize(va.NUM_PARAMS);
 -     paramLimits[va.LFO_RATE_PARAM] = fp(-5.0f, 5.0f);
 -   //  paramLimits[va.LFO_SPREAD_PARAM] = fp(-5.0f, 5.0f);
 -     paramLimits[va.FILTER_FC_PARAM] = fp(-5.0f, 5.0f);
 -     paramLimits[va.FILTER_Q_PARAM] = fp(-5.0f, 5.0f);
 -     paramLimits[va.FILTER_MOD_DEPTH_PARAM] = fp(-5.0f, 5.0f);
 - 
 - 
 -     paramLimits[va.LFO_RATE_TRIM_PARAM] = fp(-1.0f, 1.0f);
 -     paramLimits[va.FILTER_Q_TRIM_PARAM] = fp(-1.0f, 1.0f);
 -     paramLimits[va.FILTER_FC_TRIM_PARAM] = fp(-1.0f, 1.0f);
 -     paramLimits[va.FILTER_MOD_DEPTH_TRIM_PARAM] = fp(-1.0f, 1.0f);
 - 
 -     paramLimits[va.BASS_EXP_PARAM] = fp(0.f, 1.0f);
 -     paramLimits[va.TRACK_EXP_PARAM] = fp(0.f, 2.0f);
 -     paramLimits[va.LFO_MIX_PARAM] = fp(0.f, 1.0f);
 - 
 -     // TODO: why is output going so high?
 -     ExtremeTester< VocalAnimator<TestComposite>>::test(va, paramLimits, false, "vocal animator");
 - }
 - 
 - 
 - static void testVocalExtremes()
 - {
 - 
 -     VocalFilter<TestComposite> va;
 -     va.setSampleRate(44100);
 -     va.init();
 - 
 -     using fp = std::pair<float, float>;
 -     std::vector< std::pair<float, float> > paramLimits;
 - 
 -     paramLimits.resize(va.NUM_PARAMS);
 - 
 -     paramLimits[va.FILTER_Q_PARAM] = fp(-5.0f, 5.0f);
 -     paramLimits[va.FILTER_Q_TRIM_PARAM] = fp(-1.0f, 1.0f);
 -     paramLimits[va.FILTER_FC_PARAM] = fp(-5.0f, 5.0f);
 - 
 -     paramLimits[va.FILTER_FC_TRIM_PARAM] = fp(-1.0f, 1.0f);
 -     paramLimits[va.FILTER_VOWEL_PARAM] = fp(-5.f, 5.0f);
 -     paramLimits[va.FILTER_VOWEL_TRIM_PARAM] = fp(-1.f, 1.0f);
 -     paramLimits[va.FILTER_MODEL_SELECT_PARAM] = fp(0.f, 4.0f);
 - 
 -     paramLimits[va.FILTER_BRIGHTNESS_PARAM] = fp(-5.f, 5.0f);
 -     paramLimits[va.FILTER_BRIGHTNESS_TRIM_PARAM] = fp(-1.0f, 1.0f);
 - 
 -     ExtremeTester< VocalFilter<TestComposite>>::test(va, paramLimits, false, "vocal filter");
 - 
 - }
 - void testVocalAnimator()
 - {
 -     test0();
 -     test1();
 -     test2();
 -     test3();
 -     testScalers();
 -     testFormantTables();
 -     testFormantTables2();
 - 
 -     testVocalFilter();
 - #if defined(_DEBUG) && true
 -     printf("skipping extremes\n");
 - #else
 -     testVocalExtremes();
 -     testInputExtremes();
 - #endif
 - 
 - }
 
 
  |