#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
#![allow(
clippy::precedence,
clippy::type_complexity,
clippy::float_cmp,
clippy::len_zero,
clippy::double_neg,
clippy::needless_range_loop,
clippy::manual_range_contains,
clippy::too_many_arguments,
clippy::comparison_chain
)]
use numeric_array::{ArrayLength, NumericArray};
use typenum::{U1, U4, U8};
use core::cmp::PartialEq;
use core::marker::{Send, Sync};
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
use wide::{f32x8, f64x4, i32x8, u32x8};
pub trait Size<T>: ArrayLength + Sync + Send + Clone {}
impl<T, A: ArrayLength + Sync + Send + Clone> Size<T> for A {}
pub type Frame<T, Size> = NumericArray<T, Size>;
pub const DEFAULT_SR: f64 = 44_100.0;
pub const MAX_BUFFER_LOG: usize = 6;
pub const MAX_BUFFER_SIZE: usize = 1 << MAX_BUFFER_LOG;
pub type F32x = f32x8;
pub type U32x = u32x8;
pub type I32x = i32x8;
pub const SIMD_S: usize = 3;
pub const SIMD_N: usize = 1 << SIMD_S;
pub const SIMD_M: usize = SIMD_N - 1;
pub const SIMD_C: usize = MAX_BUFFER_LOG - SIMD_S;
pub const SIMD_LEN: usize = MAX_BUFFER_SIZE / SIMD_N;
#[inline(always)]
pub fn simd_items(samples: usize) -> usize {
(samples + SIMD_M) >> SIMD_S
}
#[inline(always)]
pub fn full_simd_items(samples: usize) -> usize {
samples >> SIMD_S
}
pub trait Num:
Copy
+ Default
+ Send
+ Sync
+ core::fmt::Display
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ AddAssign
+ MulAssign
+ SubAssign
+ DivAssign
+ PartialEq
{
type Size: ArrayLength + Send + Sync;
fn zero() -> Self;
fn one() -> Self;
fn new(x: i64) -> Self;
fn from_f64(x: f64) -> Self;
fn from_f32(x: f32) -> Self;
fn abs(self) -> Self;
fn signum(self) -> Self;
fn min(self, other: Self) -> Self;
fn max(self, other: Self) -> Self;
fn pow(self, other: Self) -> Self;
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn round(self) -> Self;
}
macro_rules! impl_signed_num {
( $($t:ty),* ) => {
$( impl Num for $t {
type Size = U1;
#[inline(always)] fn zero() -> Self { 0 }
#[inline(always)] fn one() -> Self { 1 }
#[inline(always)] fn new(x: i64) -> Self { x as Self }
#[inline(always)] fn from_f64(x: f64) -> Self { x as Self }
#[inline(always)] fn from_f32(x: f32) -> Self { x as Self }
#[inline(always)] fn abs(self) -> Self { <$t>::abs(self) }
#[inline(always)] fn signum(self) -> Self { <$t>::signum(self) }
#[inline(always)] fn min(self, other: Self) -> Self { core::cmp::min(self, other) }
#[inline(always)] fn max(self, other: Self) -> Self { core::cmp::max(self, other) }
#[inline(always)] fn pow(self, other: Self) -> Self { <$t>::pow(self, other as u32) }
#[inline(always)] fn floor(self) -> Self { self }
#[inline(always)] fn ceil(self) -> Self { self }
#[inline(always)] fn round(self) -> Self { self }
}) *
}
}
impl_signed_num! { i8, i16, i32, i64, i128, isize }
macro_rules! impl_unsigned_num {
( $($t:ty),* ) => {
$( impl Num for $t {
type Size = U1;
#[inline(always)] fn zero() -> Self { 0 }
#[inline(always)] fn one() -> Self { 1 }
#[inline(always)] fn new(x: i64) -> Self { x as Self }
#[inline(always)] fn from_f64(x: f64) -> Self { x as Self }
#[inline(always)] fn from_f32(x: f32) -> Self { x as Self }
#[inline(always)] fn abs(self) -> Self { self }
#[inline(always)] fn signum(self) -> Self { 1 }
#[inline(always)] fn min(self, other: Self) -> Self { core::cmp::min(self, other) }
#[inline(always)] fn max(self, other: Self) -> Self { core::cmp::max(self, other) }
#[inline(always)] fn pow(self, other: Self) -> Self { <$t>::pow(self, other as u32) }
#[inline(always)] fn floor(self) -> Self { self }
#[inline(always)] fn ceil(self) -> Self { self }
#[inline(always)] fn round(self) -> Self { self }
}) *
}
}
impl_unsigned_num! { u8, u16, u32, u64, u128, usize }
impl Num for f32 {
type Size = U1;
#[inline(always)]
fn zero() -> Self {
0.0
}
#[inline(always)]
fn one() -> Self {
1.0
}
#[inline(always)]
fn new(x: i64) -> Self {
x as Self
}
#[inline(always)]
fn from_f64(x: f64) -> Self {
x as Self
}
#[inline(always)]
fn from_f32(x: f32) -> Self {
x as Self
}
#[inline(always)]
fn abs(self) -> Self {
libm::fabsf(self)
}
#[inline(always)]
fn signum(self) -> Self {
libm::copysignf(1.0, self)
}
#[inline(always)]
fn min(self, other: Self) -> Self {
self.min(other)
}
#[inline(always)]
fn max(self, other: Self) -> Self {
self.max(other)
}
#[inline(always)]
fn pow(self, other: Self) -> Self {
libm::powf(self, other)
}
#[inline(always)]
fn floor(self) -> Self {
libm::floorf(self)
}
#[inline(always)]
fn ceil(self) -> Self {
libm::ceilf(self)
}
#[inline(always)]
fn round(self) -> Self {
libm::roundf(self)
}
}
impl Num for f64 {
type Size = U1;
#[inline(always)]
fn zero() -> Self {
0.0
}
#[inline(always)]
fn one() -> Self {
1.0
}
#[inline(always)]
fn new(x: i64) -> Self {
x as Self
}
#[inline(always)]
fn from_f64(x: f64) -> Self {
x as Self
}
#[inline(always)]
fn from_f32(x: f32) -> Self {
x as Self
}
#[inline(always)]
fn abs(self) -> Self {
libm::fabs(self)
}
#[inline(always)]
fn signum(self) -> Self {
libm::copysign(1.0, self)
}
#[inline(always)]
fn min(self, other: Self) -> Self {
self.min(other)
}
#[inline(always)]
fn max(self, other: Self) -> Self {
self.max(other)
}
#[inline(always)]
fn pow(self, other: Self) -> Self {
libm::pow(self, other)
}
#[inline(always)]
fn floor(self) -> Self {
libm::floor(self)
}
#[inline(always)]
fn ceil(self) -> Self {
libm::ceil(self)
}
#[inline(always)]
fn round(self) -> Self {
libm::round(self)
}
}
impl Num for F32x {
type Size = U8;
#[inline(always)]
fn zero() -> Self {
F32x::ZERO
}
#[inline(always)]
fn one() -> Self {
F32x::ONE
}
#[inline(always)]
fn new(x: i64) -> Self {
F32x::splat(x as f32)
}
#[inline(always)]
fn from_f64(x: f64) -> Self {
F32x::splat(x as f32)
}
#[inline(always)]
fn from_f32(x: f32) -> Self {
F32x::splat(x)
}
#[inline(always)]
fn abs(self) -> Self {
self.abs()
}
#[inline(always)]
fn signum(self) -> Self {
F32x::ONE.copysign(self)
}
#[inline(always)]
fn min(self, other: Self) -> Self {
self.fast_min(other)
}
#[inline(always)]
fn max(self, other: Self) -> Self {
self.fast_max(other)
}
#[inline(always)]
fn pow(self, other: Self) -> Self {
self.pow_f32x8(other)
}
#[inline(always)]
fn floor(self) -> Self {
(self - 0.4999999).round()
}
#[inline(always)]
fn ceil(self) -> Self {
(self + 0.4999999).round()
}
#[inline(always)]
fn round(self) -> Self {
self.round()
}
}
impl Num for f64x4 {
type Size = U4;
#[inline(always)]
fn zero() -> Self {
wide::f64x4::ZERO
}
#[inline(always)]
fn one() -> Self {
wide::f64x4::ONE
}
#[inline(always)]
fn new(x: i64) -> Self {
wide::f64x4::splat(x as f64)
}
#[inline(always)]
fn from_f64(x: f64) -> Self {
wide::f64x4::splat(x)
}
#[inline(always)]
fn from_f32(x: f32) -> Self {
wide::f64x4::splat(x as f64)
}
#[inline(always)]
fn abs(self) -> Self {
self.abs()
}
#[inline(always)]
fn signum(self) -> Self {
wide::f64x4::ONE.copysign(self)
}
#[inline(always)]
fn min(self, other: Self) -> Self {
self.fast_min(other)
}
#[inline(always)]
fn max(self, other: Self) -> Self {
self.fast_max(other)
}
#[inline(always)]
fn pow(self, other: Self) -> Self {
self.pow_f64x4(other)
}
#[inline(always)]
fn floor(self) -> Self {
(self - 0.4999999).round()
}
#[inline(always)]
fn ceil(self) -> Self {
(self + 0.4999999).round()
}
#[inline(always)]
fn round(self) -> Self {
self.round()
}
}
pub trait Int:
Num
+ PartialOrd
+ Not<Output = Self>
+ BitAnd<Output = Self>
+ BitOr<Output = Self>
+ BitXor<Output = Self>
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
{
fn wrapping_add(self, other: Self) -> Self;
fn wrapping_sub(self, other: Self) -> Self;
fn wrapping_mul(self, other: Self) -> Self;
}
macro_rules! impl_int {
( $($t:ty),* ) => {
$( impl Int for $t {
#[inline(always)] fn wrapping_add(self, other: Self) -> Self { <$t>::wrapping_add(self, other) }
#[inline(always)] fn wrapping_sub(self, other: Self) -> Self { <$t>::wrapping_sub(self, other) }
#[inline(always)] fn wrapping_mul(self, other: Self) -> Self { <$t>::wrapping_mul(self, other) }
}) *
}
}
impl_int! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize }
pub trait Float: Num + Neg<Output = Self> {
const PI: Self;
const TAU: Self;
const SQRT_2: Self;
fn from_float<T: Float>(x: T) -> Self;
fn to_f64(self) -> f64;
fn to_f32(self) -> f32;
fn to_i64(self) -> i64;
fn tan(self) -> Self;
fn exp(self) -> Self;
fn sin(self) -> Self;
fn cos(self) -> Self;
fn sqrt(self) -> Self;
fn reduce_add(self) -> f32;
fn from_frame(frame: &Frame<f32, Self::Size>) -> Self;
fn to_frame(self) -> Frame<f32, Self::Size>;
fn set(&mut self, index: usize, value: f32);
fn get(&self, index: usize) -> f32;
}
impl Float for f32 {
const PI: Self = core::f32::consts::PI;
const TAU: Self = core::f32::consts::TAU;
const SQRT_2: Self = core::f32::consts::SQRT_2;
#[inline(always)]
fn from_float<T: Float>(x: T) -> Self {
x.to_f32()
}
#[inline(always)]
fn to_f64(self) -> f64 {
self as f64
}
#[inline(always)]
fn to_f32(self) -> f32 {
self
}
#[inline(always)]
fn to_i64(self) -> i64 {
self as i64
}
#[inline(always)]
fn tan(self) -> Self {
libm::tanf(self)
}
#[inline(always)]
fn exp(self) -> Self {
libm::expf(self)
}
#[inline(always)]
fn sin(self) -> Self {
libm::sinf(self)
}
#[inline(always)]
fn cos(self) -> Self {
libm::cosf(self)
}
#[inline(always)]
fn sqrt(self) -> Self {
libm::sqrtf(self)
}
#[inline(always)]
fn reduce_add(self) -> f32 {
self
}
#[inline(always)]
fn from_frame(frame: &Frame<f32, Self::Size>) -> Self {
frame[0]
}
#[inline(always)]
fn to_frame(self) -> Frame<f32, Self::Size> {
[self].into()
}
#[inline(always)]
fn set(&mut self, _index: usize, value: f32) {
*self = value;
}
#[inline(always)]
fn get(&self, _index: usize) -> f32 {
*self
}
}
impl Float for f64 {
const PI: Self = core::f64::consts::PI;
const TAU: Self = core::f64::consts::TAU;
const SQRT_2: Self = core::f64::consts::SQRT_2;
#[inline(always)]
fn from_float<T: Float>(x: T) -> Self {
x.to_f64()
}
#[inline(always)]
fn to_f64(self) -> f64 {
self
}
#[inline(always)]
fn to_f32(self) -> f32 {
self as f32
}
#[inline(always)]
fn to_i64(self) -> i64 {
self as i64
}
#[inline(always)]
fn tan(self) -> Self {
libm::tan(self)
}
#[inline(always)]
fn exp(self) -> Self {
libm::exp(self)
}
#[inline(always)]
fn sin(self) -> Self {
libm::sin(self)
}
#[inline(always)]
fn cos(self) -> Self {
libm::cos(self)
}
#[inline(always)]
fn sqrt(self) -> Self {
libm::sqrt(self)
}
#[inline(always)]
fn reduce_add(self) -> f32 {
self as f32
}
#[inline(always)]
fn from_frame(frame: &Frame<f32, Self::Size>) -> Self {
frame[0] as f64
}
#[inline(always)]
fn to_frame(self) -> Frame<f32, Self::Size> {
[self as f32].into()
}
#[inline(always)]
fn set(&mut self, _index: usize, value: f32) {
*self = value as f64;
}
#[inline(always)]
fn get(&self, _index: usize) -> f32 {
*self as f32
}
}
impl Float for f32x8 {
const PI: Self = f32x8::PI;
const TAU: Self = f32x8::TAU;
const SQRT_2: Self = f32x8::SQRT_2;
#[inline(always)]
fn from_float<T: Float>(x: T) -> Self {
Self::splat(x.to_f32())
}
#[inline(always)]
fn to_f64(self) -> f64 {
0.0
}
#[inline(always)]
fn to_f32(self) -> f32 {
0.0
}
#[inline(always)]
fn to_i64(self) -> i64 {
0
}
#[inline(always)]
fn tan(self) -> Self {
f32x8::tan(self)
}
#[inline(always)]
fn exp(self) -> Self {
f32x8::exp(self)
}
#[inline(always)]
fn sin(self) -> Self {
f32x8::sin(self)
}
#[inline(always)]
fn cos(self) -> Self {
f32x8::cos(self)
}
#[inline(always)]
fn sqrt(self) -> Self {
f32x8::sqrt(self)
}
#[inline(always)]
fn reduce_add(self) -> f32 {
f32x8::reduce_add(self)
}
#[inline(always)]
fn from_frame(frame: &Frame<f32, U8>) -> Self {
f32x8::new((*frame.as_array()).into())
}
#[inline(always)]
fn to_frame(self) -> Frame<f32, U8> {
f32x8::to_array(self).into()
}
#[inline(always)]
fn set(&mut self, index: usize, value: f32) {
self.as_mut_array()[index] = value;
}
#[inline(always)]
fn get(&self, index: usize) -> f32 {
self.as_array()[index]
}
}
impl Float for f64x4 {
const PI: Self = f64x4::PI;
const TAU: Self = f64x4::TAU;
const SQRT_2: Self = f64x4::SQRT_2;
#[inline(always)]
fn from_float<T: Float>(x: T) -> Self {
Self::splat(x.to_f64())
}
#[inline(always)]
fn to_f64(self) -> f64 {
0.0
}
#[inline(always)]
fn to_f32(self) -> f32 {
0.0
}
#[inline(always)]
fn to_i64(self) -> i64 {
0
}
#[inline(always)]
fn tan(self) -> Self {
f64x4::tan(self)
}
#[inline(always)]
fn exp(self) -> Self {
f64x4::exp(self)
}
#[inline(always)]
fn sin(self) -> Self {
f64x4::sin(self)
}
#[inline(always)]
fn cos(self) -> Self {
f64x4::cos(self)
}
#[inline(always)]
fn sqrt(self) -> Self {
f64x4::sqrt(self)
}
#[inline(always)]
fn reduce_add(self) -> f32 {
f64x4::reduce_add(self) as f32
}
#[inline(always)]
fn from_frame(frame: &Frame<f32, U4>) -> Self {
let array = frame.as_array();
let f64_array = [
f64::from(array[0]),
f64::from(array[1]),
f64::from(array[2]),
f64::from(array[3]),
];
f64x4::new(f64_array)
}
#[inline(always)]
fn to_frame(self) -> Frame<f32, U4> {
let array_f64: [f64; 4] = f64x4::to_array(self);
let array_f32: [f32; 4] = array_f64.map(|x| x as f32);
array_f32.into()
}
#[inline(always)]
fn set(&mut self, index: usize, value: f32) {
self.as_mut_array()[index] = value as f64;
}
#[inline(always)]
fn get(&self, index: usize) -> f32 {
self.as_array()[index] as f32
}
}
#[inline(always)]
pub fn convert<T: Float, U: Float>(x: T) -> U {
U::from_float(x)
}
pub trait Real: Float + PartialOrd {
fn exp2(self) -> Self;
fn log(self) -> Self;
fn log2(self) -> Self;
fn log10(self) -> Self;
fn tanh(self) -> Self;
fn atan(self) -> Self;
}
impl Real for f32 {
#[inline(always)]
fn exp2(self) -> Self {
libm::exp2f(self)
}
#[inline(always)]
fn log(self) -> Self {
libm::logf(self)
}
#[inline(always)]
fn log2(self) -> Self {
libm::log2f(self)
}
#[inline(always)]
fn log10(self) -> Self {
libm::log10f(self)
}
#[inline(always)]
fn tanh(self) -> Self {
libm::tanhf(self)
}
#[inline(always)]
fn atan(self) -> Self {
libm::atanf(self)
}
}
impl Real for f64 {
#[inline(always)]
fn exp2(self) -> Self {
libm::exp2(self)
}
#[inline(always)]
fn log(self) -> Self {
libm::log(self)
}
#[inline(always)]
fn log2(self) -> Self {
libm::log2(self)
}
#[inline(always)]
fn log10(self) -> Self {
libm::log10(self)
}
#[inline(always)]
fn tanh(self) -> Self {
libm::tanh(self)
}
#[inline(always)]
fn atan(self) -> Self {
libm::atan(self)
}
}
pub mod adsr;
pub mod audionode;
pub mod audiounit;
pub mod biquad;
pub mod biquad_bank;
pub mod buffer;
pub mod combinator;
pub mod delay;
pub mod denormal;
pub mod dynamics;
pub mod envelope;
pub mod feedback;
pub mod fft;
pub mod filter;
pub mod fir;
pub mod follow;
pub mod generate;
pub mod granular;
pub mod math;
pub mod moog;
pub mod net;
pub mod noise;
pub mod oscillator;
pub mod oversample;
pub mod pan;
pub mod prelude;
pub mod prelude32;
pub mod prelude64;
pub mod realnet;
pub mod realseq;
pub mod resample;
pub mod resynth;
pub mod reverb;
pub mod rez;
pub mod ring;
pub mod sequencer;
pub mod setting;
pub mod shape;
pub mod shared;
pub mod signal;
pub mod slot;
pub mod snoop;
pub mod sound;
pub mod svf;
pub mod system;
pub mod vertex;
pub mod wave;
pub mod wavetable;
pub use numeric_array::{
self,
generic_array::sequence::{Concat, GenericSequence},
typenum,
};
pub use funutd;
pub use thingbuf;
pub use wide;
#[cfg(feature = "std")]
pub mod write;
#[cfg(all(feature = "std", feature = "files"))]
pub mod read;
#[cfg(all(feature = "std", feature = "fft"))]
pub mod convolve;