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}