use super::*;
use core::ops::{Add, Neg, Sub};
use fixed::traits::FromFixed;
use fixedmath::scale_fixedfloat;
pub trait DspFormat:
DspFormatBase
+ devices::osc::detail::OscOps
+ devices::env::detail::EnvOps
+ devices::filt::detail::FiltOps
+ devices::lfo::detail::LfoOps
+ voice::modulation::detail::ModulatorOps
{
}
pub trait DspFormatBase: Sized + Copy + Default + Send {
type Sample: DspType<Self>;
type Note: DspType<Self>;
type NoteOffset: DspType<Self>;
type Frequency: DspType<Self>;
type Scalar: DspType<Self>;
type IScalar: DspType<Self>;
type EnvParam: DspType<Self>;
type EnvSignal: devices::env::detail::EnvType<Self> + Send;
type Phase: DspType<Self>;
type LfoFreq: DspType<Self>;
type WideSample: Copy + Default + Add<Self::WideSample, Output = Self::WideSample>;
type Context: Send + crate::context::GetContext;
fn default_note() -> Self::Note;
fn note_to_freq(note: Self::Note) -> Self::Frequency;
fn sample_from_fixed(value: crate::IScalarFxP) -> Self::Sample;
fn sample_to_float(value: Self::Sample) -> f32;
fn widen_sample(smp: Self::Sample) -> Self::WideSample;
fn narrow_sample(wide_smp: Self::WideSample) -> Self::Sample;
fn note_from_scalar(scalar: Self::Scalar) -> Self::Note;
fn apply_note_offset(note: Self::Note, offset: Self::NoteOffset) -> Self::Note;
}
pub trait DspFloat:
crate::Float
+ Send
+ FromFixed
+ DspFormatBase<
Sample = Self,
Note = Self,
NoteOffset = Self,
Frequency = Self,
Scalar = Self,
IScalar = Self,
EnvParam = Self,
EnvSignal = Self,
Phase = Self,
LfoFreq = Self,
WideSample = Self,
Context = context::Context<Self>,
>
{
}
pub trait DspType<T: DspFormatBase>:
Copy + Default + Send + Add<Self, Output = Self> + Sub<Self, Output = Self> + PartialOrd
{
const PI: Self;
const TAU: Self;
fn zero() -> Self;
fn one() -> Self;
fn dsp_saturating_add(self, rhs: Self) -> Self;
fn multiply(self, rhs: Self) -> Self;
fn divide_by_two(self) -> Self;
fn scale(self, rhs: T::Scalar) -> Self;
}
impl<T: DspFloat> DspFormat for T {}
impl<T: Float + Send> DspFormatBase for T
where
T: From<crate::IScalarFxP> + From<crate::NoteFxP>,
{
type Sample = T;
type Note = T;
type NoteOffset = T;
type Frequency = T;
type Scalar = T;
type IScalar = T;
type EnvParam = T;
type EnvSignal = T;
type Phase = T;
type LfoFreq = T;
type WideSample = T;
type Context = context::Context<T>;
fn default_note() -> Self::Note {
Self::from_u16(69)
}
fn note_to_freq(note: Self::Note) -> Self::Frequency {
T::midi_to_freq(note)
}
fn sample_from_fixed(value: IScalarFxP) -> Self::Sample {
value.into()
}
fn sample_to_float(value: Self::Sample) -> f32 {
value.as_f32()
}
fn widen_sample(smp: Self::Sample) -> Self::WideSample {
smp
}
fn narrow_sample(wide_smp: Self::WideSample) -> Self::Sample {
wide_smp
}
fn note_from_scalar(scalar: Self::Scalar) -> Self::Note {
let note_max: Self = NoteFxP::MAX.into();
note_max * scalar
}
fn apply_note_offset(note: Self::Note, offset: Self::NoteOffset) -> Self::Note {
note + offset
}
}
impl DspFloat for f32 {}
impl DspFloat for f64 {}
impl<T: Float + Send> DspType<T> for T
where
T: From<crate::IScalarFxP> + From<crate::NoteFxP>,
{
const PI: Self = Self::PI;
const TAU: Self = Self::TAU;
fn zero() -> Self {
T::ZERO
}
fn one() -> Self {
T::ONE
}
fn dsp_saturating_add(self, rhs: Self) -> Self {
self + rhs
}
fn multiply(self, rhs: Self) -> Self {
self * rhs
}
fn divide_by_two(self) -> Self {
self / Self::TWO
}
fn scale(self, rhs: Self) -> Self {
self * rhs
}
}
impl DspFormat for i16 {}
impl DspFormatBase for i16 {
type Sample = SampleFxP;
type Note = NoteFxP;
type NoteOffset = SignedNoteFxP;
type Frequency = FrequencyFxP;
type Scalar = ScalarFxP;
type IScalar = IScalarFxP;
type EnvParam = EnvParamFxP;
type EnvSignal = devices::env::detail::EnvSignalFxP;
type Phase = PhaseFxP;
type LfoFreq = LfoFreqFxP;
type WideSample = WideSampleFxP;
type Context = context::ContextFxP;
fn default_note() -> Self::Note {
const DEFAULT: NoteFxP = NoteFxP::lit("69");
DEFAULT
}
fn note_to_freq(note: NoteFxP) -> FrequencyFxP {
crate::fixedmath::midi_note_to_frequency(note)
}
fn sample_from_fixed(value: IScalarFxP) -> Self::Sample {
SampleFxP::from_num(value)
}
fn sample_to_float(value: Self::Sample) -> f32 {
value.into()
}
fn widen_sample(smp: Self::Sample) -> Self::WideSample {
crate::fixedmath::widen_i(smp)
}
fn narrow_sample(wide_smp: Self::WideSample) -> SampleFxP {
SampleFxP::saturating_from_num(wide_smp)
}
fn note_from_scalar(scalar: ScalarFxP) -> NoteFxP {
NoteFxP::from_bits(scalar.to_bits())
}
fn apply_note_offset(note: NoteFxP, offset: SignedNoteFxP) -> NoteFxP {
note.saturating_add_signed(offset)
}
}
impl<T: Fixed16 + Send> DspType<i16> for T {
const PI: Self = T::PI;
const TAU: Self = T::TAU;
fn zero() -> Self {
Self::ZERO
}
fn one() -> Self {
Self::ONE_OR_MAX
}
fn dsp_saturating_add(self, rhs: Self) -> Self {
self.saturating_add(rhs)
}
fn multiply(self, rhs: Self) -> Self {
self.multiply_fixed(rhs)
}
fn divide_by_two(self) -> Self {
self.unwrapped_shr(1)
}
fn scale(self, rhs: ScalarFxP) -> Self {
self.scale_fixed(rhs)
}
}
impl DspType<i16> for FrequencyFxP {
const PI: Self = FrequencyFxP::PI;
const TAU: Self = FrequencyFxP::TAU;
fn zero() -> Self {
Self::ZERO
}
fn one() -> Self {
Self::ONE
}
fn dsp_saturating_add(self, rhs: Self) -> Self {
self.saturating_add(rhs)
}
fn multiply(self, rhs: Self) -> Self {
Self::from_num(self.wide_mul(rhs))
}
fn divide_by_two(self) -> Self {
self.unwrapped_shr(1)
}
fn scale(self, rhs: ScalarFxP) -> Self {
scale_fixedfloat(self, rhs)
}
}
impl DspType<i16> for PhaseFxP {
const PI: Self = PhaseFxP::PI;
const TAU: Self = PhaseFxP::TAU;
fn zero() -> Self {
Self::ZERO
}
fn one() -> Self {
Self::ONE
}
fn dsp_saturating_add(self, rhs: Self) -> Self {
self.saturating_add(rhs)
}
fn multiply(self, rhs: Self) -> Self {
Self::from_num(self.wide_mul(rhs))
}
fn divide_by_two(self) -> Self {
self.unwrapped_shr(1)
}
fn scale(self, rhs: ScalarFxP) -> Self {
let (abs, neg) = (self.unsigned_abs(), self.is_negative());
let mut scaled = Self::from_num(scale_fixedfloat(abs, rhs));
if neg {
scaled = scaled.neg();
}
scaled
}
}