CS_RAND.DOC

8 September 1995

Robin Whittle   firstpr@ozemail.com.au  rwhittle@ozonline.com.au
                http://www.ozemail.com.au/~firstpr

For Csound users and C programmers.


Mods to the xlinrand series of noise generators added by Paris 
Smarargdis early in 1995.  

*       A new common 31 bit random source for these generators.

*       Setting the seed of this generator.

*       A new uniform distribution generator to make the family 
        complete.  (Uniform means even distribution between 0 and 1.)


Introduction
============

I am interested in a Csound piece having quite a few random elements, 
and there being:

1 -     An even distribution of random values.

2 -     A long pattern of pseudo-randomness - ie. not a short repeat 
        pattern.

3 -     The ability to start all random functions from a single seed.   

So ideally, all random functions would return a huge range of values, 
in a very long repeating pattern, and a single seed would start the 
process.  This enables me to create a piece say ten times, based on 
ten seeds that I choose.  Then I can listen to them and depending on 
which one I like the most, know that I can regenerate that version 
predictably from the same .ORC and .SCO file and the same seed.

So all random numbers would arise from a single common function, 
working from a single variable which is updated every call.  This 
variable is initialised by the seed I put in.

Ideally, we would be dealing with floating point numbers, or at least 
32 bit long integers.  The repeat time is typically a direct function 
of the length of the internal state number.

What we have at present (until my mods) in Csound is rather different 
from that.


Standard rand ugens
===================

These are rand, rand and randi in ugens4.c.  They all share a common 
approach to generating a pseudo random number.


Each instance maintains its own state, so if you have two rand ugens 
in the one instrument, or in separate instruments (or separate 
instances of instruments) then if you start with the same seed, each 
ugen will always produce the same sequence of numbers, at whatever 
rate it runs.

The default is for a seed of 0.5.  The 16 bit state is multiplied by a 
constant (15625) then 1 is added.  The result overflows, and the 
remainder is a 16 bit number, which is treated as a signed short 
integer (+32767 to - 32768).  This is converted to a float and divided 
by 32768 to give a +/- 1 pseudo-random number.

I presume the constant has been chosen wisely to give a repeat cycle 
as long as possible.  Since it is a 16 bit internal state, it must 
repeat at least every 65536 cycles.


This system has no common state which I seek for controlling all 
pseudo-randomness in a peice from a single seed.  I suspect that the 
sophisication of the random generator is modest.  Certainly it has a 
short repeat cycle.


zlinrand family of noise generators
===================================

These were added by Paris Smarargdis early in 1995.  The doco I use 
comes from John Fitch's readme.cso 14 April 95 (the original file name 
on his Bath ftp server was README.csound).  

Looking at the code in CMATH.C, it can be seen that they all operate 
from the standard ANSI C library function int rand(), which returns a 
16 bit pseudo random number and maintains a 16 bit state.

This goes a long way towards what I want.  Given a particular seed, 
rand() will produce a predictable sequence of numbers.  I presume its 
algorithm is a more sophisticated than that used in ugens4.c.

In the doco, there is nothing mentioned about setting the seed, but 
Paris has provided a ugen for it.  

        seed    iblah

This ugen runs only once, at the init time of the instrument it is in.  
It sets the C library's rand() internal state to the contents of 
iblah.  It also prints iblah on the console, with three decimal places 
of precision.

Looking at the ANSI C doco and running tests, I have determined the 
following:

1 -     The result and internal state of rand() is based on a 16 bit 
        integer.

2 -     The seed ugen feeds its parameter directly to the ANSI srand() 
        function. 

3 -     This is expecting an integer, not a float. So there is no 
        difference between iblah being 12.7 and 12.  This means that 
        the printing of 3 decimal places of precision is misleading - 
        these make no difference.

4 -     The seed ugen requires an integer between 0 and 65535.  
        Anything outside that just wraps around.  So giving it 0 or 
        65536 gives the same subsequent set of pseudo-random results.


DJGPP (DOS GCC ANSI Compiler) contains an "improved" set of pseudo-
random generators random() and srandom(), but they too are based on 16 
bit values.  These are not, to my knowledge standard ANSI C functions.

I will use Paris' set of random noise generators in preference to the 
standard Csound ones - they share a common seed, allow the seed to be 
set, and use the ANSI library random number generator.

I wish I knew more about some of the distributions provided in this 
set of ugens.

The above comments apply to the original CMATH.C and CMATH.H - now 
called CMATH.COL and CMATH.HOL in my CSRW_SRC.ZIP.


