#ifndef ROTOR_MATHS #define ROTOR_MATHS #include "rotor.h" namespace Rotor { #define COMPARISON_Equal 1 #define COMPARISON_Not_equal 2 #define COMPARISON_Greater 3 #define COMPARISON_Less 4 #define COMPARISON_Greater_or_equal 5 #define COMPARISON_Less_or_equal 6 class Comparison: public Signal_node { public: Comparison(){}; Comparison(map &settings) { base_settings(settings); value=find_setting(settings,"value",0.0f); string _op=find_setting(settings,"operator","=="); if (_op=="==") op=COMPARISON_Equal; if (_op=="!=") op=COMPARISON_Not_equal; if (_op==">") op=COMPARISON_Greater; if (_op=="<") op=COMPARISON_Less; if (_op==">=") op=COMPARISON_Greater_or_equal; if (_op=="<=") op=COMPARISON_Less_or_equal; } void link_params() { for (auto p:parameter_inputs){ if (p->parameter=="value") p->receiver=&value; } }; Comparison* clone(map &_settings) { return new Comparison(_settings);}; const float output(const Time_spec &time) { if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml if (inputs[0]->connection) { float in= (((Signal_node*)inputs[0]->connection)->get_output(time)); switch (op) { case COMPARISON_Equal: return fequal(value,in)?1.0f:0.0f; break; case COMPARISON_Not_equal: return fequal(value,in)?0.0f:1.0f; break; case COMPARISON_Greater: return fgreater(value,in)?1.0f:0.0f; break; case COMPARISON_Less: return fless(value,in)?1.0f:0.0f; break; case COMPARISON_Greater_or_equal: return fgreater_or_equal(value,in)?1.0f:0.0f; break; case COMPARISON_Less_or_equal: return fless_or_equal(value,in)?1.0f:0.0f; break; } } } return 0.0f; } int op; float value; }; #define ARITHMETIC_plus 1 #define ARITHMETIC_minus 2 #define ARITHMETIC_multiply 3 #define ARITHMETIC_divide 4 #define ARITHMETIC_modulo 5 #define ARITHMETIC_pow 6 #define ARITHMETIC_sin 7 #define ARITHMETIC_cos 8 #define ARITHMETIC_ease 9 #define ARITHMETIC_jolt 10 class Arithmetic: public Signal_node { public: Arithmetic(){}; Arithmetic(map &settings) { base_settings(settings); value=find_setting(settings,"value",0.0f); string _op=find_setting(settings,"operator","+"); if (_op=="+"||_op=="plus"||_op=="add") op=ARITHMETIC_plus; if (_op=="-"||_op=="minus"||_op=="subtract") op=ARITHMETIC_minus; if (_op=="*"||_op=="x"||_op=="multiply") op=ARITHMETIC_multiply; if (_op=="/"||_op=="divide") op=ARITHMETIC_divide; if (_op=="%"||_op=="mod"||_op=="modulo"||_op=="modulus") op=ARITHMETIC_modulo; if (_op=="^"||_op=="power") op=ARITHMETIC_pow; if (_op=="sin"||_op=="sine") op=ARITHMETIC_sin; if (_op=="cos"||_op=="cos") op=ARITHMETIC_cos; if (_op=="ease") op=ARITHMETIC_ease; if (_op=="jolt") op=ARITHMETIC_jolt; } void link_params() { for (auto p:parameter_inputs){ p->receiver=nullptr; if (p->parameter=="value") p->receiver=&value; } }; Arithmetic* clone(map &_settings) { return new Arithmetic(_settings);}; const float output(const Time_spec &time) { if (op==ARITHMETIC_divide||op==ARITHMETIC_modulo){ if (value==0.0f) { Logger& logger = Logger::get("Rotor"); logger.error("Arithmetic node: caught division by zero, frame "+time.frame()); return 0.0f; } } if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml if (inputs[0]->connection) { float in= (((Signal_node*)inputs[0]->connection)->get_output(time)); switch (op) { case ARITHMETIC_plus: return in+value; break; case ARITHMETIC_minus: return in-value; break; case ARITHMETIC_multiply: return in*value; break; case ARITHMETIC_divide: return in/value; break; case ARITHMETIC_modulo: return fmod(in,value); break; case ARITHMETIC_pow: return pow(in,value); break; case ARITHMETIC_sin: return sin(in)*value; break; case ARITHMETIC_cos: return cos(in)*value; break; case ARITHMETIC_ease: return ((1.0-value)*in)+(value*(0.5f+((cos((fmod(in,1.0f)+1.0f)*M_PI))*0.5f))); break; case ARITHMETIC_jolt: return ((1.0-value)*in)+(value*(0.5f+((sin((fmod(in,1.0f)+1.0f)*M_PI))*0.5f))); break; } } } return 0.0f; } int op; float value; }; class Signal_divide: public Signal_node { public: Signal_divide(){}; Signal_divide(map &settings) { base_settings(settings); divide_amount=ofToFloat(find_setting(settings,"amount")); for (auto p:parameter_inputs){ if (p->parameter=="amount") p->receiver=÷_amount; } }; Signal_divide* clone(map &_settings) { return new Signal_divide(_settings);}; const float output(const Time_spec &time) { if (inputs.size()) { //there should there be a way to specify number of inputs in the code rather than in xml if (inputs[0]->connection) { return (((Signal_node*)inputs[0]->connection)->get_output(time))/divide_amount; } } return 0.0f; } float divide_amount; }; class Is_new_integer: public Signal_node { public: Is_new_integer(){}; Is_new_integer(map &settings) { base_settings(settings); }; Is_new_integer* clone(map &_settings) { return new Is_new_integer(_settings);}; const float output(const Time_spec &time) { if (inputs[0]->connection) { float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time)); float s2=(((Signal_node*)(inputs[0]->connection))->get_output(time.lastframe())); if (((int)s1)>((int)s2)) { return 1.0f; } } return 0.0f; } }; class On_off: public Signal_node { public: On_off(){}; On_off(map &settings) { base_settings(settings); }; On_off* clone(map &_settings) { return new On_off(_settings);}; const float output(const Time_spec &time) { if (inputs[0]->connection) { float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time)); if ((int)s1%2) return 1.0f; } return 0.0f; } }; //pseudo random repeatable hash function //http://create.stephan-brumme.com/fnv-hash/ const uint32_t Prime = 0x01000193; // 16777619 const uint32_t Seed = 0x811C9DC5; // 2166136261 /// hash a byte inline uint32_t fnv1a(unsigned char oneByte, uint32_t hash = Seed) { return (oneByte ^ hash) * Prime; } /// hash a short (two bytes) inline uint32_t fnv1a(unsigned short twoBytes, uint32_t hash = Seed) { const unsigned char* ptr = (const unsigned char*) &twoBytes; hash = fnv1a(*ptr++, hash); return fnv1a(*ptr , hash); } /// hash a 32 bit integer (four bytes) inline uint32_t fnv1a(uint32_t fourBytes, uint32_t hash = Seed) { const unsigned char* ptr = (const unsigned char*) &fourBytes; hash = fnv1a(*ptr++, hash); hash = fnv1a(*ptr++, hash); hash = fnv1a(*ptr++, hash); return fnv1a(*ptr , hash); } class Random: public Signal_node { public: Random(){}; Random(map &settings) { base_settings(settings); seed=(Seed+find_setting(settings,"seed",0)); cerr<<"random:: seed "< &_settings) { return new Random(_settings);}; const float output(const Time_spec &time) { if (inputs.size()) { if (inputs[0]->connection) { //hash the integer part and add the fractional part back on float o=(((Signal_node*)inputs[0]->connection)->get_output(time)); uint32_t m=(int)o; return ((float)(fnv1a(m,seed)%((uint32_t)time.duration)))+(o-m); } } return 0.0f; } uint32_t seed; private: }; } #endif