| 
							- 
 - #include "GenerativeTriggerGenerator.h"
 - #include "StochasticGrammar.h"
 - #include "TriggerSequencer.h"
 - 
 - #include <string>
 - #include <vector>
 - #include <set>
 - //#include <random>
 - 
 - static const int numRules = fullRuleTableSize;
 - 
 - typedef GKEY(*INITFN)();
 - static ProductionRule rules[numRules];
 - 
 - 
 - 
 - // Test basic integrity of key data
 - static void test0()
 - {
 -     GKEY key;
 -     GKEY outKeys[ProductionRuleKeys::bufferSize];
 -     for (key = sg_first; key <= sg_last; ++key) {
 -         ProductionRuleKeys::breakDown(key, outKeys);
 -         for (GKEY* p = outKeys; *p != sg_invalid; ++p) {
 -             assert(*p >= sg_first);
 -             assert(*p <= sg_last);
 -         }
 - 
 -         std::string s = ProductionRuleKeys::toString(key);
 -         assert(!s.empty());
 -         assert(s.length() < 256);
 - 
 -         int dur = ProductionRuleKeys::getDuration(key);
 -         assert(dur > 0);
 -         assert(dur <= PPQ * 8);
 - 
 -     }
 - }
 - 
 - // test all the gkeys
 - void testAllKeys()
 - {
 -     const int siz = ProductionRuleKeys::bufferSize;
 -     GKEY buffer[siz];
 - 
 -     for (GKEY gk = sg_first; gk <= sg_last; ++gk) {
 -        // printf("testing key %d\n", gk);
 -        // printf("to string: %s\n", ProductionRuleKeys::toString(gk));
 -         const int dur = ProductionRuleKeys::getDuration(gk);
 -         ProductionRuleKeys::breakDown(gk, buffer);
 -         int sum = 0;
 -         for (GKEY * p = buffer; *p != sg_invalid; ++p) {
 -            // printf("adding to sum %d\n", ProductionRuleKeys::getDuration(*p));
 -             sum += ProductionRuleKeys::getDuration(*p);
 - 
 -         }
 -        // printf("dur = %d sum = %d (should be the same)\n", dur, sum);
 -         assert(dur == sum);
 -     }
 - }
 - 
 - 
 - 
 - /**************************************************************************************
 -  * Make some simple grammars and test them
 -  **************************************************************************************/
 - 
 - #ifdef _DEBUG
 - void gdt0()
 - {
 -     {
 -         static ProductionRule rules[numRules];
 -         bool b = ProductionRule::isGrammarValid(rules, numRules, sg_invalid);
 -         assert(!b);
 -     }
 -     {
 -         // throw in a positive case
 -         static ProductionRule rules[numRules];
 -         ProductionRule& r = rules[sg_w];
 -         r.entries[0].probability = 1.0f;
 -         r.entries[0].code = sg_invalid;
 - 
 -         bool b = ProductionRule::isGrammarValid(rules, numRules, sg_w);
 -         assert(b);
 -     }
 -     {
 -         // terminal code wrong
 -         static ProductionRule rules[numRules];
 -         ProductionRule& r = rules[sg_w];
 -         r.entries[0].probability = 1.0f;
 -         r.entries[0].code = sg_q;
 - 
 -         bool b = ProductionRule::isGrammarValid(rules, numRules, sg_w);
 -         assert(!b);
 -     }
 -     {
 -         // bad order of probability
 -         static ProductionRule rules[numRules];
 -         ProductionRule& r = rules[sg_w];
 -         r.entries[0].probability = 1.0f;
 -         r.entries[0].code = sg_q;
 - 
 -         bool b = ProductionRule::isGrammarValid(rules, numRules, sg_w);
 -         assert(!b);
 -     }
 -     {
 -         // rule branches to nowhere
 -         static ProductionRule rules[numRules];
 - 
 -         // break w2 into w,w prob 100
 -         ProductionRule& r = rules[sg_w2];
 -         r.entries[0].probability = 1.0f;
 -         r.entries[0].code = sg_ww;
 -         bool b = ProductionRule::isGrammarValid(rules, numRules, sg_w);
 -         assert(!b);
 -     }
 - }
 - #endif
 - 
 - 
 - class TestEvaluator : public ProductionRule::EvaluationState
 - {
 - public:
 -     TestEvaluator(AudioMath::RandomUniformFunc xr) : ProductionRule::EvaluationState(xr)
 -     {
 -     }
 - 
 -     void writeSymbol(GKEY key) override
 -     {
 -         keys.push_back(key);
 -     }
 - 
 -     int getNumSymbols()
 -     {
 -         //printf("final keys: ");
 -        // for (size_t i = 0; i< keys.size(); ++i) printf("%s, ", ProductionRuleKeys::toString(keys[i]));
 -        // printf("\n");
 -         return (int) keys.size();
 -     }
 - private:
 -     std::vector<GKEY> keys;
 - };
 - 
 - 
 - /**
 -  * simplest possible grammar.
 -  */
 - static GKEY init0()
 - {
 -    // printf("called init0\n");
 -     // This rule always generate sg-w2 (two whole notes tied together)
 -     ProductionRule& r = rules[sg_w2];
 - 
 -     r.entries[0].probability = 1;
 -     r.entries[0].code = sg_invalid;		// terminate expansion		
 - 
 - 
 -     return sg_w2;
 - }
 - 
 - /**
 -  * Simple grammar with a rule but no random.
 -  */
 - static GKEY init1()
 - {
 - 
 -     {
 -         // start with w2 duration
 -         ProductionRule& r = rules[sg_w2];
 - 
 -         // break into w,w prob 100
 -         r.entries[0].probability = 1.0f;
 -         r.entries[0].code = sg_ww;
 -     }
 - 
 -     {
 -         // now need rule for w hole
 -         //printf("in init1 making 100 for %d\n", sg_w);
 -         ProductionRule& r = rules[sg_w];
 -         r.entries[0].probability = 1.0f;
 -         r.entries[1].code = sg_invalid;
 -     }
 -     //printf("leave init 1. rule 1 p0 = %f\n", rules[sg_w2].entries[0].probability);
 -     return sg_w2;
 - }
 - 
 - 
 - /**
 -  * Simple grammar with randomness initializer
 -  */
 - static GKEY init2()
 - {
 -     {
 -         // start with w2 duration
 -         ProductionRule& r = rules[sg_w2];
 - 
 -         // break into w,w prob 50
 - 
 -         r.entries[0].probability = .5f;
 -         r.entries[0].code = sg_ww;
 -         r.entries[1].probability = 1.0f;
 -         r.entries[1].code = sg_invalid;		// always terminate
 -     }
 - 
 -     {
 -         // now need rule for w hole
 -         ProductionRule& r = rules[sg_w];
 -         r.entries[1].probability = 1.0f;
 -         r.entries[1].code = sg_invalid;		// always terminate
 -     }
 - 
 -     return sg_w2;
 - }
 - 
 - #ifdef _DEBUG
 - static void testGrammarSub(INITFN f)
 - {
 -     GKEY init = f();
 - 
 - 
 -     bool b = ProductionRule::isGrammarValid(rules, numRules, init);
 -     assert(b);
 - 
 -     TestEvaluator es(AudioMath::random());
 -     es.rules = rules;
 -     es.numRules = numRules;
 -     ProductionRule::evaluate(es, init);
 - 
 -     assert(es.getNumSymbols() > 0);
 - }
 - #endif
 - 
 - 
 - /*********************************************************************************************************
 -  * TriggerSequencer
 -  **********************************************************************************************************/
 - 
 -  // test event at zero fires at zero
 - static void ts0()
 - {
 -     TriggerSequencer::Event seq[] =
 -     {
 -         {TriggerSequencer::TRIGGER, 0},
 -     {TriggerSequencer::END, 100}
 -     };
 -     TriggerSequencer ts(seq);
 - 
 -     ts.clock();
 -     assert(ts.getTrigger());
 - 
 -     ts.clock();
 -     assert(!ts.getTrigger());
 - 
 - }
 - 
 - // test trigger at 1 happens at 1
 - static void ts1()
 - {
 -     TriggerSequencer::Event seq[] =
 -     {
 -         {TriggerSequencer::TRIGGER, 1},
 -     {TriggerSequencer::END, 0}
 -     };
 -     TriggerSequencer ts(seq);
 - 
 -     ts.clock();
 -     assert(!ts.getTrigger());
 - 
 -     ts.clock();
 -     assert(ts.getTrigger());
 - 
 -     ts.clock();
 -     assert(!ts.getTrigger());
 - 
 -     ts.clock();
 -     assert(!ts.getTrigger());
 - }
 - 
 - 
 - // 4 clock loop: delay 4, trigger, end
 - static void ts2()
 - {
 -     TriggerSequencer::Event seq[] =
 -     {
 -         {TriggerSequencer::TRIGGER, 4},
 -     {TriggerSequencer::END, 0}
 -     };
 -     TriggerSequencer ts(seq);
 - 
 -     bool firstTime = true;
 -     // first time through, 4 clocks of nothing. then clock, 0,0,0
 -     for (int i = 0; i < 4; ++i) {
 -         ts.clock();
 -         if (firstTime) {
 -             assert(!ts.getTrigger()); assert(!ts.getEnd());
 -             firstTime = false;
 -         } else {
 -             //printf("second time around, t=%d e=%d\n", ts.getTrigger(), ts.getEnd());
 - 
 -             // second time around we finally see the trigger
 - 
 -             assert(ts.getTrigger());
 - 
 -             // second time around, need to clock the end of the last time
 -             assert(ts.getEnd());
 -             ts.reset(seq);				// start it up again
 -             assert(!ts.getTrigger());	// resetting should not set us up for a trigger
 -         }
 -         ts.clock(); assert(!ts.getTrigger()); assert(!ts.getEnd());
 -         ts.clock(); assert(!ts.getTrigger()); assert(!ts.getEnd());
 - 
 -         ts.clock(); assert(!ts.getTrigger());
 -         //	assert(ts.getEnd());
 - 
 -         //	ts.reset(seq);
 -     }
 - }
 - 
 - // test trigger seq qith
 - // 4 clock loop: trigger, delay 4 end
 - static void ts3()
 - {
 -     TriggerSequencer::Event seq[] =
 -     {
 -         {TriggerSequencer::TRIGGER, 0},
 -     {TriggerSequencer::END, 4}
 -     };
 -     TriggerSequencer ts(seq);
 - 
 - 
 -     bool firstLoop = true;
 -     for (int i = 0; i < 4; ++i) {
 -         //printf("--- loop ----\n");
 - 
 -         // 1
 - 
 -         ts.clock();
 -         if (firstLoop) {
 -             assert(ts.getTrigger());
 -             // we just primed loop at top, so it's got a ways
 -             assert(!ts.getEnd());
 -             firstLoop = false;
 -         } else {
 -             // second time around, need to clock the end of the last time
 -             assert(ts.getEnd());
 -             ts.reset(seq);				// start it up again
 -             assert(ts.getTrigger());	// resetting should have set us up for a trigger
 -         }
 -         // 2
 -         ts.clock(); assert(!ts.getTrigger()); assert(!ts.getEnd());
 -         // 3
 -         ts.clock(); assert(!ts.getTrigger()); assert(!ts.getEnd());
 -         // 4
 -         ts.clock();
 -         assert(!ts.getTrigger());
 -         assert(!ts.getEnd());
 -     }
 - }
 - 
 - // test trigger seq with straight ahead 4/4 as generated by a grammar
 - static void ts4()
 - {
 -     TriggerSequencer::Event seq[] =
 -     {
 -         {TriggerSequencer::TRIGGER, 0},
 -     {TriggerSequencer::TRIGGER, 4},
 -     {TriggerSequencer::TRIGGER, 4},
 -     {TriggerSequencer::TRIGGER, 4},
 -     {TriggerSequencer::END, 4}
 -     };
 -     TriggerSequencer ts(seq);
 - 
 - 
 -     //bool firstLoop = true;
 -     for (int i = 0; i < 100; ++i) {
 -         bool firstTime = (i == 0);
 -         // repeating pattern of trigg, no, no, no
 -         for (int j = 0; j < 4; ++j) {
 -             for (int k = 0; k < 4; ++k) {
 -                 //	printf("test loop, i=%d, j=%d, k=%d\n", i, j, k);
 -                 ts.clock();
 - 
 -                 bool expectEnd = (k == 0) && (j == 0) && !firstTime;
 -                 assert(ts.getEnd() == expectEnd);
 -                 if (ts.getEnd()) {
 -                     ts.reset(seq);
 -                 }
 -                 assert(ts.getTrigger() == (k == 0));
 -             }
 -         }
 -     }
 - }
 - 
 - /*******************************************************************************
 -  ** StochasticGrammarDictionary
 -  */
 - 
 - #ifdef _DEBUG
 - void gdt1()
 - {
 -     assert(StochasticGrammarDictionary::getNumGrammars() > 0);
 -     for (int i = 0; i < StochasticGrammarDictionary::getNumGrammars(); ++i) {
 -         StochasticGrammarDictionary::Grammar g = StochasticGrammarDictionary::getGrammar(i);
 -         bool b = ProductionRule::isGrammarValid(g.rules, g.numRules, g.firstRule);
 -         assert(b);
 -     }
 - }
 - #endif
 - 
 - /********************************************************************************************
 - * GenerativeTriggerGenerator
 - **********************************************************************************************/
 - 
 - // test that we get some clocks and some not
 - static void gtg0()
 - {
 -     GKEY key = init1();
 -     GenerativeTriggerGenerator gtg(AudioMath::random(), rules, numRules, key);
 -     bool yes = false;
 -     bool no = false;
 -     for (int i = 0; i < 100000; ++i) {
 -         if (gtg.clock())
 -             yes = true;
 -         else
 -             no = true;
 - 
 -         if (yes && no) {
 -             //printf("clocked at %d\n", i);
 -             return;
 -         }
 -     }
 -     assert(false);
 - 
 - }
 - 
 - 
 - // test that we get everything in even quarter notes
 - static void gtg1()
 - {
 -     GKEY key = init1();
 -     std::set<int> counts;
 - 
 -     GenerativeTriggerGenerator gtg(AudioMath::random(), rules, numRules, key);
 - 
 -     int ct = 0;
 -     for (int i = 0; i < 10000; ++i) {
 -         bool b = gtg.clock();
 -         if (b) {
 -             //printf("clocked at %d\n", ct);
 -             counts.insert(ct);
 -             ct = 0;
 -         }
 -         ct++;
 -     }
 -     //counts.insert(50);
 -     assert(!counts.empty());
 -     for (std::set<int>::iterator it = counts.begin(); it != counts.end(); ++it) {
 -         int c = *it;
 - 
 -         if ((c % PPQ) != 0) {
 -             //printf("PPQ=%d, c modePPQ =%d\n", PPQ, (c % PPQ));
 -             //printf("2ppq = %d, 4ppq=%d\n", 2 * PPQ, 4 * PPQ);
 -             assert(false);
 -         }
 -     }
 - }
 - 
 - 
 - 
 - 
 - 
 - 
 - void testStochasticGrammar()
 - {
 -     test0();
 -     testAllKeys();
 - 
 - #ifdef _DEBUG
 -     gdt0();
 -     testGrammarSub(init0);
 -     testGrammarSub(init1);
 -     testGrammarSub(init2);
 - #endif
 -     ts0();
 -     ts1();
 -     ts2();
 -     ts3();
 -     ts4();
 - 
 - #ifdef _DEBUG
 -     gdt1();
 - #endif
 - 
 -     gtg0();
 -     gtg1();
 - 
 - }
 
 
  |