Skip to content

Commit

Permalink
Doxygen documentation for the randomizer
Browse files Browse the repository at this point in the history
  • Loading branch information
theGreatWhiteShark committed Jul 21, 2018
1 parent 1635785 commit ec73701
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 53 deletions.
76 changes: 61 additions & 15 deletions src/core/include/hydrogen/randomizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,37 @@
#include <cmath>

#define PI ( 3.1415926536d )
/**
* Number of white noise sources to approximate a 1/f spectrum in the
* pink() function.
*/
#define PINK_USED_ROWS ( 12 )
/**
* Maximum number of independent white noise sources to be used in
* pink().
*/
#define PINK_MAX_ROWS ( 30 )
/**
* Number of bits used in the output of the pink() function.
*/
#define PINK_BITS ( 24 )
/**
* How much bits less then the 32 bit long integer does the output of
* the pink() function have.
*/
#define PINK_SHIFT ( ( sizeof( long )* 8 ) - PINK_BITS )

namespace H2Core {

/**
* @brief Used to generate all random numbers used within the humanizer.
*
* Since not only Gaussian white noise, with increments perfectly
* independent from each other, but also noise of different colors
* will be use, this object provides a state of the random number
* generator. This state is required to draw the next, correlated
* number and should not be shared between different instruments.
*/
class Randomizer {
public:
// Constructor and destructor
Expand Down Expand Up @@ -69,34 +93,56 @@ class Randomizer {
private:
static Randomizer* __instance;
////////////// White uniform noise ///////////////////////////
// Internal state of the white uniform random number
// generator.
/**
* Internal state of the white uniform random number
* generator.
*/
unsigned long long int uniformStateInt64;
//////////////////////////////////////////////////////////////
//
////////////////////// Gaussian white noise //////////////////
// This methods generates two Gaussian-distributed variables
// out of two uniformly distributed ones. One will be returned
// and the other stored in this variable to be returned during
// the next call.
/**
* @brief Auxiliary variable storing an addition Gaussian
* white number.
*
* The white_gaussian() function generates two
* Gaussian-distributed variables out of two uniformly
* distributed ones. One will be returned and the other stored
* in this variable to be returned during the next call.
*/
double gaussianSecondVariable;
//////////////////////////////////////////////////////////////
//
/////////////////////////// Pink noise ///////////////////////
// Array containing the `PINK_MAX_ROWS' independent white
// noise sources.
/**
* Array containing the PINK_MAX_ROWS independent white
* noise sources in the pink() function.
*/
long rowsPink[ PINK_MAX_ROWS ];
// Variable holding the sum over all independent white noise
// sources (used for optimization purposes).
/**
* Variable holding the sum over all independent white noise
* sources (used for optimization purposes) in the pink()
* function.
*/
long runningSumPink;
// Internal time unit.
/**
* Internal time unit of the pink() function.
*/
int indexPink;
// Determines the maximum possible value of `indexPink'.
/**
* Determines the maximum possible value of `indexPink'.
*/
int indexMaskPink;
// Biggest possible value generated by the pink noise source.
/**
* Biggest possible value generated by the pink noise source
* pink().
*/
long maxValuePink;
// Normalization constant to transform the result of type
// long into float and in the range of -1.0 to +1.0.
/**
* Normalization constant to transform the result of the
* pink() function of type long into float and in the range of
* -1.0 to +1.0.
*/
float normalizationPink;
//////////////////////////////////////////////////////////////
};
Expand Down
135 changes: 97 additions & 38 deletions src/core/src/randomizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,34 @@ namespace H2Core {

Randomizer* Randomizer::__instance = 0;

// Constructor
/**
* @brief Constructor initializing the states of the individual
* colors.
*
* Since the \p uniform_white() function is used within the generation
* of all other colors the state of the uniform white noise generator
* is initialized first. This is done using a random seed drawn by the
* \p std::rand() function. The output of the \p std::rand() function
* will be of type integer and the first bits will be filled with
* zeros in the conversion into a 64 bit integer. But since this only
* affects the initialization step, it won't cause any problems within
* for the algorithms within used within the Randomizer.
*
* @return Object of class Randomizer.
*/
Randomizer::Randomizer() :
uniformStateInt64( 4101842887655102017LL ) {
__instance = this;
// Generate a random seed
//
// Random seed used to initiate the Randomizer object.
//
// The output of the std::rand() function will be of type
// integer and the first bits will be filled with zeros in the
// conversion into a 64 bit integer. But since this only
// affects the initialization step, it won't cause any
// problems within for the algorithms within used within the
// Randomizer.
//
unsigned long long int initialSeed = std::rand();
//
// Initialize the white uniform noise source.
Expand All @@ -49,7 +72,7 @@ Randomizer::Randomizer() :
indexMaskPink = ( 1 << PINK_USED_ROWS ) - 1;
// Biggest possible signed random value generated by the pink
// noise generator. An extra 1 is added for the white noise
// source added to the pink noise.
// source added to the pink noise.
maxValuePink = ( PINK_USED_ROWS + 1 ) *
( 1 << ( PINK_BITS - 1 ) );
// Normalization constant to convert the output into float.
Expand All @@ -64,52 +87,79 @@ Randomizer::Randomizer() :
runningSumPink = 0;
}

// Create an instance within Hydrogen
/**
* Create an instance within Hydrogen
*/
Randomizer* Randomizer::create_instance(){
if ( __instance == 0 ){
__instance = new Randomizer;
}
return __instance;
}
// Retrieve a created instance
/**
* Retrieve the created instance
*/
Randomizer* Randomizer::get_instance(){
assert( __instance );
return __instance;
}
/////////////////////// White uniform noise //////////////////////////
// The uniform white noise generator is the basis for all colors
// produced by this struct. It will use the `Ranq1' code recommended
// by the book "Numerical Recipes" by Press et al. p. 351. It is a
// composed generator capable of producing random numbers (the
// std::rand() function produces slightly correlated output) and has
// a period of "only" 1.8 * 10^19. But for our use at hand it is more
// than sufficient.
//
// Composed generator with a multiplicative linear congruential
// generator as the outer method and a 64-bit Xorshift method as the
// inner one.
/**
* @brief Uniform white noise generator for 64 bit integers.
*
* A Composed generator with a multiplicative linear congruential
* generator as the outer method and a 64-bit Xorshift method as the
* inner one.
*
* The uniform white noise generator is the basis for all colors
* produced by this struct. It will use the *Ranq1* code recommended
* by the book "Numerical Recipes" by Press et al. p. 351. It is a
* composed generator capable of producing random numbers (the
* std::rand() function produces slightly correlated output) and has a
* period of \e only 1.8 * 10^19. But for our use at hand it is more
* than sufficient.
*
* @return A 64 bit integer uniformly and independently distributed
* random number.
*/
unsigned long long int Randomizer::white_uniform_int64(){
uniformStateInt64 ^= uniformStateInt64 >> 21;
uniformStateInt64 ^= uniformStateInt64 << 35;
uniformStateInt64 ^= uniformStateInt64 >> 4;
return uniformStateInt64 * 2685821657736338717LL;
}
// Double precision version of the algorithm.
/**
* @brief Uniform white noise generator at double precision.
*
* @return A double precision uniformly and independently
* distributed random number.
*/
double Randomizer::white_uniform(){
return 5.42101086242752217E-20 * white_uniform_int64();
}
//////////////////////////////////////////////////////////////////////

////////////////////////// Gaussian white noise //////////////////////
// There are several algorithms for generating Gaussian white
// noise. But most of them just try to approximate the Gaussian nature
// of the signal. Instead the Box-Muller transformation will be used
// to transform uniformly distributed white noise into true Gaussian
// white noise.
//
// Box-Muller transformation. The resulting Gaussian random
// variable will be of mean 0 and of standard deviation
// `standardDeviation'.
/**
* @brief Gaussian white noise generator at double precision.
*
* This function is based on the Box-Muller transformation. The
* resulting Gaussian random variable will be of mean 0 and of
* standard deviation \p standardDeviation.
*
* While other algorithms do approximate the Gaussian nature of the
* generated noise this one will yield the most precise results
* because it is based on more mathematical exact transformation.
*
* @param standardDeviation A double precision number specifying the
* standard deviation, or square root of the variance, of the
* generated Gaussian white noise.
*
* @sa white_uniform
*
* @return A double precision independently and normally distributed
* random number.
*/
double Randomizer::white_gaussian( double standardDeviation ){
double uniformRandomNumber1, uniformRandomNumber2,
distance, factor;
Expand Down Expand Up @@ -147,17 +197,26 @@ double Randomizer::white_gaussian( double standardDeviation ){
//////////////////////////////////////////////////////////////////////

/////////////////////////////// Pink noise ///////////////////////////
// The one over frequency behavior of a true pink spectrum will be
// approximated by summing a bunch of white noises, which are updated
// on different time scales. Those times are positioned equidistant on
// a logarithmic time scale.
// This algorithm will generate a fair 1/f spectrum with some
// inaccuracy at very low frequencies and is based on code snippet
// posted by Phil Burk on the music-dsp mailing
// list. http://www.firstpr.com.au/dsp/pink-noise/
// The number of involved independent random white noises can be
// controlled using the `PINK_USED_ROWS' constant in the corresponding
// header file.
/**
* @brief Pink noise generator at double precision.
*
* The one over frequency behavior of a true pink spectrum will be
* approximated by summing a bunch of white noises, which are updated
* on different time scales. Those times are positioned equidistant on
* a logarithmic time scale. This algorithm will generate a fair 1/f
* spectrum with some inaccuracy at very low frequencies and is based
* on code snippet posted by Phil Burk on the music-dsp mailing
* list. http:www.firstpr.com.au/dsp/pink-noise/ The number of
* involved independent random white noises can be controlled using
* the \p PINK_USED_ROWS constant in the corresponding header file.
*
* @param scale A float number, which will be multiplied with the
* resulting pink random numbers.
*
* @sa white_uniform_int64
*
* @return A pink random number at float precision
*/
float Randomizer::pink( float scale ){
long uniformRandomNumber, sumUpdate;
float output;
Expand Down Expand Up @@ -187,7 +246,7 @@ float Randomizer::pink( float scale ){
// noise sources will not be calculated in every
// run. Instead, the chosen one will be subtracted and
// the updated value will be add back to
// `runningSumPink'.
// `runningSumPink'.
runningSumPink -= rowsPink[ numberOfZeros ];
uniformRandomNumber =
( (long)white_uniform_int64() ) >> PINK_SHIFT;
Expand Down

0 comments on commit ec73701

Please sign in to comment.