use crate::prelude::*;
#[derive(Clone, Copy, Debug, Default)]
pub struct Saw;
impl Map for Saw {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
map::sgn(x.inner())
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct InvSaw;
impl Map for InvSaw {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
-map::sgn(x.inner())
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct PosSaw;
impl Map for PosSaw {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
x.inner()
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct PosInvSaw;
impl Map for PosInvSaw {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
1.0 - x.inner()
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Sin;
impl Map for Sin {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
(x.inner() * std::f64::consts::TAU).sin()
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Cos;
impl Cos {
#[must_use]
pub const fn new() -> Self {
Self
}
}
impl Map for Cos {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
(x.inner() * std::f64::consts::TAU).cos()
}
}
#[must_use]
pub fn pulse(x: f64, shape: f64) -> f64 {
if x < shape {
-1.0
} else {
1.0
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Sq;
impl Map for Sq {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: Self::Input) -> f64 {
pulse(x.inner(), 0.5)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Pulse {
pub shape: f64,
}
impl Pulse {
#[must_use]
pub const fn new(shape: f64) -> Self {
Self { shape }
}
#[must_use]
pub const fn sq() -> Self {
Self::new(0.5)
}
}
impl Default for Pulse {
fn default() -> Self {
Self::sq()
}
}
impl Map for Pulse {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
pulse(x.inner(), self.shape)
}
}
#[must_use]
pub fn saw_tri(x: f64, shape: unt::Val) -> f64 {
const EPS: f64 = 1e-7;
let shape = shape.inner();
if x < shape {
if shape < EPS {
1.0
} else {
buf::int::linear(-1.0, 1.0, unt::Val::new(x / shape))
}
} else if 1.0 - shape < EPS {
1.0
} else {
buf::int::linear(-1.0, 1.0, unt::Val::new((1.0 - x) / (1.0 - shape)))
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Tri;
impl Map for Tri {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
saw_tri(x.inner(), unt::Val::HALF)
}
}
#[derive(Clone, Copy, Debug)]
pub struct SawTri {
pub shape: unt::Val,
}
impl SawTri {
#[must_use]
pub const fn new(shape: unt::Val) -> Self {
Self { shape }
}
#[must_use]
pub const fn saw() -> Self {
Self::new(unt::Val::ONE)
}
#[must_use]
pub const fn tri() -> Self {
Self::new(unt::Val::HALF)
}
#[must_use]
pub const fn inv_saw() -> Self {
Self::new(unt::Val::ZERO)
}
}
impl Default for SawTri {
fn default() -> Self {
Self::tri()
}
}
impl Map for SawTri {
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
saw_tri(x.inner(), self.shape)
}
}
pub struct Morph<C: Map<Input = unt::Val, Output = f64>, D: Map<Input = unt::Val, Output = f64>> {
pub fst: C,
pub snd: D,
pub morph: unt::Val,
}
impl<C: Map<Input = unt::Val, Output = f64>, D: Map<Input = unt::Val, Output = f64>> Morph<C, D> {
pub const fn new(fst: C, snd: D, morph: unt::Val) -> Self {
Self { fst, snd, morph }
}
pub const fn fst(fst: C, snd: D) -> Self {
Self::new(fst, snd, unt::Val::ZERO)
}
pub const fn half(fst: C, snd: D) -> Self {
Self::new(fst, snd, unt::Val::HALF)
}
pub const fn snd(fst: C, snd: D) -> Self {
Self::new(fst, snd, unt::Val::ONE)
}
}
impl<C: Map<Input = unt::Val, Output = f64>, D: Map<Input = unt::Val, Output = f64>> Map
for Morph<C, D>
{
type Input = unt::Val;
type Output = f64;
fn eval(&self, x: unt::Val) -> f64 {
buf::int::linear(self.fst.eval(x), self.snd.eval(x), self.morph)
}
}