use super::*;
use funutd::Rnd;
#[inline]
pub fn abs<T: Num>(x: T) -> T {
x.abs()
}
#[inline]
pub fn signum<T: Num>(x: T) -> T {
x.signum()
}
#[inline]
pub fn min<T: Num>(x: T, y: T) -> T {
x.min(y)
}
#[inline]
pub fn max<T: Num>(x: T, y: T) -> T {
x.max(y)
}
#[inline]
pub fn pow<T: Num>(x: T, y: T) -> T {
x.pow(y)
}
#[inline]
pub fn floor<T: Num>(x: T) -> T {
x.floor()
}
#[inline]
pub fn fract<T: Num>(x: T) -> T {
x.fract()
}
#[inline]
pub fn ceil<T: Num>(x: T) -> T {
x.ceil()
}
#[inline]
pub fn round<T: Num>(x: T) -> T {
x.round()
}
#[inline]
pub fn sqrt<T: Real>(x: T) -> T {
x.sqrt()
}
#[inline]
pub fn exp<T: Real>(x: T) -> T {
x.exp()
}
#[inline]
pub fn exp2<T: Real>(x: T) -> T {
x.exp2()
}
#[inline]
pub fn exp10<T: Real>(x: T) -> T {
(x * T::from_f64(LN_10)).exp()
}
#[inline]
pub fn log<T: Real>(x: T) -> T {
x.log()
}
#[inline]
pub fn log2<T: Real>(x: T) -> T {
x.log2()
}
#[inline]
pub fn log10<T: Real>(x: T) -> T {
x.log10()
}
#[inline]
pub fn sin<T: Real>(x: T) -> T {
x.sin()
}
#[inline]
pub fn cos<T: Real>(x: T) -> T {
x.cos()
}
#[inline]
pub fn tan<T: Real>(x: T) -> T {
x.tan()
}
#[inline]
pub fn tanh<T: Real>(x: T) -> T {
x.tanh()
}
pub const SQRT_2: f64 = std::f64::consts::SQRT_2;
pub const PI: f64 = std::f64::consts::PI;
pub const TAU: f64 = std::f64::consts::TAU;
pub const LN_2: f64 = std::f64::consts::LN_2;
pub const LN_10: f64 = std::f64::consts::LN_10;
#[inline]
pub fn clamp<T: Num>(x0: T, x1: T, x: T) -> T {
x.max(x0).min(x1)
}
#[inline]
pub fn clamp01<T: Num>(x: T) -> T {
x.max(T::zero()).min(T::one())
}
#[inline]
pub fn clamp11<T: Num>(x: T) -> T {
x.max(T::new(-1)).min(T::one())
}
#[inline]
pub fn id<T>(x: T) -> T {
x
}
#[inline]
pub fn squared<T: Num>(x: T) -> T {
x * x
}
#[inline]
pub fn cubed<T: Num>(x: T) -> T {
x * x * x
}
pub trait Lerp<T> {
fn lerp(self, other: Self, t: T) -> Self;
}
impl<U, T> Lerp<T> for U
where
U: Add<Output = U> + Mul<T, Output = U>,
T: Num,
{
#[inline]
fn lerp(self, other: U, t: T) -> U {
self * (T::one() - t) + other * t
}
}
#[inline]
pub fn lerp<U: Lerp<T>, T>(a: U, b: U, t: T) -> U {
a.lerp(b, t)
}
#[inline]
pub fn lerp11<U: Lerp<T>, T: Num>(a: U, b: U, t: T) -> U {
a.lerp(b, t * T::from_f32(0.5) + T::from_f32(0.5))
}
#[inline]
pub fn delerp<T: Num>(a: T, b: T, x: T) -> T {
(x - a) / (b - a)
}
#[inline]
pub fn delerp11<T: Num>(a: T, b: T, x: T) -> T {
(x - a) / (b - a) * T::new(2) - T::new(1)
}
#[inline]
pub fn xerp<U: Lerp<T> + Real, T>(a: U, b: U, t: T) -> U {
exp(lerp(log(a), log(b), t))
}
#[inline]
pub fn xerp11<U: Lerp<T> + Real, T: Num>(a: U, b: U, t: T) -> U {
exp(lerp(
log(a),
log(b),
t * T::from_f32(0.5) + T::from_f32(0.5),
))
}
#[inline]
pub fn dexerp<T: Real>(a: T, b: T, x: T) -> T {
log(x / a) / log(b / a)
}
#[inline]
pub fn dexerp11<T: Real>(a: T, b: T, x: T) -> T {
log(x / a) / log(b / a) * T::new(2) - T::new(1)
}
#[inline]
pub fn dissonance<T: Real>(f0: T, f1: T) -> T {
let q = abs(f0 - f1) / (T::from_f64(0.021) * min(f0, f1) + T::from_f64(19.0));
T::from_f64(5.531753) * (exp(T::from_f64(-0.84) * q) - exp(T::from_f64(-1.38) * q))
}
#[inline]
pub fn dissonance_max<T: Num>(f: T) -> T {
T::from_f64(1.0193) * f + T::from_f64(17.4672)
}
#[inline]
pub fn db_amp<T: Real>(db: T) -> T {
exp10(db / T::new(20))
}
#[inline]
pub fn amp_db<T: Real>(gain: T) -> T {
log10(gain) * T::new(20)
}
#[inline]
pub fn a_weight<T: Real>(f: T) -> T {
let f2 = squared(f);
let c0 = squared(T::from_f64(12194.0));
let c1 = squared(T::from_f64(20.6));
let c2 = squared(T::from_f64(107.7));
let c3 = squared(T::from_f64(737.9));
let c4 = T::from_f64(1.2589048990582914);
c4 * c0 * f2 * f2 / ((f2 + c1) * sqrt((f2 + c2) * (f2 + c3)) * (f2 + c0))
}
#[inline]
pub fn m_weight<T: Real>(f: T) -> T {
let c0 = T::from_f64(1.246332637532143 * 1.0e-4);
let c1 = T::from_f64(-4.737338981378384 * 1.0e-24);
let c2 = T::from_f64(2.04382833606125 * 1.0e-15);
let c3 = T::from_f64(-1.363894795463638 * 1.0e-7);
let c4 = T::from_f64(1.306612257412824 * 1.0e-19);
let c5 = T::from_f64(-2.118150887518656 * 1.0e-11);
let c6 = T::from_f64(5.559488023498642 * 1.0e-4);
let c7 = T::from_f64(8.164578311186197);
let f2 = f * f;
let f4 = f2 * f2;
c7 * c0 * f
/ sqrt(
squared(c1 * f4 * f2 + c2 * f4 + c3 * f2 + T::one())
+ squared(c4 * f4 * f + c5 * f2 * f + c6 * f),
)
}
#[inline]
pub fn spline<T: Num>(y0: T, y1: T, y2: T, y3: T, x: T) -> T {
y1 + x / T::new(2)
* (y2 - y0
+ x * (T::new(2) * y0 - T::new(5) * y1 + T::new(4) * y2 - y3
+ x * (T::new(3) * (y1 - y2) + y3 - y0)))
}
pub fn spline_mono<T: Num>(y0: T, y1: T, y2: T, y3: T, x: T) -> T {
let d0 = y1 - y0;
let d1 = y2 - y1;
let d2 = y3 - y2;
let d1d = (signum(d0) + signum(d1)) * min(d0 + d1, min(abs(d0), abs(d1)));
let d2d = (signum(d1) + signum(d2)) * min(d1 + d2, min(abs(d1), abs(d2)));
x * x * x * (T::new(2) * y1 - T::new(2) * y2 + d1d + d2d)
+ x * x * (T::new(-3) * y1 + T::new(3) * y2 - T::new(2) * d1d - d2d)
+ x * d1d
+ y1
}
#[inline]
pub fn softsign<T: Num>(x: T) -> T {
x / (T::one() + x.abs())
}
#[inline]
pub fn softexp<T: Num>(x: T) -> T {
let p = max(x, T::zero());
p * p + p + T::one() / (T::one() + p - x)
}
#[inline]
pub fn softmix<T: Num>(x: T, y: T, bias: T) -> T {
let xw = softexp(x * bias);
let yw = softexp(y * bias);
let epsilon = T::from_f32(1.0e-10);
(x * xw + y * yw) / (xw + yw + epsilon)
}
#[inline]
pub fn smooth3<T: Num>(x: T) -> T {
(T::new(3) - T::new(2) * x) * x * x
}
#[inline]
pub fn smooth5<T: Num>(x: T) -> T {
((x * T::new(6) - T::new(15)) * x + T::new(10)) * x * x * x
}
#[inline]
pub fn smooth7<T: Num>(x: T) -> T {
let x2 = x * x;
x2 * x2 * (T::new(35) - T::new(84) * x + (T::new(70) - T::new(20) * x) * x2)
}
#[inline]
pub fn smooth9<T: Num>(x: T) -> T {
let x2 = x * x;
((((T::new(70) * x - T::new(315)) * x + T::new(540)) * x - T::new(420)) * x + T::new(126))
* x2
* x2
* x
}
#[inline]
pub fn uparc<T: Real>(x: T) -> T {
T::one() - sqrt(max(T::zero(), T::one() - x * x))
}
#[inline]
pub fn downarc<T: Real>(x: T) -> T {
sqrt(max(T::new(0), (T::new(2) - x) * x))
}
#[inline]
pub fn sin_hz<T: Real>(hz: T, t: T) -> T {
sin(t * hz * T::from_f64(TAU))
}
#[inline]
pub fn cos_hz<T: Real>(hz: T, t: T) -> T {
cos(t * hz * T::from_f64(TAU))
}
#[inline]
pub fn semitone_ratio<T: Real>(x: T) -> T {
exp2(x / T::from_f64(12.0))
}
#[inline]
pub fn rnd(x: i64) -> f64 {
let x = x as u64 ^ 0x5555555555555555;
let x = x.wrapping_mul(0x9e3779b97f4a7c15);
let x = (x ^ (x >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
let x = (x ^ (x >> 27)).wrapping_mul(0x94d049bb133111eb);
let x = x ^ (x >> 31);
(x >> 11) as f64 / (1u64 << 53) as f64
}
#[inline]
pub fn rnd2(x: i64) -> f64 {
let x = funutd::hash::hash64g(x as u64);
(x >> 11) as f64 / (1u64 << 53) as f64
}
#[inline]
pub fn hash(x: i64) -> i64 {
let x = x as u64 ^ 0x5555555555555555;
let x = x.wrapping_mul(0x517cc1b727220a95);
let x = (x ^ (x >> 32)).wrapping_mul(0xd6e8feb86659fd93);
let x = (x ^ (x >> 32)).wrapping_mul(0xd6e8feb86659fd93);
(x ^ (x >> 32)) as i64
}
#[inline]
pub fn midi_hz<T: Real>(x: T) -> T {
T::new(440) * exp2((x - T::new(69)) / T::new(12))
}
#[inline]
pub fn bpm_hz<T: Real>(bpm: T) -> T {
bpm / T::new(60)
}
#[derive(Default, Clone)]
pub struct AttoHash {
state: u64,
}
impl AttoHash {
#[inline(always)]
pub fn new(seed: u64) -> AttoHash {
AttoHash { state: seed }
}
#[inline(always)]
pub fn state(&self) -> u64 {
self.state
}
#[inline]
pub fn hash(self, data: u64) -> Self {
AttoHash {
state: self
.state
.rotate_left(5)
.bitxor(data)
.wrapping_mul(0x517cc1b727220a95),
}
}
#[inline]
pub fn hash01<T: Float>(self) -> T {
let x = funutd::hash::hash64a(self.state);
T::from_f64((x >> 11) as f64 / (1u64 << 53) as f64)
}
#[inline]
pub fn hash11<T: Float>(self) -> T {
let x = funutd::hash::hash64a(self.state);
T::from_f64((x >> 10) as f64 / (1u64 << 53) as f64 - 1.0)
}
}
pub trait SegmentInterpolator<T: Float>: Clone {
fn interpolate(&self, x1: T, y1: T, x2: T, y2: T, t: T) -> T;
}
impl<T: Float, X> SegmentInterpolator<T> for X
where
X: Fn(T) -> T + Clone,
{
#[inline]
fn interpolate(&self, _x1: T, y1: T, _x2: T, y2: T, t: T) -> T {
lerp(y1, y2, (*self)(t))
}
}
impl<T: Float, X, Y> SegmentInterpolator<T> for (X, Y)
where
X: SegmentInterpolator<T>,
Y: SegmentInterpolator<T>,
{
#[inline]
fn interpolate(&self, x1: T, y1: T, x2: T, y2: T, t: T) -> T {
if y2 >= y1 {
self.0.interpolate(x1, y1, x2, y2, t)
} else {
self.1.interpolate(x1, y1, x2, y2, t)
}
}
}
pub fn ease_noise<T: Float>(ease: impl SegmentInterpolator<T>, seed: i64, x: T) -> T {
let fx = floor(x);
let dx = x - fx;
let ix = fx.to_i64();
fn get_point<T: Float>(seed: i64, i: i64) -> T {
AttoHash::new(seed as u64).hash(i as u64).hash11()
}
let y1 = get_point(seed, ix);
let y2 = get_point(seed, ix.wrapping_add(1));
ease.interpolate(fx, y1, fx + T::one(), y2, dx)
}
pub fn spline_noise<T: Float>(seed: i64, x: T) -> T {
let fx = floor(x);
let dx = x - fx;
let ix = fx.to_i64();
fn get_point<T: Float>(seed: i64, i: i64) -> T {
AttoHash::new(seed as u64).hash(i as u64).hash11()
}
let y0 = get_point(seed, ix.wrapping_sub(1));
let y1 = get_point(seed, ix);
let y2 = get_point(seed, ix.wrapping_add(1));
let y3 = get_point(seed, ix.wrapping_add(2));
spline(y0, y1, y2, y3, dx) / T::from_f32(1.25)
}
pub fn fractal_noise<T: Float>(seed: i64, octaves: i64, roughness: T, x: T) -> T {
assert!(octaves > 0);
let mut octave_weight = T::one();
let mut total_weight = T::zero();
let mut frequency = T::one();
let mut result = T::zero();
let mut rnd = Rnd::from_u64(seed as u64);
for _octave in 0..octaves {
let octave_x = x * frequency + T::from_f32(rnd.f32());
result += octave_weight * spline_noise(rnd.i64(), octave_x);
total_weight += octave_weight;
octave_weight *= roughness;
frequency *= T::new(2);
}
result / total_weight
}
pub fn fractal_ease_noise<T: Float>(
ease: impl SegmentInterpolator<T>,
seed: i64,
octaves: i64,
roughness: T,
x: T,
) -> T {
assert!(octaves > 0);
let mut octave_weight = T::one();
let mut total_weight = T::zero();
let mut frequency = T::one();
let mut result = T::zero();
let mut rnd = Rnd::from_u64(seed as u64);
for _octave in 0..octaves {
let octave_x = x * frequency + T::from_f32(rnd.f32());
result += octave_weight * ease_noise(ease.clone(), rnd.i64(), octave_x);
total_weight += octave_weight;
octave_weight *= roughness;
frequency *= T::new(2);
}
result / total_weight
}