Skip to main content

nice_plug_core/params/
internals.rs

1//! Implementation details for the parameter management.
2
3use super::{InternalParamMut, Param, ParamFlags};
4
5/// Internal pointers to parameters. This is an implementation detail used by the wrappers for type
6/// erasure.
7#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
8pub enum ParamPtr {
9    FloatParam(*const super::FloatParam),
10    IntParam(*const super::IntParam),
11    BoolParam(*const super::BoolParam),
12    /// Since we can't encode the actual enum here, this inner parameter struct contains all of the
13    /// relevant information from the enum so it can be type erased.
14    EnumParam(*const super::enums::EnumParamInner),
15}
16
17// These pointers only point to fields on structs kept in an `Arc<dyn Params>`, and the caller
18// always needs to make sure that dereferencing them is safe. To do that the plugin wrappers will
19// keep references to that `Arc` around for the entire lifetime of the plugin.
20unsafe impl Send for ParamPtr {}
21unsafe impl Sync for ParamPtr {}
22
23/// Generate a [`ParamPtr`] function that forwards the function call to the underlying `Param`. We
24/// can't have an `.as_param()` function since the return type would differ depending on the
25/// underlying parameter type, so instead we need to type erase all of the functions individually.
26macro_rules! param_ptr_forward(
27    ($vis:vis unsafe fn $method:ident(&self $(, $arg_name:ident: $arg_ty:ty)*) $(-> $ret:ty)?) => {
28        /// Calls the corresponding method on the underlying [`Param`] object.
29        ///
30        /// # Safety
31        ///
32        /// Calling this function is only safe as long as the object this [`ParamPtr`] was created
33        /// for is still alive.
34        $vis unsafe fn $method(&self $(, $arg_name: $arg_ty)*) $(-> $ret)? {
35            unsafe {
36                match self {
37                    ParamPtr::FloatParam(p) => (**p).$method($($arg_name),*),
38                    ParamPtr::IntParam(p) => (**p).$method($($arg_name),*),
39                    ParamPtr::BoolParam(p) => (**p).$method($($arg_name),*),
40                    ParamPtr::EnumParam(p) => (**p).$method($($arg_name),*),
41                }
42            }
43        }
44    };
45    // XXX: Is there a way to combine these two? Hygienic macros don't let you call `&self` without
46    //      it being defined in the macro.
47    ($vis:vis unsafe fn $method:ident(&mut self $(, $arg_name:ident: $arg_ty:ty)*) $(-> $ret:ty)?) => {
48        /// Calls the corresponding method on the underlying [`Param`] object.
49        ///
50        /// # Safety
51        ///
52        /// Calling this function is only safe as long as the object this [`ParamPtr`] was created
53        /// for is still alive.
54        $vis unsafe fn $method(&mut self $(, $arg_name: $arg_ty)*) $(-> $ret)? {
55            match self {
56                ParamPtr::FloatParam(p) => (**p).$method($($arg_name),*),
57                ParamPtr::IntParam(p) => (**p).$method($($arg_name),*),
58                ParamPtr::BoolParam(p) => (**p).$method($($arg_name),*),
59                ParamPtr::EnumParam(p) => (**p).$method($($arg_name),*),
60            }
61        }
62    };
63);
64
65impl ParamPtr {
66    param_ptr_forward!(pub unsafe fn name(&self) -> &str);
67    param_ptr_forward!(pub unsafe fn unit(&self) -> &'static str);
68    param_ptr_forward!(pub unsafe fn poly_modulation_id(&self) -> Option<u32>);
69    param_ptr_forward!(pub unsafe fn modulated_normalized_value(&self) -> f32);
70    param_ptr_forward!(pub unsafe fn unmodulated_normalized_value(&self) -> f32);
71    param_ptr_forward!(pub unsafe fn default_normalized_value(&self) -> f32);
72    param_ptr_forward!(pub unsafe fn step_count(&self) -> Option<usize>);
73    param_ptr_forward!(pub unsafe fn previous_normalized_step(&self, from: f32, finer: bool) -> f32);
74    param_ptr_forward!(pub unsafe fn next_normalized_step(&self, from: f32, finer: bool) -> f32);
75    param_ptr_forward!(pub unsafe fn normalized_value_to_string(&self, normalized: f32, include_unit: bool) -> String);
76    param_ptr_forward!(pub unsafe fn string_to_normalized_value(&self, string: &str) -> Option<f32>);
77    param_ptr_forward!(pub unsafe fn flags(&self) -> ParamFlags);
78
79    param_ptr_forward!(pub unsafe fn _internal_set_normalized_value(&self, normalized: f32) -> bool);
80    param_ptr_forward!(pub unsafe fn _internal_modulate_value(&self, modulation_offset: f32) -> bool);
81    param_ptr_forward!(pub unsafe fn _internal_update_smoother(&self, sample_rate: f32, reset: bool));
82
83    // These functions involve casts since the plugin formats only do floating point types, so we
84    // can't generate them with the macro:
85
86    /// Get the parameter's plain, unnormalized value, converted to a float. Useful in conjunction
87    /// with [`preview_plain()`][Self::preview_plain()] to compare a snapped discrete value to a
88    /// parameter's current snapped value without having to do a back and forth conversion using
89    /// normalized values.
90    ///
91    /// # Safety
92    ///
93    /// Calling this function is only safe as long as the object this `ParamPtr` was created for is
94    /// still alive.
95    pub unsafe fn modulated_plain_value(&self) -> f32 {
96        unsafe {
97            match self {
98                ParamPtr::FloatParam(p) => (**p).modulated_plain_value(),
99                ParamPtr::IntParam(p) => (**p).modulated_plain_value() as f32,
100                ParamPtr::BoolParam(p) => (**p).modulated_normalized_value(),
101                ParamPtr::EnumParam(p) => (**p).modulated_plain_value() as f32,
102            }
103        }
104    }
105
106    /// Get the parameter's plain, unnormalized value, converted to a float, before any monophonic
107    /// host modulation has been applied. This is useful for handling modulated parameters for CLAP
108    /// plugins in Bitwig in a way where the actual parameter does not move in the GUI while the
109    /// parameter is being modulated. You can also use this to show the difference between the
110    /// unmodulated value and the current value. Useful in conjunction with
111    /// [`preview_plain()`][Self::preview_plain()] to compare a snapped discrete value to a
112    /// parameter's current snapped value without having to do a back and forth conversion using
113    /// normalized values.
114    ///
115    /// # Safety
116    ///
117    /// Calling this function is only safe as long as the object this `ParamPtr` was created for is
118    /// still alive.
119    pub unsafe fn unmodulated_plain_value(&self) -> f32 {
120        unsafe {
121            match self {
122                ParamPtr::FloatParam(p) => (**p).unmodulated_plain_value(),
123                ParamPtr::IntParam(p) => (**p).unmodulated_plain_value() as f32,
124                ParamPtr::BoolParam(p) => (**p).unmodulated_normalized_value(),
125                ParamPtr::EnumParam(p) => (**p).unmodulated_plain_value() as f32,
126            }
127        }
128    }
129
130    /// Get the parameter's default value as a plain, unnormalized value, converted to a float.
131    ///
132    /// # Safety
133    ///
134    /// Calling this function is only safe as long as the object this `ParamPtr` was created for is
135    /// still alive.
136    pub unsafe fn default_plain_value(&self) -> f32 {
137        unsafe {
138            match self {
139                ParamPtr::FloatParam(p) => (**p).default_plain_value(),
140                ParamPtr::IntParam(p) => (**p).default_plain_value() as f32,
141                ParamPtr::BoolParam(p) => (**p).modulated_normalized_value(),
142                ParamPtr::EnumParam(p) => (**p).default_plain_value() as f32,
143            }
144        }
145    }
146
147    /// Get the normalized value for a plain, unnormalized value, as a float. Used as part of the
148    /// wrappers.
149    ///
150    /// # Safety
151    ///
152    /// Calling this function is only safe as long as the object this `ParamPtr` was created for is
153    /// still alive.
154    pub unsafe fn preview_normalized(&self, plain: f32) -> f32 {
155        unsafe {
156            match self {
157                ParamPtr::FloatParam(p) => (**p).preview_normalized(plain),
158                ParamPtr::IntParam(p) => (**p).preview_normalized(plain as i32),
159                ParamPtr::BoolParam(_) => plain,
160                ParamPtr::EnumParam(p) => (**p).preview_normalized(plain as i32),
161            }
162        }
163    }
164
165    /// Get the plain, unnormalized value for a normalized value, as a float. Used as part of the
166    /// wrappers.
167    ///
168    /// # Safety
169    ///
170    /// Calling this function is only safe as long as the object this `ParamPtr` was created for is
171    /// still alive.
172    pub unsafe fn preview_plain(&self, normalized: f32) -> f32 {
173        unsafe {
174            match self {
175                ParamPtr::FloatParam(p) => (**p).preview_plain(normalized),
176                ParamPtr::IntParam(p) => (**p).preview_plain(normalized) as f32,
177                ParamPtr::BoolParam(_) => normalized,
178                ParamPtr::EnumParam(p) => (**p).preview_plain(normalized) as f32,
179            }
180        }
181    }
182}