Tendency { var <>parX, <>parY, <>parA, <>parB; *new {|parX = 1.0, parY = 0.0, parA = 0.1, parB = 0.1| ^super.newCopyArgs(parX, parY, parA, parB); } at {|time = 0.0, dist = \uniform| ^case {dist == \uniform} {this.uniformAt(time)} {dist == \lpRand} {this.lpRandAt(time)} {dist == \hpRand} {this.hpRandAt(time)} {dist == \meanRand} {this.meanRandAt(time)} {dist == \betaRand} {this.betaRandAt(time)} {dist == \cauchy} {this.cauchyRandAt(time)} {dist == \gauss} {this.gaussRandAt(time)} {dist == \poisson} {this.poissonRandAt(time)} {dist == \expRand} {this.expRandAt(time)} {dist == \exponential} {this.expAt(time)} {dist == \gamma} {this.gammaAt(time)} {dist == \laplace} {this.laplaceAt(time)} {dist == \alaplace} {this.alaplaceAt(time)} {dist == \hcos} {this.hcosAt(time)} {dist == \logistic} {this.logisticAt(time)} {dist == \arcsin} {this.arcsinAt(time)} {true} {this.uniformAt(time)}; } uniformAt {|time| ^this.parXAt(time).rrand(this.parYAt(time)) } parXAt {|time| ^this.valAt(parX.value(time), time); } parYAt {|time| ^this.valAt(parY.value(time), time); } valAt {|obj, time| ^(obj.isKindOf(Env)).if({obj[time]}, { obj.value(time) }) } lpRandAt {|time| ^min(this.at(time), this.at(time)) } hpRandAt {|time| ^max(this.at(time), this.at(time)) } meanRandAt {|time| ^(this.at(time) + this.at(time) * 0.5) } betaRandAt {|time| var sum, rprob1, rprob2, temp, curparY, curparX, i; sum = 2; i = 0; rprob1 = this.valAt(parA, time).reciprocal; rprob2 = this.valAt(parB, time).reciprocal; curparX = this.parXAt(time); curparY = this.parYAt(time); while ({ (sum > 1) && (i < 10) }, { temp = 1.0.rand ** rprob1; sum = temp + (1.0.rand ** rprob2); i = i + 1; }); ^((temp / sum) * (curparX - curparY) + curparY) } // parX = mean, parY = spread // cauchyRandAt {|time| // var tmp; // while ({ // tmp = 1.0.rand; // tmp == 0.5; // }); // ^(this.parYAt(time) * tan(tmp * pi)) + this.parXAt(time); // } // cauchy // parX = spread, parA=1 => positive half only cauchyRandAt {|time| var u; u = 1.0.rand; (this.parA == 1).if{ u = u * 0.5 }; u = pi * u; ^( this.parXAt(time) * tan(u) + this.parYAt(time) ); } // parX = mean, parY = dev // gaussRandAt {|time| // ^(((-2 * log(1.0.rand)).sqrt * sin(2pi.rand)) * this.parYAt(time)) + this.parXAt(time); // } // parX = dev gaussRandAt {|time| var a, b; a = 1.0.rand; b = 1.0.rand; ^((-2 * log(1 - a)).sqrt * cos(2pi * b) * this.parXAt(time) + this.parYAt(time)); } // parX = mean poissonRandAt {|time| var count = -1, ranVal, tmp; ranVal = 1.0.rand; tmp = exp(this.parXAt(time).neg); while({ count = count + 1; ranVal = ranVal * 1.0.rand; ranVal > tmp; }); ^count; } // don't cross 0! don't do it! expRandAt {|time| ^exprand(this.parYAt(time), this.parXAt(time)); } // exponential with parX = density expAt {|time| var xs, us; xs = log(1.0.rand).neg; ^((xs/this.parXAt(time)) + this.parYAt(time)) } // gamma distribution, parX = mean gammaAt { |time| var sum; sum = 1.0; for(1, this.parXAt(time), { sum = sum * (1 - 1.0.rand) }); ^(log(sum).neg + this.parYAt(time)); } // laplace // parX = dispersion or spread laplaceAt { |time| var u, val; u = 1.0.rand * 2.0; (u > 1.0).if({ u = 2.0 - u; val = this.parXAt(time).neg * log(u); },{ val = this.parXAt(time) * log(u) ; }); ^(val + this.parYAt(time)) } // alaplace // special case of laplace (returns exp(u) instead of log(u) // parX = dispersion or spread alaplaceAt { |time| var u, val; u = 1.0.rand * 2.0; (u > 1.0).if({ u = 2.0 - u; val = this.parXAt(time).neg * exp(u); },{ val = this.parXAt(time) * exp(u) ; }); ^(val + this.parYAt(time)) } // hcos // hyperbolic cosine distribution hcosAt { |time| var u, val; u = 1.0.rand; val = log(tan(0.5pi * u)); ^(this.parXAt(time) * val + this.parYAt(time)) } // logistic // logistic distribution // parX = dispersion (beta) // we keep alpha as 1 for simplicity logisticAt { |time| var u, val; u = 1.0.rand; val = log(u.reciprocal - 1); ^(this.parXAt(time).neg * val + this.parYAt(time)) } // arcsin // arcsin distribution arcsinAt { |time| var u, val; u = 1.0.rand; val = (1 - sin(pi * (u - 0.5))) * 0.5; ^(this.parXAt(time) * val + this.parYAt(time)) } // may be broken embedInStream {| inval, dist | var startTime, thisVal, thisTime; startTime = thisThread.beats; loop { thisTime = thisThread.beats - startTime; inval = this.at(thisTime, dist, parA, parB); inval.yield; } ^inval; } asStream { |dist| ^Routine({ arg inval; this.embedInStream(inval, dist, parA, parB) }); } }