diff --git a/coupler-derive/src/lib.rs b/coupler-derive/src/lib.rs index 308ebb0..698589d 100644 --- a/coupler-derive/src/lib.rs +++ b/coupler-derive/src/lib.rs @@ -3,11 +3,9 @@ use syn::{parse_macro_input, DeriveInput}; mod enum_; mod params; -mod smooth; use enum_::expand_enum; use params::expand_params; -use smooth::expand_smooth; #[proc_macro_derive(Params, attributes(param))] pub fn derive_params(input: TokenStream) -> TokenStream { @@ -28,13 +26,3 @@ pub fn derive_enum(input: TokenStream) -> TokenStream { Err(err) => return err.into_compile_error().into(), } } - -#[proc_macro_derive(Smooth, attributes(param, smooth))] -pub fn derive_smooth(input: TokenStream) -> TokenStream { - let input: DeriveInput = parse_macro_input!(input as DeriveInput); - - match expand_smooth(&input) { - Ok(expanded) => expanded.into(), - Err(err) => return err.into_compile_error().into(), - } -} diff --git a/coupler-derive/src/smooth.rs b/coupler-derive/src/smooth.rs deleted file mode 100644 index 9f3d107..0000000 --- a/coupler-derive/src/smooth.rs +++ /dev/null @@ -1,233 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::parse::{Parse, ParseStream, Result}; -use syn::punctuated::Punctuated; -use syn::{Data, DeriveInput, Error, Expr, Field, Fields, Ident, Path, Token}; - -use super::params::{gen_decode, parse_param, ParamAttr}; - -struct SmoothAttr { - builder: Path, - args: Punctuated, -} - -impl Parse for SmoothAttr { - fn parse(input: ParseStream) -> Result { - let builder = input.parse::()?; - - let args = if input.peek(Token![,]) { - let _ = input.parse::()?; - input.parse_terminated(SmoothArg::parse, Token![,])? - } else { - Punctuated::new() - }; - - Ok(SmoothAttr { builder, args }) - } -} - -struct SmoothArg { - name: Ident, - value: Expr, -} - -impl Parse for SmoothArg { - fn parse(input: ParseStream) -> Result { - let name = input.parse::()?; - let _ = input.parse::()?; - let value = input.parse::()?; - - Ok(SmoothArg { name, value }) - } -} - -fn parse_smooth(field: &Field) -> Result> { - let mut smooth = None; - - for attr in &field.attrs { - if !attr.path().is_ident("smooth") { - continue; - } - - if smooth.is_some() { - return Err(Error::new_spanned( - attr.path(), - "duplicate `smooth` attribute", - )); - } - - smooth = Some(attr.parse_args::()?); - } - - Ok(smooth) -} - -struct SmoothField<'a> { - field: &'a Field, - param: Option, - smooth: Option, -} - -fn parse_fields(input: &DeriveInput) -> Result> { - let body = match &input.data { - Data::Struct(body) => body, - _ => { - return Err(Error::new_spanned( - &input, - "#[derive(Smooth)] can only be used on structs", - )); - } - }; - - let fields = match &body.fields { - Fields::Named(fields) => fields, - _ => { - return Err(Error::new_spanned( - &input, - "#[derive(Smooth)] can only be used on structs with named fields", - )); - } - }; - - let mut smooth_fields = Vec::new(); - - for field in &fields.named { - let param = parse_param(field)?; - let smooth = parse_smooth(field)?; - - if smooth.is_some() && !param.is_some() { - return Err(Error::new_spanned( - &field, - "smooth attribute requires param attribute", - )); - } - - smooth_fields.push(SmoothField { - field, - param, - smooth, - }); - } - - Ok(smooth_fields) -} - -pub fn expand_smooth(input: &DeriveInput) -> Result { - let fields = parse_fields(&input)?; - - let generics = &input.generics; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let ident = &input.ident; - - let smooth_fields = fields.iter().map(|field| { - let vis = &field.field.vis; - let ident = &field.field.ident; - let ty = &field.field.ty; - - let field_type = if let Some(smooth) = &field.smooth { - let builder = &smooth.builder; - quote! { <#builder as ::coupler::params::smooth::BuildSmoother<#ty>>::Smoother } - } else { - quote! { #ty } - }; - - quote! { #vis #ident: #field_type } - }); - - let smooth_fields_init = fields.iter().map(|field| { - let ident = &field.field.ident; - let ty = &field.field.ty; - - if let Some(smooth) = &field.smooth { - let builder = &smooth.builder; - - let args = smooth.args.iter().map(|arg| { - let name = &arg.name; - let value = &arg.value; - quote! { - let __builder = #builder::#name(__builder, #value); - } - }); - - quote! { - #ident: <#builder as ::coupler::params::smooth::BuildSmoother<#ty>>::build( - { - let __builder = <#builder as ::std::default::Default>::default(); - #(#args)* - __builder - }, - &self.#ident, - __sample_rate, - ) - } - } else { - quote! { #ident: ::std::clone::Clone::clone(&self.#ident) } - } - }); - - let set_cases = fields.iter().filter_map(|field| { - let param = field.param.as_ref()?; - - let ident = &field.field.ident; - let id = ¶m.id; - - let decode = gen_decode(&field.field, param, quote! { __value }); - - if field.smooth.is_some() { - Some(quote! { - #id => { - ::coupler::params::smooth::Smoother::set(&mut self.#ident, &#decode); - } - }) - } else { - Some(quote! { - #id => { - self.#ident = #decode; - } - }) - } - }); - - let reset_stmts = fields.iter().filter_map(|field| { - let ident = &field.field.ident; - - if field.param.is_none() || field.smooth.is_none() { - return None; - } - - Some(quote! { - ::coupler::params::smooth::Smoother::reset(&mut self.#ident); - }) - }); - - Ok(quote! { - const _: () = { - pub struct __Smooth #generics { - #(#smooth_fields,)* - } - - impl #impl_generics ::coupler::params::smooth::Smooth for #ident #ty_generics #where_clause { - type Smoothed = __Smooth #ty_generics; - - fn smoothed(&self, __sample_rate: f64) -> Self::Smoothed { - __Smooth { - #(#smooth_fields_init,)* - } - } - } - - impl #impl_generics ::coupler::params::smooth::SmoothParams for __Smooth #ty_generics #where_clause { - fn set_param(&mut self, __id: ParamId, __value: ParamValue) { - match __id { - #(#set_cases)* - _ => {} - } - } - - fn reset(&mut self) { - #(#reset_stmts)* - } - } - }; - }) -} diff --git a/examples/gain/src/lib.rs b/examples/gain/src/lib.rs index f86130f..b6e188b 100644 --- a/examples/gain/src/lib.rs +++ b/examples/gain/src/lib.rs @@ -4,14 +4,11 @@ use serde::{Deserialize, Serialize}; use coupler::format::clap::*; use coupler::format::vst3::*; -use coupler::{ - buffers::*, bus::*, editor::*, events::*, params::smooth::*, params::*, plugin::*, process::*, -}; +use coupler::{buffers::*, bus::*, editor::*, events::*, params::*, plugin::*, process::*}; -#[derive(Params, Smooth, Serialize, Deserialize, Clone)] +#[derive(Params, Serialize, Deserialize, Clone)] struct GainParams { #[param(id = 0, name = "Gain", range = 0.0..1.0, format = "{:.2}")] - #[smooth(Exp, ms = 10.0)] gain: f32, } @@ -81,7 +78,7 @@ impl Plugin for Gain { fn processor(&self, config: Config) -> Self::Processor { GainProcessor { - params: self.params.smoothed(config.sample_rate), + params: self.params.clone(), } } @@ -107,7 +104,7 @@ impl ClapPlugin for Gain { } pub struct GainProcessor { - params: Smoothed, + params: GainParams, } impl Processor for GainProcessor { @@ -115,9 +112,7 @@ impl Processor for GainProcessor { self.params.set_param(id, value); } - fn reset(&mut self) { - self.params.reset(); - } + fn reset(&mut self) {} fn process(&mut self, buffers: Buffers, events: Events) { let buffer: BufferMut = buffers.try_into().unwrap(); @@ -132,9 +127,8 @@ impl Processor for GainProcessor { } for sample in buffer.samples() { - let gain = self.params.gain.next(); for channel in sample { - *channel *= gain; + *channel *= self.params.gain; } } } diff --git a/src/params.rs b/src/params.rs index aca4f7e..4cb5269 100644 --- a/src/params.rs +++ b/src/params.rs @@ -5,7 +5,6 @@ use std::str::FromStr; pub use coupler_derive::{Enum, Params}; mod range; -pub mod smooth; pub use range::{Encode, Log, Range}; diff --git a/src/params/smooth.rs b/src/params/smooth.rs deleted file mode 100644 index b565b94..0000000 --- a/src/params/smooth.rs +++ /dev/null @@ -1,126 +0,0 @@ -use super::{ParamId, ParamValue, Params}; - -#[cfg(feature = "derive")] -pub use coupler_derive::Smooth; - -pub trait Smooth: Params { - type Smoothed: SmoothParams; - - fn smoothed(&self, sample_rate: f64) -> Self::Smoothed; -} - -pub type Smoothed

