/* Math functions for Csound coded by Paris Smaragdis 1994 */ /* Berklee College of Music Csound development team */ /* Changes 6 July 1998 - Robin Whittle http://www.firstpr.com.au * * 31 bit Park Miller "Minimal Standard" Pseudo Random Number Generator * now used for all these noise sources, with a seed setting function and a * raw 31 bit function available for other Csound functions too. * * This removes the dependency on the library function rand() which could * be as simple as a 16 bit PRNG, which would be lousy for audio purposes. * * Changes made to seedrand(). * A new function randint31() is created. * Macro "unirand()" is now defined in terms of randint31() instead of * the library call rand(). * New functions for bipolar uniform noise -1 to +1. Three new lines * for this xbunirand family need to be added to entry.c, as well as * declaring the new function names: */ #include "cs.h" #include "cmath.h" #include #include /* for random seeding from the time - mkc July 1997 */ #ifndef RAND_MAX #define RAND_MAX (32767) #endif void ipow(POW *p) /* Power for i-rate */ { *p->sr = (float)pow(*p->in, *p->pow); /* sophisticated code! */ } void apow(POW *p) /* Power routine for a-rate */ { long n = ksmps; float *in = p->in, *out = p->sr; do { *out++ = (float)pow(*in++, *p->pow) / *p->norm; } while (--n); } void kpow(POW *p) /* Power routine for k-rate */ { *p->sr = (float)pow(*p->in, *p->pow) / *p->norm; } /*========================================================================= * * seedrand() and the PRNG seed. * * Driven by opcode "seed". Takes a float input parm and seeds the * 31 bit state of the PRNG as follows: * * Input = 0 Use time of day to generate seed. * * Input != 0 Make it positive, multiply by 1,000, mod it by * (2^31 - 1) turn it into an integer using floor, * so it can never be 2^31, make it 1 if the result * was 0, and use this as the seed. * The PRNG will put out 0s if its state is 0! * * The seed is a 32 bit integer. Initialise it with an * auspicious number - pi to the 17th power. * * The seed opcode uses the same data structure PRAND as the generators * - its sole parameter, an input, is in the first position, which is * called "out". */ #define CS_RANDINT_MAX 2147483647L /* 2**31 - 1 = 0x7FFFFFFF */ /* Add one in case y2k voodoo causes time() * to return 0. */ static long seed31 = 282844563L; void seedrand(PRAND *p) { /* Make sure that the time of day function is returning * non-zero. */ if ( (*p->out == 0) && (time(NULL) != 0) ) { printf("0 -> Setting ramdom seed from current time and date. "); /* Since the time changes rather slowly, and the * first generated randint31() result depends * on it and therefore changes rather slowly * call randint31() twice the mash the seed * well before an opcode can use it. */ seed31 = (long) time(NULL); seed31 = randint31(); seed31 = randint31(); } else { seed31 = (long) floor( fmod( (double)(1000 * fabs(*p->out)), (double)2147483647 ) ); printf("Seeding with %.3f ", *p->out); } if (seed31 == 0) seed31 = 1; printf("Seed = %10lu \n", seed31) ; } /*========================================================================= * * randint31() * * 31 bit Park Miller PRNG using Linus Schrage's method for doing it all * with 32 bit variables. * * Code adapted from Ray Garder's public domain code of July 1997 at: * http://www.snippets.org/RG_RAND.C Thanks! * * Based on "Random Number Generators: Good Ones Are Hard to Find", * S.K. Park and K.W. Miller, Communications of the ACM 31:10 (Oct 1988), * and "Two Fast Implementations of the 'Minimal Standard' Random * Number Generator", David G. Carta, Comm. ACM 33, 1 (Jan 1990), p. 87-88 * * Linear congruential generator: f(z) = (16807 * z) mod (2 ** 31 - 1) * * Uses L. Schrage's method to avoid overflow problems. */ #define ria 16807 /* multiplier */ #define rim 2147483647L /* 2**31 - 1 */ #define riq 127773L /* m div a */ #define rir 2836 /* m mod a */ long randint31() { unsigned long rilo, rihi; rilo = ria * (long)(seed31 & 0xFFFF); rihi = ria * (long)((unsigned long)seed31 >> 16); rilo += (rihi & 0x7FFF) << 16; if (rilo > rim) { rilo &= rim; ++rilo; } rilo += rihi >> 15; if (rilo > rim) { rilo &= rim; ++rilo; } return ( seed31 = (long)rilo ); } /*========================================================================= * * unirand() macro to call the above PRNG function. */ #define unirand() (float)((double)randint31()/(double)CS_RANDINT_MAX) /*========================================================================= * * Funcions for xbunirand opcodes in entry.c. * Based on auinform() and ikuniform() below. * unirand was 0 to +1. bunirand is -1 to +1 */ void abuniform(PRAND *p) /* Uniform bipolar distribution */ { long n = ksmps; float *out = p->out; float arg1 = *p->arg1; do *out++ = arg1 * (unifrand(2) - 1); while( --n); } void ikbuniform(PRAND *p) { float *out = p->out; *out = *p->arg1 * (unifrand(2) - 1); } /* Back to Paris' code. - - - - - - - - - - - - - - - - - - - - - - - - - - */ void auniform(PRAND *p) /* Uniform distribution */ { long n = ksmps; float *out = p->out; float arg1 = *p->arg1; do *out++ = unifrand(arg1); while( --n); } void ikuniform(PRAND *p) { float *out = p->out; *out = unifrand(*p->arg1); } void alinear(PRAND *p) /* Linear random functions */ { long n = ksmps; float *out = p->out; do { *out++ = linrand(*p->arg1); } while (--n); } void iklinear(PRAND *p) { float *out = p->out; *out++ = linrand(*p->arg1); } void atrian(PRAND *p) /* Triangle random functions */ { long n = ksmps; float *out = p->out; do { *out++ = trirand(*p->arg1); } while (--n); } void iktrian(PRAND *p) { float *out = p->out; *out++ = trirand(*p->arg1); } void aexp(PRAND *p) /* Exponential random functions */ { long n = ksmps; float *out = p->out; do { *out++ = exprand(*p->arg1); } while (--n); } void ikexp(PRAND *p) { float *out = p->out; *out++ = exprand(*p->arg1); } void abiexp(PRAND *p) /* Bilateral exponential rand. functions */ { long n = ksmps; float *out = p->out; do { *out++ = biexprand(*p->arg1); } while (--n); } void ikbiexp(PRAND *p) { float *out = p->out; *out++ = biexprand(*p->arg1); } void agaus(PRAND *p) /* Gaussian random functions */ { long n = ksmps; float *out = p->out; do { *out++ = gaussrand(*p->arg1); } while (--n); } void ikgaus(PRAND *p) { float *out = p->out; *out++ = gaussrand(*p->arg1); } void acauchy(PRAND *p) /* Cauchy random functions */ { long n = ksmps; float *out = p->out; do { *out++ = cauchrand(*p->arg1); } while (--n); } void ikcauchy(PRAND *p) { float *out = p->out; *out++ = cauchrand(*p->arg1); } void apcauchy(PRAND *p) /* Positive Cauchy random functions */ { long n = ksmps; float *out = p->out; do { *out++ = pcauchrand(*p->arg1); } while (--n); } void ikpcauchy(PRAND *p) { float *out = p->out; *out++ = pcauchrand(*p->arg1); } void abeta(PRAND *p) /* Beta random functions */ { long n = ksmps; float *out = p->out; do { *out++ = betarand(*p->arg1, *p->arg2, *p->arg3); } while (--n); } void ikbeta(PRAND *p) { float *out = p->out; *out++ = betarand(*p->arg1, *p->arg2, *p->arg3); } void aweib(PRAND *p) /* Weibull randon functions */ { long n = ksmps; float *out = p->out; do { *out++ = weibrand(*p->arg1, *p->arg2); } while (--n); } void ikweib(PRAND *p) { float *out = p->out; *out++ = weibrand(*p->arg1, *p->arg2); } void apoiss(PRAND *p) /* Poisson random funcions */ { long n = ksmps; float *out = p->out; do { *out++ = poissrand(*p->arg1); } while (--n); } void ikpoiss(PRAND *p) { float *out = p->out; *out++ = poissrand(*p->arg1); } /* * * * * * RANDOM NUMBER GENERATORS * * * * * */ /* This was the old macro which called the library function rand(). * * #define unirand() (float)((double)rand()/(double)RAND_MAX) * * See above for the new unirand() macro. */ float unifrand(float range) { return range*unirand(); } float linrand(float range) /* linear distribution routine */ { float r1, r2; r1 = unirand(); r2 = unirand(); if (r1 > r2) r1 = r2; return (r1 * range); } float trirand(float range) /* triangle distribution routine */ { float r1, r2; r1 = unirand(); r2 = unirand(); return (((r1 + r2) - 1.0f) * range); } float exprand(float l) /* exponential distribution routine */ { float r1; if (l < 0.0f) return (0.0f); do { r1 = unirand(); } while (r1 == 0.0f); return (-(float)log(r1 *l)); } float biexprand(float l) /* bilateral exponential distribution routine */ { float r1; if (l < 0.0f) return (0.0f); do { r1 = 2.0f * unirand(); } while (r1 == 0.0f || r1 == 2.0f); if (r1 > 1.0f) { r1 = 2.0f - r1; return (-(float)log(r1 * l)); } return ((float)log(r1 * l)); } float gaussrand(float s) /* gaussian distribution routine */ { float r1 = 0.0f; int n = 12; s /= 3.83f; do { r1 += unirand(); } while (--n); return (s * (r1 - 6.0f)); } float cauchrand(float a) /* cauchy distribution routine */ { float r1; a /= 318.3f; do { do { r1 = unirand(); } while (r1 == 0.5f); r1 = a * (float)tan(pi*(double)r1); } while (r1>1.0f || r1<-1.0f); /* Limit range artificially */ return r1; } float pcauchrand(float a) /* positive cauchy distribution routine */ { float r1; a /= 318.3f; do { do { r1 = unirand(); } while (r1 == 1); r1 = a * (float)tan( pi * 0.5 * r1); } while (r1>1.0f); return r1; } float betarand(float range, float a, float b) /* beta distribution routine */ { float r1, r2; if (a < 0.0f || b < 0.0f ) return (0.0f); do { do { r1 = unirand(); } while (r1 == 0.0f); do { r2 = unirand(); } while (r2 == 0.0f); r1 = (float)pow(r1, 1.0 / (double)a); r2 = (float)pow(r2, 1.0 / (double)b); } while ((r1 + r2) > 1.0f); return ((r1 / (r1 +r2)) * range); } float weibrand(float s, float t) /* weibull distribution routine */ { float r1, r2; if (t < 0.0f ) return (0.0f); do { r1 = unirand(); } while (r1 == 0.0f || r1 == 1.0f); r2 = 1.0f / (1.0f - r1); return (s * (float)pow (log((double)r2), (1.0 /(double)t))); } float poissrand(float l) /* poisson distribution routine */ { float r1, r2, r3; if (l < 0.0f ) return (0.0f); r1 = unirand(); r2 = (float)exp(-l); r3 = 0.0f; while (r1 >= r2) { r3++; r1 *= unirand(); } return (r3); }