From 817ff72265efe20d6b511d2d6cd16cc6dfbff4f4 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 8 Mar 2022 20:42:59 +0100 Subject: [PATCH] Add a PCG implementation for pcg32i and floats --- plugins/crisp/src/lib.rs | 2 + plugins/crisp/src/pcg.rs | 79 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 plugins/crisp/src/pcg.rs diff --git a/plugins/crisp/src/lib.rs b/plugins/crisp/src/lib.rs index efd98808..6e11068a 100644 --- a/plugins/crisp/src/lib.rs +++ b/plugins/crisp/src/lib.rs @@ -17,6 +17,8 @@ use nih_plug::prelude::*; use std::pin::Pin; +mod pcg; + /// Hardcoded to make SIMD-ifying this a bit easier in the future const NUM_CHANNELS: usize = 2; diff --git a/plugins/crisp/src/pcg.rs b/plugins/crisp/src/pcg.rs new file mode 100644 index 00000000..1ecc362c --- /dev/null +++ b/plugins/crisp/src/pcg.rs @@ -0,0 +1,79 @@ +// Crisp: a distortion plugin but not quite +// Copyright (C) 2021-2022 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! A minimal implementation of `pcg32i` PRNG from the PCG library. Implemented separately instead +//! of using the rand crate implementation so we can adapt this for SIMD use. +//! +//! +//! + +const PCG_DEFAULT_MULTIPLIER_32: u32 = 747796405; + +/// The `pcg32i` PRNG from PCG. +#[derive(Copy, Clone)] +pub struct Pcg32iState { + state: u32, + inc: u32, +} + +impl Pcg32iState { + /// Initialize the PRNG, aka `*_srandom()`. + /// + /// + pub fn new(state: u32, sequence: u32) -> Self { + let mut rng = Self { + state: 0, + inc: (sequence << 1) | 1, + }; + + rng.step(); + rng.state += state; + rng.step(); + + rng + } + + /// Generate a new uniformly distirubted `u32` covering all possible values. + /// + /// + #[inline] + pub fn next_u32(&mut self) -> u32 { + let old_state = self.state; + self.step(); + + let word = ((old_state >> ((old_state >> 28) + 4)) ^ old_state) * 277803737; + (word >> 22) ^ word + } + + /// Generate a new `f32` value in the open `(0, 1)` range. + #[inline] + pub fn next_f32(&mut self) -> f32 { + const FLOAT_SIZE: u32 = std::mem::size_of::() as u32 * 8; + + // Implementation from https://docs.rs/rand/0.8.4/rand/distributions/struct.Open01.html + let value = self.next_u32(); + let fraction = value >> (FLOAT_SIZE - f32::MANTISSA_DIGITS - 1); + + let exponent_bits: u32 = ((f32::MAX_EXP - 1) as u32) << (f32::MANTISSA_DIGITS - 1); + f32::from_bits(fraction | exponent_bits) - (1.0 - f32::EPSILON / 2.0) + } + + /// + #[inline] + fn step(&mut self) { + self.state = self.state * PCG_DEFAULT_MULTIPLIER_32 + self.inc; + } +}