=

::Smoothed; - -pub trait SmoothParams { - fn set_param(&mut self, id: ParamId, value: ParamValue); - fn reset(&mut self); -} - -pub trait BuildSmoother { - type Smoother: Smoother; - - fn build(self, value: &T, sample_rate: f64) -> Self::Smoother; -} - -pub trait Smoother { - type Value; - - fn reset(&mut self); - fn set(&mut self, value: &T); - fn get(&self) -> Self::Value; - fn next(&mut self) -> Self::Value; - - #[inline] - fn fill(&mut self, slice: &mut [Self::Value]) { - for out in slice { - *out = self.next(); - } - } - - #[inline] - fn is_active(&self) -> bool { - true - } -} - -const EPSILON: f64 = 1e-3; - -pub struct Exp { - ms: f64, -} - -impl Default for Exp { - fn default() -> Exp { - Exp { ms: 10.0 } - } -} - -impl Exp { - pub fn ms(self, ms: f64) -> Self { - Exp { ms, ..self } - } -} - -pub struct ExpSmoother { - rate: T, - current: T, - target: T, -} - -macro_rules! impl_exp { - ($float:ty) => { - impl BuildSmoother<$float> for Exp { - type Smoother = ExpSmoother<$float>; - - #[inline] - fn build(self, value: &$float, sample_rate: f64) -> Self::Smoother { - let dt = 1000.0 / sample_rate; - let rate = 1.0 - (-dt / self.ms).exp(); - - ExpSmoother { - rate: rate as $float, - current: *value, - target: *value, - } - } - } - - impl Smoother<$float> for ExpSmoother<$float> { - type Value = $float; - - #[inline] - fn reset(&mut self) { - self.current = self.target; - } - - #[inline] - fn set(&mut self, value: &$float) { - self.target = *value; - } - - #[inline] - fn get(&self) -> Self::Value { - self.current - } - - #[inline] - fn next(&mut self) -> Self::Value { - if (self.target - self.current).abs() > EPSILON as $float { - self.current = (1.0 - self.rate) * self.current + self.rate * self.target; - } else { - self.current = self.target; - } - - self.current - } - - #[inline] - fn is_active(&self) -> bool { - self.current != self.target - } - } - }; -} - -impl_exp!(f32); -impl_exp!(f64);