diff --git a/MozziGuts.cpp b/MozziGuts.cpp index 5fe2676ee..dae408bdd 100644 --- a/MozziGuts.cpp +++ b/MozziGuts.cpp @@ -14,7 +14,7 @@ #include "CircularBuffer.h" #include "MozziGuts.h" #include "mozzi_analog.h" -//#include "mozzi_utils.h" +#include "internal/mozzi_rand_p.h" #include "AudioOutput.h" // Forward declarations of functions to be provided by platform specific implementations @@ -274,6 +274,10 @@ void startMozzi(int control_rate_hz) { startAudio(); } +uint32_t MozziRandPrivate::x=132456789; +uint32_t MozziRandPrivate::y=362436069; +uint32_t MozziRandPrivate::z=521288629; + ////// END initialization /////// // reduce Macro leakage diff --git a/MozziGuts_impl_AVR.hpp b/MozziGuts_impl_AVR.hpp index 635780e5f..30e053ea7 100644 --- a/MozziGuts_impl_AVR.hpp +++ b/MozziGuts_impl_AVR.hpp @@ -409,15 +409,15 @@ static long longRandom() } #endif -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { ADCSRA &= ~ (1 << ADIE); // adc Disable Interrupt, re-enable at end // this attempt at remembering analog_reference stops it working // maybe needs a delay after changing analog reference in longRandom (Arduino reference suggests this) // because the analog reads return 0 //uint8_t analog_reference_orig = ADMUX&192; // analog_reference is high 2 bits of ADMUX, store this because longRandom sets it to internal - *x = longRandom(); - *y = longRandom(); - *z = longRandom(); + x = longRandom(); + y = longRandom(); + z = longRandom(); //analogReference(analog_reference_orig); // change back to original ADCSRA |= (1 << ADIE); // adc re-Enable Interrupt } diff --git a/MozziGuts_impl_ESP32.hpp b/MozziGuts_impl_ESP32.hpp index 2991bdc5c..3a2196146 100644 --- a/MozziGuts_impl_ESP32.hpp +++ b/MozziGuts_impl_ESP32.hpp @@ -162,10 +162,10 @@ void stopMozzi() { //// END AUDIO OUTPUT code /////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { - *x = esp_random(); - *y = esp_random(); - *z = esp_random(); +void MozziRandPrivate::autoSeed() { + x = esp_random(); + y = esp_random(); + z = esp_random(); } //// END Random seeding //////// diff --git a/MozziGuts_impl_ESP8266.hpp b/MozziGuts_impl_ESP8266.hpp index f56441c44..10d321642 100644 --- a/MozziGuts_impl_ESP8266.hpp +++ b/MozziGuts_impl_ESP8266.hpp @@ -139,11 +139,11 @@ void stopMozzi() { //// BEGIN Random seeding //////// #include -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { - *x = RANDOM_REG32; +void MozziRandPrivate::autoSeed() { + x = RANDOM_REG32; // TODO: The XORs may not be needed, but for lack of documentation (that I could find), let's assume RANDOM_REG32 // itself might not get updated on every read. NOTE: x, y, and z are initialized to non-zero, before this. - *y = *y ^ RANDOM_REG32; - *z = *z ^ RANDOM_REG32; + y = y ^ RANDOM_REG32; + z = z ^ RANDOM_REG32; } //// END Random seeding //////// diff --git a/MozziGuts_impl_MBED.hpp b/MozziGuts_impl_MBED.hpp index 96f4a1008..8babb2972 100644 --- a/MozziGuts_impl_MBED.hpp +++ b/MozziGuts_impl_MBED.hpp @@ -222,7 +222,7 @@ void stopMozzi() { ////// END audio output code ////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { #warning Automatic random seedings is not implemented on this platform } //// END Random seeding //////// diff --git a/MozziGuts_impl_RENESAS.hpp b/MozziGuts_impl_RENESAS.hpp index 0fbaaecd1..71f4dc2c6 100644 --- a/MozziGuts_impl_RENESAS.hpp +++ b/MozziGuts_impl_RENESAS.hpp @@ -170,7 +170,7 @@ void stopMozzi() { //// END AUDIO OUTPUT code /////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { #warning Automatic random seedings is not implemented on this platform } //// END Random seeding //////// diff --git a/MozziGuts_impl_RP2040.hpp b/MozziGuts_impl_RP2040.hpp index 79daf4995..51556ad0f 100644 --- a/MozziGuts_impl_RP2040.hpp +++ b/MozziGuts_impl_RP2040.hpp @@ -267,7 +267,7 @@ void stopMozzi() { ////// END audio output code ////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { #warning Automatic random seedings is not implemented on this platform } //// END Random seeding //////// diff --git a/MozziGuts_impl_SAMD.hpp b/MozziGuts_impl_SAMD.hpp index 84adc833b..a975fae86 100644 --- a/MozziGuts_impl_SAMD.hpp +++ b/MozziGuts_impl_SAMD.hpp @@ -140,7 +140,7 @@ void stopMozzi() { //// END AUDIO OUTPUT code /////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { #warning Automatic random seedings is not implemented on this platform } //// END Random seeding //////// diff --git a/MozziGuts_impl_STM32.hpp b/MozziGuts_impl_STM32.hpp index e57956544..bc881d168 100644 --- a/MozziGuts_impl_STM32.hpp +++ b/MozziGuts_impl_STM32.hpp @@ -140,7 +140,7 @@ void stopMozzi() { //// END AUDIO OUTPUT code /////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { // Unfortunately the internal temp sensor on STM32s does _not_ appear to create a lot of noise. // Ironically, the calls to calibrate help induce some random noise. You're still fairly likely to produce two equal // random seeds in two subsequent runs, however. @@ -150,12 +150,12 @@ void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { uint32_t ci; } conv; conv.cf = adc.readTemp(); - *x=*x^conv.ci; + x=x^conv.ci; adc.calibrate(); conv.cf = adc.readTemp(); - *y=*y^conv.ci; + y=y^conv.ci; adc.calibrate(); conv.cf = adc.readTemp(); - *z=*z^conv.ci; + z=z^conv.ci; } //// END Random seeding //////// diff --git a/MozziGuts_impl_STM32duino.hpp b/MozziGuts_impl_STM32duino.hpp index 8a56e0dcb..88d0e4be4 100644 --- a/MozziGuts_impl_STM32duino.hpp +++ b/MozziGuts_impl_STM32duino.hpp @@ -173,7 +173,7 @@ void stopMozzi() { //// END AUDIO OUTPUT code /////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { #warning Automatic random seedings is not implemented on this platform } //// END Random seeding //////// diff --git a/MozziGuts_impl_TEENSY.hpp b/MozziGuts_impl_TEENSY.hpp index a8efc2199..81ce2cf6e 100644 --- a/MozziGuts_impl_TEENSY.hpp +++ b/MozziGuts_impl_TEENSY.hpp @@ -114,7 +114,7 @@ void stopMozzi() { //// END AUDIO OUTPUT code /////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { +void MozziRandPrivate::autoSeed() { #warning Automatic random seedings is not implemented on this platform } //// END Random seeding //////// diff --git a/MozziGuts_impl_template.hpp b/MozziGuts_impl_template.hpp index 544b1b2e2..565cb39ba 100644 --- a/MozziGuts_impl_template.hpp +++ b/MozziGuts_impl_template.hpp @@ -158,8 +158,8 @@ void stopMozzi() { ////// END audio output code ////// //// BEGIN Random seeding //////// -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z) { - // Add here code to initialize the values pointed to by x, y, and z to some random values +void MozziRandPrivate::autoSeed() { + // Add here code to initialize the values of MozziRandPrivate::x, MozziRandPrivate::y, and MozziRandPrivate::z to some random values // This doesn't need to be crypographically safe. If nothing better is available, e.g. try reading an internal temperature sensor // in order to get some noise. It also doesn't have to be fast. // It *should* however ensure that rand() sequences will differ across reboots, after randSeed() has been called. diff --git a/mozzi_rand.cpp b/mozzi_rand.cpp deleted file mode 100644 index 531b0316a..000000000 --- a/mozzi_rand.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "mozzi_rand.h" - -// moved these out of xorshift96() so xorshift96() can be reseeded manually -static uint32_t x=132456789, y=362436069, z=521288629; -// static unsigned long x= analogRead(A0)+123456789; -// static unsigned long y= analogRead(A1)+362436069; -// static unsigned long z= analogRead(A2)+521288629; - -/** @ingroup random -Random number generator. A faster replacement for Arduino's random function, -which is too slow to use with Mozzi. -Based on Marsaglia, George. (2003). Xorshift RNGs. http://www.jstatsoft.org/v08/i14/xorshift.pdf -@return a random 32 bit integer. -@todo check timing of xorshift96(), rand() and other PRNG candidates. - */ - -unsigned long xorshift96() -{ //period 2^96-1 - uint32_t t; - - x ^= x << 16; - x ^= x >> 5; - x ^= x << 1; - - t = x; - x = y; - y = z; - z = t ^ x ^ y; - - return z; -} - - -/** @ingroup random -Initialises Mozzi's (pseudo)random number generator xorshift96(), which is used -in Mozzi's rand() function. This can be useful if you want random sequences to -be different on each run of a sketch, by seeding with fairly random input, such -as analogRead() on an unconnected pin (as explained in the Arduino documentation -for randomSeed(). randSeed is the same as xorshift96Seed(), but easier to -remember. -@param seed a number to use as a seed. -*/ -void randSeed(unsigned long seed) -{ - x=seed; -} - -// To be defined in hardware implementations -void autoRandomSeeds(uint32_t *x, uint32_t *y, uint32_t *z); - -/** @ingroup random -Initialises Mozzi's (pseudo)random number generator xorshift96(), which is used -in Mozzi's rand() function. This can be useful if you want random sequences to -be different on each run of a sketch, by seeding with a fairly random input. -randSeed() called without a parameter uses noise from reading the Arduino's -internal temperature as the seed, a technique discussed at -http://arduino.cc/forum/index.php/topic,38091.0.html, borrowing code put there -by Rob Tillaart. - -@note Intialization of the random seed is done differently on different MCUs, - but is nowhere near perfect for most (and for some it is not even implemented at all). - Many implementations (e.g. on AVR, STM32) simply rely on reading a (hopefully noisy) - internal temperature sensor. - You will often get better results by calling analogRead() - @em not mozziAnalogRead(0), in this case! - - on one or two floating (non-connected) analog pins. -*/ -void randSeed() { - autoRandomSeeds(&x, &y, &z); -} - -/** @ingroup random -Initialises Mozzi's (pseudo)random number generator xorshift96() with a chosen seed number. -@param seed a number to use as a seed. -*/ -void xorshiftSeed(unsigned long seed) -{ - x=seed; -} - - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param minval the minimum signed byte value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. -@param maxval the maximum signed byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random signed byte between minval and maxval-1 inclusive. -*/ -int8_t rand(int8_t minval, int8_t maxval) -{ - return (int8_t) ((((int) (lowByte(xorshift96()))) * (maxval-minval))>>8) + minval; -} - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param minval the minimum unsigned byte value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. -@param maxval the maximum unsigned byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random unsigned byte between minval and maxval-1 inclusive. -*/ -uint8_t rand(uint8_t minval, uint8_t maxval) -{ - return (uint8_t) ((((unsigned int) (lowByte(xorshift96()))) * (maxval-minval))>>8) + minval; -} - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param minval the minimum signed int value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. -@param maxval the maximum signed int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random int between minval and maxval-1 inclusive. -*/ -int rand( int minval, int maxval) -{ - return (int) ((((xorshift96() & 0xFFFF) * (maxval-minval))>>16) + minval); -} - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param minval the minimum unsigned int value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. -@param maxval the maximum unsigned int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random unsigned int between minval and maxval-1 inclusive. -*/ -unsigned int rand(unsigned int minval, unsigned int maxval) -{ - return (unsigned int) ((((xorshift96() & 0xFFFF) * (maxval-minval))>>16) + minval); -} - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param maxval the maximum signed byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random signed byte between 0 and maxval-1 inclusive. -*/ -int8_t rand(int8_t maxval) -{ - return (int8_t) ((((int) (lowByte(xorshift96()))) * maxval)>>8); -} - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param maxval the maximum unsigned byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random unsigned byte between 0 and maxval-1 inclusive. -*/ -uint8_t rand(uint8_t maxval) -{ - return (uint8_t) ((((unsigned int) (lowByte(xorshift96()))) * maxval)>>8); -} - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param maxval the maximum signed int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random int between 0 and maxval-1 inclusive. -*/ -int rand(int maxval) -{ - return (int) (((xorshift96() & 0xFFFF) * maxval)>>16); -} - - -/** @ingroup random -Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. -@param maxval the maximum unsigned int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. -@return a random unsigned int between 0 and maxval-1 inclusive. -*/ -unsigned int rand(unsigned int maxval) -{ - return (unsigned int) (((xorshift96() & 0xFFFF) * maxval)>>16); -} - - -/** @ingroup random -Generates a random number in the range for midi notes. -@return a random value between 0 and 127 inclusive -*/ -uint8_t randMidiNote() -{ - return lowByte(xorshift96())>>1; -} diff --git a/mozzi_rand.h b/mozzi_rand.h index ac75db24f..4e96fb94f 100644 --- a/mozzi_rand.h +++ b/mozzi_rand.h @@ -1,31 +1,151 @@ #ifndef MOZZI_RAND_H_ #define MOZZI_RAND_H_ -#if ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif +#include +#include "internal/mozzi_rand_p.h" +/** @ingroup random +Random number generator. A faster replacement for Arduino's random function, +which is too slow to use with Mozzi. +Based on Marsaglia, George. (2003). Xorshift RNGs. http://www.jstatsoft.org/v08/i14/xorshift.pdf +@return a random 32 bit integer. +@todo check timing of xorshift96(), rand() and other PRNG candidates. + */ +inline uint32_t xorshift96() { return MozziRandPrivate::xorshift96(); }; -unsigned long xorshift96(); +/** @ingroup random +Initialises Mozzi's (pseudo)random number generator xorshift96(), which is used +in Mozzi's rand() function. This can be useful if you want random sequences to +be different on each run of a sketch, by seeding with fairly random input, such +as analogRead() on an unconnected pin (as explained in the Arduino documentation +for randomSeed(). randSeed is the same as xorshift96Seed(), but easier to +remember. +@param seed a number to use as a seed. +*/ +inline void randSeed(uint32_t seed) { + MozziRandPrivate::x=seed; +} -void xorshiftSeed(unsigned long seed); -void randSeed(unsigned long seed); -void randSeed(); +/** @ingroup random +Initialises Mozzi's (pseudo)random number generator xorshift96(), which is used +in Mozzi's rand() function. This can be useful if you want random sequences to +be different on each run of a sketch, by seeding with a fairly random input. +randSeed() called without a parameter uses noise from reading the Arduino's +internal temperature as the seed, a technique discussed at +http://arduino.cc/forum/index.php/topic,38091.0.html, borrowing code put there +by Rob Tillaart. -int8_t rand(int8_t minval, int8_t maxval); -int8_t rand(int8_t maxval); +@note Intialization of the random seed is done differently on different MCUs, + but is nowhere near perfect for most (and for some it is not even implemented at all). + Many implementations (e.g. on AVR, STM32) simply rely on reading a (hopefully noisy) + internal temperature sensor. + You will often get better results by calling analogRead() - @em not mozziAnalogRead(0), in this case! - + on one or two floating (non-connected) analog pins. +*/ +inline void randSeed() { MozziRandPrivate::autoSeed(); }; -uint8_t rand(uint8_t minval, uint8_t maxval); -uint8_t rand(uint8_t maxval); +/** @ingroup random +Initialises Mozzi's (pseudo)random number generator xorshift96() with a chosen seed number. +@param seed a number to use as a seed. +// TODO: duplicate deprecate / remove +*/ +inline void xorshiftSeed(uint32_t seed) { randSeed(seed); }; -int rand(int minval, int maxval); -int rand(int maxval); +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param minval the minimum signed byte value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. +@param maxval the maximum signed byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random signed byte between minval and maxval-1 inclusive. +*/ +inline int8_t rand(int8_t minval, int8_t maxval) +{ + return (int8_t) ((((int) (lowByte(xorshift96()))) * (maxval-minval))>>8) + minval; +} -unsigned int rand(unsigned int minval, unsigned int maxval); -unsigned int rand(unsigned int maxval); +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param maxval the maximum signed byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random signed byte between 0 and maxval-1 inclusive. +*/ +inline int8_t rand(int8_t maxval) +{ + return (int8_t) ((((int) (lowByte(xorshift96()))) * maxval)>>8); +} -uint8_t randMidiNote(); +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param minval the minimum unsigned byte value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. +@param maxval the maximum unsigned byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random unsigned byte between minval and maxval-1 inclusive. +*/ +inline uint8_t rand(uint8_t minval, uint8_t maxval) +{ + return (uint8_t) ((((unsigned int) (lowByte(xorshift96()))) * (maxval-minval))>>8) + minval; +} + +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param maxval the maximum unsigned byte value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random unsigned byte between 0 and maxval-1 inclusive. +*/ +inline uint8_t rand(uint8_t maxval) +{ + return (uint8_t) ((((unsigned int) (lowByte(xorshift96()))) * maxval)>>8); +} + +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param minval the minimum signed int value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. +@param maxval the maximum signed int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random int between minval and maxval-1 inclusive. +*/ +inline int16_t rand(int16_t minval, int16_t maxval) +{ + return (int16_t) ((((xorshift96() & 0xFFFF) * (maxval-minval))>>16) + minval); +} + + +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param minval the minimum unsigned int value of the range to be chosen from. Minval will be the minimum value possibly returned by the function. +@param maxval the maximum unsigned int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random unsigned int between minval and maxval-1 inclusive. +*/ +inline uint16_t rand(uint16_t minval, uint16_t maxval) +{ + return (uint16_t) ((((xorshift96() & 0xFFFF) * (maxval-minval))>>16) + minval); +} + + +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param maxval the maximum signed int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random int between 0 and maxval-1 inclusive. +*/ +inline int16_t rand(int16_t maxval) +{ + return (int16_t) (((xorshift96() & 0xFFFF) * maxval)>>16); +} + + +/** @ingroup random +Ranged random number generator, faster than Arduino's built-in random function, which is too slow for generating at audio rate with Mozzi. +@param maxval the maximum unsigned int value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function. +@return a random unsigned int between 0 and maxval-1 inclusive. +*/ +inline uint16_t rand(uint16_t maxval) +{ + return (uint16_t) (((xorshift96() & 0xFFFF) * maxval)>>16); +} + + +/** @ingroup random +Generates a random number in the range for midi notes. +@return a random value between 0 and 127 inclusive +*/ +inline uint8_t randMidiNote() +{ + return lowByte(xorshift96())>>1; +} #endif /* MOZZI_RAND_H_ */