use rand::prelude::*;
use std::any::Any;
use std::f32;
use crate::Modulator;
use crate::ModulatorEnv;
pub struct Wave {
pub amplitude: f32,
pub frequency: f32,
pub wave: Box<dyn Fn(&Wave, f32) -> f32>,
pub time: u64,
pub value: f32,
pub enabled: bool,
}
impl Wave {
pub fn new(amplitude: f32, frequency: f32) -> Self {
Wave {
amplitude,
frequency,
wave: Box::new(|_, _| 0.0),
time: 0,
value: 0.0,
enabled: true,
}
}
pub fn wave(mut self, wave: Box<dyn Fn(&Wave, f32) -> f32>) -> Self {
self.wave = wave;
self
}
pub fn set_wave(&mut self, wave: Box<dyn Fn(&Wave, f32) -> f32>) {
self.wave = wave;
}
}
impl Modulator<f32> for Wave {
fn value(&self) -> f32 {
self.value
}
fn range(&self) -> Option<[f32; 2]> {
Some([-self.amplitude, self.amplitude])
}
fn goal(&self) -> Option<f32> {
Some(self.value)
}
fn elapsed_us(&self) -> u64 {
self.time
}
fn enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn advance(&mut self, dt: u64) {
self.time += dt;
self.value = (self.wave)(self, ModulatorEnv::<f32>::micros_to_secs(self.time));
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
pub struct ScalarSpring {
pub smooth: f32,
pub undamp: f32,
pub goal: f32,
pub value: f32,
pub vel: f32,
pub time: u64,
pub enabled: bool,
}
impl ScalarSpring {
pub fn new(smooth: f32, undamp: f32, initial: f32) -> Self {
ScalarSpring {
smooth,
undamp,
goal: initial,
value: initial,
vel: 0.0,
time: 0,
enabled: true,
}
}
pub fn spring_to(&mut self, goal: f32) {
self.goal = goal;
}
pub fn jump_to(&mut self, goal: f32) {
self.goal = goal;
self.value = goal;
self.vel = 0.0;
}
}
impl Modulator<f32> for ScalarSpring {
fn value(&self) -> f32 {
self.value
}
fn goal(&self) -> Option<f32> {
Some(self.goal)
}
fn set_goal(&mut self, goal: f32) {
self.spring_to(goal);
}
fn elapsed_us(&self) -> u64 {
self.time
}
fn enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn advance(&mut self, dt: u64) {
self.time += dt;
if self.smooth < 0.0001 {
self.value = self.goal; self.vel = 0.0;
} else {
let dt = ModulatorEnv::<f32>::micros_to_secs(dt);
let (p, q, v) = (self.value - self.goal, self.goal, self.vel);
let b = self.undamp * 2.0 - 1.0;
let k = 2.0 / self.smooth;
let (kp, kdt) = (k * p, k * dt);
let ix = (-kdt).exp();
let dp = (v + kp) * dt;
let dv = (v * b - kp) * kdt;
self.value = (p + dp) * ix + q;
self.vel = (v + dv) * ix;
}
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
pub struct ScalarGoalFollower {
pub regions: Vec<[f32; 2]>,
pub random_region: bool,
pub threshold: f32,
pub vel_threshold: f32,
pub pause_range: [u64; 2],
pub follower: Box<dyn Modulator<f32>>,
pub current_region: usize,
pub paused_left: u64,
pub time: u64,
pub enabled: bool,
}
impl ScalarGoalFollower {
pub fn new(follower: Box<dyn Modulator<f32>>) -> Self {
ScalarGoalFollower {
regions: vec![],
random_region: false,
threshold: 0.01,
vel_threshold: 0.0001,
pause_range: [0, 0],
follower,
current_region: 0,
paused_left: 0,
time: 0,
enabled: true,
}
}
fn set_new_goal(&mut self) {
let n = self.regions.len(); if n > 0 {
self.current_region = if self.random_region {
thread_rng().gen_range(0..n)
} else if self.current_region + 1 < n {
self.current_region + 1
} else {
0
};
let region = &self.regions[self.current_region]; let goal = if region[1] > region[0] {
thread_rng().gen_range(region[0]..region[1])
} else {
region[0]
};
self.follower.set_goal(goal); }
}
}
impl Modulator<f32> for ScalarGoalFollower {
fn value(&self) -> f32 {
self.follower.value()
}
fn range(&self) -> Option<[f32; 2]> {
let mut r = if !self.regions.is_empty() {
self.regions[0]
} else {
[0.0, 0.0]
};
for j in self.regions.iter().skip(1) {
if j[0] < r[0] {
r[0] = j[0];
}
if j[1] > r[1] {
r[1] = j[1];
}
}
Some(r)
}
fn goal(&self) -> Option<f32> {
self.follower.goal()
}
fn set_goal(&mut self, goal: f32) {
self.follower.set_goal(goal);
}
fn elapsed_us(&self) -> u64 {
self.time
}
fn enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn advance(&mut self, dt: u64) {
self.time += dt;
if self.paused_left > 0 {
self.paused_left -= u64::min(self.paused_left, dt); } else {
let p0 = self.follower.value();
self.follower.advance(dt);
let p1 = self.follower.value();
let secs = ModulatorEnv::<f32>::micros_to_secs(dt);
let vel = if secs > f32::MIN {
(p1 - p0) / secs
} else {
0.0
};
if (p1 - self.follower.goal().unwrap()).abs() > self.threshold
|| vel.abs() > self.vel_threshold
{
return; }
self.paused_left = if self.pause_range[1] > self.pause_range[0] {
thread_rng().gen_range(self.pause_range[0]..self.pause_range[1])
} else {
self.pause_range[0]
};
}
if self.paused_left == 0 {
self.set_new_goal(); }
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
pub struct Newtonian {
pub speed_limit: [f32; 2],
pub acceleration: [f32; 2],
pub deceleration: [f32; 2],
pub goal: f32,
pub value: f32,
pub time: u64,
pub enabled: bool,
s: f32,
a: f32,
d: f32,
f: f32,
t: [f32; 3],
}
impl Newtonian {
pub fn new(
speed_limit: [f32; 2],
acceleration: [f32; 2],
deceleration: [f32; 2],
initial: f32,
) -> Self {
Newtonian {
speed_limit,
acceleration,
deceleration,
goal: initial,
value: initial,
time: 0,
enabled: true,
s: 0.0,
a: 0.0,
d: 0.0,
f: initial,
t: [0.0; 3],
}
}
pub fn reset(&mut self, value: f32) {
self.value = value;
self.goal = value;
self.s = 0.0;
self.a = 0.0;
self.d = 0.0;
self.f = value;
self.t = [0.0; 3];
}
pub fn move_to(&mut self, goal: f32) {
self.time = 0; self.goal = goal;
self.s = Newtonian::gen_value(&self.speed_limit);
self.a = Newtonian::gen_value(&self.acceleration);
self.d = Newtonian::gen_value(&self.deceleration);
self.f = self.value;
self.calculate_events();
}
fn calculate_events(&mut self) {
let x = (self.goal - self.f).abs();
let a = if self.a > f32::EPSILON {
self.a
} else {
1_000_000.0
};
let d = if self.d > f32::EPSILON {
self.d
} else {
1_000_000.0
};
let r = a / d;
self.t[0] = (x * 2.0 / (a * (1.0 + r))).sqrt();
let mut v = a * self.t[0];
if v > self.s {
v = self.s;
self.t[0] = self.s / a; } else {
self.s = v; }
self.t[2] = self.t[0] * r;
let d0 = self.t[0] * self.t[0] * a * 0.5;
let d2 = self.t[2] * self.t[2] * d * 0.5;
self.t[1] = (x - d0 - d2) / v;
if self.goal > self.f {
self.a = a;
self.d = -d;
} else {
self.s = -self.s;
self.a = -a;
self.d = d;
}
self.t[1] = self.t[0] + self.t[1]; self.t[2] = self.t[1] + self.t[2];
}
fn accelerate(a: f32, t: f32) -> f32 {
a * t * t * 0.5
}
fn forward(s: f32, t: f32) -> f32 {
s * t
}
fn gen_value(r: &[f32]) -> f32 {
if r[1] > r[0] {
thread_rng().gen_range(r[0]..r[1])
} else {
r[0]
}
}
}
impl Modulator<f32> for Newtonian {
fn value(&self) -> f32 {
self.value
}
fn goal(&self) -> Option<f32> {
Some(self.value)
}
fn set_goal(&mut self, goal: f32) {
self.move_to(goal);
}
fn elapsed_us(&self) -> u64 {
self.time
}
fn enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn advance(&mut self, dt: u64) {
self.time += dt;
let t = ModulatorEnv::<f32>::micros_to_secs(self.time); let (t0, t1, t2) = (self.t[0], self.t[1], self.t[2]);
self.value = self.f + Newtonian::accelerate(self.a, f32::min(t, t0));
if t > t0 {
self.value = self.value + Newtonian::forward(self.s, f32::min(t, t2) - t0);
if t > t1 {
self.value = self.value + Newtonian::accelerate(self.d, f32::min(t, t2) - t1);
}
}
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
pub struct ShiftRegister {
pub buckets: Vec<f32>,
pub ages: Vec<u32>,
pub value_range: [f32; 2],
pub odds: f32,
pub age_range: [u32; 2],
pub period: f32,
pub interp: ShiftRegisterInterp,
pub time: u64,
pub value: f32,
pub enabled: bool,
}
pub enum ShiftRegisterInterp {
Linear,
Quadratic,
None,
}
impl ShiftRegister {
pub fn new(
buckets: usize,
value_range: [f32; 2],
odds: f32,
period: f32,
interp: ShiftRegisterInterp,
) -> Self {
let b = Self::new_buckets(buckets, &value_range);
let v = if buckets > 0 { b[0] } else { 0.0 };
ShiftRegister {
buckets: b,
ages: vec![0; buckets],
value_range,
odds,
age_range: [std::u32::MAX; 2],
period,
interp,
time: 0,
value: v,
enabled: true,
}
}
fn new_buckets(buckets: usize, range: &[f32; 2]) -> Vec<f32> {
let mut b = Vec::with_capacity(buckets);
for _ in 0..buckets {
b.push(thread_rng().gen_range(range[0]..range[1]));
}
b }
fn total_period(&self) -> u64 {
(self.period * 1_000_000.0) as u64
}
fn bucket_period(&self) -> u64 {
let n = self.buckets.len();
assert!(n > 0);
self.total_period() / n as u64
}
fn next_bucket(&self, i: usize, n: usize) -> usize {
debug_assert!(n > 0);
if i < n - 1 {
i + 1
} else {
0
}
}
fn previous_bucket(&self, i: usize, n: usize) -> usize {
debug_assert!(n > 0);
if i > 0 {
i - 1
} else {
n - 1
}
}
}
impl Modulator<f32> for ShiftRegister {
fn value(&self) -> f32 {
self.value
}
fn range(&self) -> Option<[f32; 2]> {
Some(self.value_range)
}
fn elapsed_us(&self) -> u64 {
self.time
}
fn enabled(&self) -> bool {
self.enabled
}
fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
fn advance(&mut self, dt: u64) {
let n = self.buckets.len(); let p = self.total_period(); let bp = self.bucket_period();
if n == 0 || p == 0 || bp == 0 {
return;
}
let pt = self.time % p; let mut bi = usize::min((pt / bp) as usize, n - 1);
let bt = pt - bp * bi as u64; let r = (bt + dt) / bp;
for _ in 0..r {
let bh = self.previous_bucket(bi, n); let mut odds = f32::min(f32::max(0.0, self.odds), 1.0);
if self.ages[bh] >= self.age_range[0] && self.age_range[0] < self.age_range[1] {
let t = f32::min(
(self.ages[bh] - self.age_range[0]) as f32
/ (self.age_range[1] - self.age_range[0]) as f32,
1.0,
);
odds = odds + (1.0 - odds) * t;
}
if thread_rng().gen_range(0.0..1.0) < odds {
self.buckets[bh] = thread_rng().gen_range(self.value_range[0]..self.value_range[1]);
self.ages[bh] = 0;
} else {
self.ages[bh] += 1; }
bi = self.next_bucket(bi, n);
}
self.time += dt;
match self.interp {
ShiftRegisterInterp::Quadratic => {
let bh = self.previous_bucket(bi, n);
let bj = self.next_bucket(bi, n);
let v1 = self.buckets[bi];
let v0 = (self.buckets[bh] + v1) * 0.5;
let v2 = (self.buckets[bj] + v1) * 0.5;
let bt = self.time % p - bp * bi as u64;
let tt = bt as f32 / bp as f32;
let a0 = v0 + (v1 - v0) * tt;
let a1 = v1 + (v2 - v1) * tt;
self.value = a0 + (a1 - a0) * tt;
}
ShiftRegisterInterp::Linear => {
let v0 = self.buckets[bi];
let v1 = self.buckets[self.next_bucket(bi, n)];
let bt = self.time % p - bp * bi as u64;
self.value = v0 + (v1 - v0) * (bt as f32 / bp as f32);
}
ShiftRegisterInterp::None => self.value = self.buckets[bi],
}
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}