forked from sensorium/Mozzi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mozzi_rand.cpp
264 lines (222 loc) · 9.63 KB
/
mozzi_rand.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#include "mozzi_rand.h"
#include "hardware_defines.h"
#if IS_STM32()
#include <STM32ADC.h>
extern STM32ADC adc;
#elif IS_ESP8266()
#include <esp8266_peri.h>
#endif
// moved these out of xorshift96() so xorshift96() can be reseeded manually
static unsigned long 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
// static unsigned long x=123456789, y=362436069, z=521288629;
unsigned long 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(long seed)
{
x=seed;
}
#if defined (__AVR_ATmega644P__)
// a less fancy version for gizduino (__AVR_ATmega644P__) which doesn't know INTERNAL
static long longRandom()
{
return ((long)analogRead(0)+63)*(analogRead(1)+97); // added offsets in case analogRead is 0
}
#elif defined (__AVR_ATmega2560__)
/*
longRandom(), used as a seed generator, comes from:
http://arduino.cc/forum/index.php/topic,38091.0.html
// AUTHOR: Rob Tillaart
// PURPOSE: Simple Random functions based upon unreliable internal temp sensor
// VERSION: 0.1
// DATE: 2011-05-01
//
// Released to the public domain, use at own risk
//
*/
static long longRandom()
{
//analogReference(INTERNAL2V56);
unsigned long rv = 0;
for (uint8_t i=0; i< 32; i++) rv |= ((analogRead(8)+2294) & 1L) << i; // added 2294 in case analogRead is 0
return rv;
}
#elif IS_AVR()
static long longRandom()
{
//analogReference(INTERNAL);
unsigned long rv = 0;
for (uint8_t i=0; i< 32; i++) rv |= ((analogRead(8)+1171) & 1L) << i; // added 1171 in case analogRead is 0
return rv;
}
#endif
/** @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 It's not perfect, as discussed in the forum thread.
It might only work with some processors: (from the thread)
"...ATmega328P in DIP, possibly others but the duemilanove and uno will do it at least."
So far, gizduino's __AVR_ATmega644P__ chip doesn't like it, so we use (long)analogRead(0)*analogRead(1) for that instead.
It works to some degree on STM32 chips, but the produced seed is not very random at all. Again, using an appropriate
analogRead() (preferably on one or two floating input pins) is much more effective.
@todo add Teensy 3 code
*/
void randSeed() {
#if IS_AVR()
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();
//analogReference(analog_reference_orig); // change back to original
ADCSRA |= (1 << ADIE); // adc re-Enable Interrupt
#elif IS_STM32()
// 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.
adc.enableInternalReading();
float dummy = adc.readTemp();
int* dummy_int = (int*) &dummy;
x=*dummy_int;
adc.calibrate();
dummy = adc.readTemp();
y=*dummy_int;
adc.calibrate();
dummy = adc.readTemp();
z=*dummy_int;
#elif IS_ESP8266()
x = RANDOM_REG32;
y = random (0xFFFFFFFF) ^ RANDOM_REG32;
z = random (0xFFFFFFFF) ^ RANDOM_REG32;
#else
#warning Automatic random seeding not implemented on this platform
#endif
}
/** @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(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 uint8_t value of the range to be chosen from. Minval will be the minimum value possibly returned by the function.
@param maxval the maximum signed uint8_t value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function.
@return a random int8_t 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 uint8_t value of the range to be chosen from. Minval will be the minimum value possibly returned by the function.
@param maxval the maximum unsigned uint8_t value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function.
@return a random uint8_t 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 uint8_t value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function.
@return a random int8_t 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 uint8_t value of the range to be chosen from. Maxval-1 will be the largest value possibly returned by the function.
@return a random uint8_t 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;
}