#[macro_export]
macro_rules! effect_algorithm {
(
$(#[$struct_meta:meta])*
$vis:vis struct $name:ident<$($generic:ident: $bound:path),+> {
params: {
$(
$(#[$param_meta:meta])*
$param_name:ident : $param_type:ty = $param_default:expr
),* $(,)?
},
state: {
$(
$(#[$state_meta:meta])*
$state_name:ident : $state_type:ty = $state_default:expr
),* $(,)?
},
wet: $wet_default:expr,
process: $process:expr
}
) => {
$(#[$struct_meta])*
$vis struct $name<$($generic: $bound),+> {
$(
$(#[$param_meta])*
pub $param_name: $param_type,
)*
$(
$(#[$state_meta])*
pub $state_name: $state_type,
)*
pub wet: T,
pub sample_rate: f32,
}
impl<$($generic: $bound),+> $name<$($generic),+> {
pub fn new($($param_name: $param_type),*) -> Self {
Self {
$($param_name),*,
$($state_name: $state_default),*,
wet: $wet_default,
sample_rate: 44100.0,
}
}
pub fn set_wet(&mut self, wet: T) {
self.wet = wet.clamp(T::ZERO, T::ONE);
}
}
impl<$($generic: $bound),+> $crate::algorithm::Algorithm<T> for $name<$($generic),+>
where
T: rill_core::math::Transcendental,
{
fn init(&mut self, sample_rate: f32) {
self.sample_rate = sample_rate;
}
fn reset(&mut self) {
$(
self.$state_name = $state_default;
)*
}
fn process(
&mut self,
input: Option<&[T]>,
output: &mut [T],
_ctx: &$crate::algorithm::ActionContext,
) -> $crate::algorithm::ProcessResult<()> {
let input = input.unwrap_or(&[]);
let len = input.len().min(output.len());
let process_fn: fn(&mut Self, T) -> T = $process;
let wet = self.wet;
let one = T::ONE;
for i in 0..len {
let wet_signal = process_fn(self, input[i]);
let dry = input[i] * (one - wet);
let wet_mixed = wet_signal * wet;
output[i] = dry + wet_mixed;
}
Ok(())
}
fn metadata(&self) -> $crate::algorithm::AlgorithmMetadata {
$crate::algorithm::AlgorithmMetadata {
name: stringify!($name),
category: $crate::algorithm::AlgorithmCategory::Effect,
description: stringify!($name),
author: "Rill",
version: env!("CARGO_PKG_VERSION"),
}
}
}
};
}