My modifications
================

Here is what I have done in my modified CSMATH.C and CSMATH.H.
These mods do not affect the standard Csound random generators - only 
Paris' xlinrand family - and then only in the quality of the random 
numbers they generate.

1 - The global random number generator
--------------------------------------

I have removed Paris' use of the compiler's rand() function.  In its 
place I have installed a 31 bit function - the source code of which I 
obtained from a library function of a BSD Unix release which I found 
via a WWW search.  This is but one line from their rand function - a 
simple self contained function which was only used when some much more 
elaborate code is not used.

It seems that pseudo random generators come in three flavours:

1 -     El-cheapo 15 or 16 bit things - quite sus for audio rate noise.

2 -     Relatively rare, but still simple 31 bit generators like this 
        one.  (This is the only one I could find.)

3 -     Much more complex, highly sophisticated generators suitable 
        for use in the most demanding scientific calculations.

The new generator is the multiply by foo and add bar kind - where both 
foo and bar have somehow been chosen to give a very long repeat cycle.


The original Csound random number generators rand, randh and randi are 
not affected by this - they have their own self contained generator 
for each instance.

To set the seed for the new global generator use the seed ugen:

        seed    iblah
        
Where the seed is any number.  Values with three decimal places 
between 0 and 2147483.647 should give unique starting points.


Here is the new code for the common random number generator and its 
seed setting function.

/*-----------------------------------------------------------------*/

#define GRAND_MAX  0x7FFFFFFFL 

                                /* grand()
                                 *
                                 * A 31 bit global random number 
                                 * generator.
                                 *
                                 * This is intended to give a  
                                 * long cycle - longer than the
                                 * 32767 cycles available 
                                 * from ANSI rand() - which show
                                 * up as cyclic fluctuations in noise
                                 * when we use them at audio rates.
                                 *
                                 * We need a global variable for
                                 * the state - a 32 bit long integer.
                                 *
                                 * Initialize it with an auspicious 
                                 * number derived from 32 tosses of
                                 * a coin.
                                 *
                                 * Also define the maximum value for
                                 * the random number generator - see
                                 * start of file.
                                 *
                                 * The generator produces a 31 bit
                                 * positive integer. 
                                 */
long    grandstat = 0x16BA2118L;

                                /* Random number generator.
                                 */
long    grand(void)
{
        grandstat = (grandstat * 1103515245 + 12345) & GRAND_MAX;

        return  grandstat;
}               


void seedrand(PRAND *p)
{
                                /* New random seed setting function.
                                 *
                                 * Paris wrote it to use the same
                                 * PRAND data structure as the other
                                 * functions. It has only one input
                                 * parameter, and no output parameters
                                 * so the input is in the first 
                                 * variable in PRAND.
                                 *
                                 * Take this to be a floating point
                                 * number with three decimal points.
                                 * Display this and multiply it by
                                 * 1000 to make these parts of the 
                                 * number map into the final 32 bit
                                 * seed.
                                 * 
                                 * This is quite arbitrary, but it 
                                 * enables people to use numbers 
                                 * between 0.000 and 2147483.647
                                 * to get unique starting points.
                                 * 
                                 * Hash the seed with another 
                                 * auspicious number before using
                                 * it. This number comes from the 
                                 * xor of 32 tosses of two coins -
                                 * and rounded to an odd number so
                                 * bits 0 to 30 of the original
                                 * value affect their respective bits 
                                 * of the final 31 bit seed.
                                 *
                                 * Unique starting points can be
                                 * had from any number with three
                                 * decimal places of precision from
                                 * 0.0 to 2147483.647.
                                 */

        printf("Seeding with %.3f\n", *p->out);

        grandstat = ( (unsigned int)*p->out * 1000) * 0xA7DD150D + 1234567;

        grandstat = grandstat & GRAND_MAX;
}

/*------------------------------------------------------------------*/


2 - New Uniform random number generator
---------------------------------------

A uniform random number generator has an even distribution of numbers 
between 0 and 1.  It is a standard, no frills random generator.

(The linear distribution generator has a high probability of it being 
near 0 and a decreasing probablility of the number being higher - 
until there is a virtually 0 probability of it being near 1.)

New ungens:

ir      iunirand irange

kr      kunirand krange

ar      aunirand arange

These are like the rest of Paris' family of noise generators.  
The output value is xrange is multiplied by the raw 0 to 1 random 
number.

Paris told me he meant to include this in his release.

<<<<