Random Number Generation
A fast XorShift64 random number generator suitable for audio applications.
Overview
XorShiftRng provides:
- Fast pseudo-random number generation
- Deterministic output (given the same seed)
- Audio-range output methods (-1.0 to 1.0)
API
Creating an RNG
#![allow(unused)] fn main() { use bbx_core::random::XorShiftRng; // Create with a seed let mut rng = XorShiftRng::new(42); // Create with a different seed for different sequences let mut rng2 = XorShiftRng::new(12345); }
Generating Numbers
#![allow(unused)] fn main() { use bbx_core::random::XorShiftRng; let mut rng = XorShiftRng::new(42); // Raw u64 value let raw = rng.next_u64(); // Floating-point 0.0 to 1.0 let normalized = rng.next_f32(); // or next_f64() // Audio sample -1.0 to 1.0 let sample = rng.next_noise_sample(); }
Usage in Audio
White Noise Generator
#![allow(unused)] fn main() { use bbx_core::random::XorShiftRng; struct NoiseGenerator { rng: XorShiftRng, } impl NoiseGenerator { fn new(seed: u64) -> Self { Self { rng: XorShiftRng::new(seed), } } fn process(&mut self, output: &mut [f32]) { for sample in output { *sample = self.rng.next_noise_sample(); } } } }
Randomized Modulation
#![allow(unused)] fn main() { use bbx_core::random::XorShiftRng; struct RandomLfo { rng: XorShiftRng, current_value: f32, target_value: f32, smoothing: f32, } impl RandomLfo { fn new(seed: u64, smoothing: f32) -> Self { let mut rng = XorShiftRng::new(seed); let initial = rng.next_noise_sample(); Self { rng, current_value: initial, target_value: initial, smoothing, } } fn process(&mut self) -> f32 { // Occasionally pick a new target if self.rng.next_f32() < 0.001 { self.target_value = self.rng.next_noise_sample(); } // Smooth toward target self.current_value += (self.target_value - self.current_value) * self.smoothing; self.current_value } } }
Algorithm
XorShift64 is a simple but effective pseudo-random number generator:
#![allow(unused)] fn main() { fn next_u64(&mut self) -> u64 { let mut x = self.state; x ^= x << 13; x ^= x >> 7; x ^= x << 17; self.state = x; x } }
Properties:
- Period: 2^64 - 1
- Fast: ~3 CPU cycles per number
- Good statistical properties for audio use
- Not cryptographically secure
Seeding
Different seeds produce completely different sequences:
#![allow(unused)] fn main() { use bbx_core::random::XorShiftRng; let mut rng1 = XorShiftRng::new(1); let mut rng2 = XorShiftRng::new(2); // Completely different sequences assert_ne!(rng1.next_u64(), rng2.next_u64()); }
For reproducible results (e.g., testing), use a fixed seed.
For unique sequences each run, use a time-based seed:
#![allow(unused)] fn main() { use bbx_core::random::XorShiftRng; use std::time::{SystemTime, UNIX_EPOCH}; let seed = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_nanos() as u64; let mut rng = XorShiftRng::new(seed); }