nice_plug_core/params/
boolean.rs1use atomic_float::AtomicF32;
4use std::fmt::{Debug, Display};
5use std::sync::Arc;
6use std::sync::atomic::{AtomicBool, Ordering};
7
8use super::internals::ParamPtr;
9use super::{InternalParamMut, Param, ParamFlags, ParamInfo};
10
11pub struct BoolParam {
13 value: AtomicBool,
15 normalized_value: AtomicF32,
17 unmodulated_value: AtomicBool,
20 unmodulated_normalized_value: AtomicF32,
23 modulation_offset: AtomicF32,
27 default: bool,
29
30 value_changed: Option<Arc<dyn Fn(bool) + Send + Sync>>,
35
36 info: Box<ParamInfo<bool>>,
38 poly_modulation_id: Option<u32>,
44}
45
46impl Display for BoolParam {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 match (self.value(), &self.info.value_to_string) {
49 (v, Some(func)) => write!(f, "{}", func(v)),
50 (true, None) => write!(f, "On"),
51 (false, None) => write!(f, "Off"),
52 }
53 }
54}
55
56impl Debug for BoolParam {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 if self.value.load(Ordering::Relaxed) != self.unmodulated_value.load(Ordering::Relaxed) {
60 write!(f, "{}: {} (modulated)", self.info.name, self)
61 } else {
62 write!(f, "{}: {}", self.info.name, self)
63 }
64 }
65}
66
67impl super::Sealed for BoolParam {}
69
70impl Param for BoolParam {
71 type Plain = bool;
72
73 fn name(&self) -> &str {
74 &self.info.name
75 }
76
77 fn unit(&self) -> &'static str {
78 self.info.unit
79 }
80
81 fn poly_modulation_id(&self) -> Option<u32> {
82 self.poly_modulation_id
83 }
84
85 #[inline]
86 fn modulated_plain_value(&self) -> Self::Plain {
87 self.value.load(Ordering::Relaxed)
88 }
89
90 #[inline]
91 fn modulated_normalized_value(&self) -> f32 {
92 self.normalized_value.load(Ordering::Relaxed)
93 }
94
95 #[inline]
96 fn unmodulated_plain_value(&self) -> Self::Plain {
97 self.unmodulated_value.load(Ordering::Relaxed)
98 }
99
100 #[inline]
101 fn unmodulated_normalized_value(&self) -> f32 {
102 self.unmodulated_normalized_value.load(Ordering::Relaxed)
103 }
104
105 #[inline]
106 fn default_plain_value(&self) -> Self::Plain {
107 self.default
108 }
109
110 fn step_count(&self) -> Option<usize> {
111 Some(1)
112 }
113
114 fn previous_step(&self, _from: Self::Plain, _finer: bool) -> Self::Plain {
115 false
116 }
117
118 fn next_step(&self, _from: Self::Plain, _finer: bool) -> Self::Plain {
119 true
120 }
121
122 fn normalized_value_to_string(&self, normalized: f32, _include_unit: bool) -> String {
123 let value = self.preview_plain(normalized);
124 match (value, &self.info.value_to_string) {
125 (v, Some(f)) => f(v),
126 (true, None) => String::from("On"),
127 (false, None) => String::from("Off"),
128 }
129 }
130
131 fn string_to_normalized_value(&self, string: &str) -> Option<f32> {
132 let string = string.trim();
133 let value = match &self.info.string_to_value {
134 Some(f) => f(string),
135 None => Some(string.eq_ignore_ascii_case("true") || string.eq_ignore_ascii_case("on")),
136 }?;
137
138 Some(self.preview_normalized(value))
139 }
140
141 #[inline]
142 fn preview_normalized(&self, plain: Self::Plain) -> f32 {
143 if plain { 1.0 } else { 0.0 }
144 }
145
146 #[inline]
147 fn preview_plain(&self, normalized: f32) -> Self::Plain {
148 normalized > 0.5
149 }
150
151 fn flags(&self) -> ParamFlags {
152 self.info.flags
153 }
154
155 fn as_ptr(&self) -> ParamPtr {
156 ParamPtr::BoolParam(self as *const BoolParam as *mut BoolParam)
157 }
158}
159
160impl InternalParamMut for BoolParam {
161 unsafe fn _internal_set_plain_value(&self, plain: Self::Plain) -> bool {
162 let unmodulated_value = plain;
163 let unmodulated_normalized_value = self.preview_normalized(plain);
164
165 let modulation_offset = self.modulation_offset.load(Ordering::Relaxed);
166 let (value, normalized_value) = if modulation_offset == 0.0 {
167 (unmodulated_value, unmodulated_normalized_value)
168 } else {
169 let normalized_value =
170 (unmodulated_normalized_value + modulation_offset).clamp(0.0, 1.0);
171
172 (self.preview_plain(normalized_value), normalized_value)
173 };
174
175 let old_value = self.value.swap(value, Ordering::Relaxed);
179 if value != old_value {
180 self.normalized_value
181 .store(normalized_value, Ordering::Relaxed);
182 self.unmodulated_value
183 .store(unmodulated_value, Ordering::Relaxed);
184 self.unmodulated_normalized_value
185 .store(unmodulated_normalized_value, Ordering::Relaxed);
186 if let Some(f) = &self.value_changed {
187 f(value);
188 }
189
190 true
191 } else {
192 false
193 }
194 }
195
196 unsafe fn _internal_set_normalized_value(&self, normalized: f32) -> bool {
197 unsafe { self._internal_set_plain_value(self.preview_plain(normalized)) }
202 }
203
204 unsafe fn _internal_modulate_value(&self, modulation_offset: f32) -> bool {
205 self.modulation_offset
206 .store(modulation_offset, Ordering::Relaxed);
207
208 unsafe { self._internal_set_plain_value(self.unmodulated_plain_value()) }
210 }
211
212 unsafe fn _internal_update_smoother(&self, _sample_rate: f32, _init: bool) {
213 }
215}
216
217impl BoolParam {
218 pub fn new(name: impl Into<String>, default: bool) -> Self {
221 Self {
222 value: AtomicBool::new(default),
223 normalized_value: AtomicF32::new(if default { 1.0 } else { 0.0 }),
224 unmodulated_value: AtomicBool::new(default),
225 unmodulated_normalized_value: AtomicF32::new(if default { 1.0 } else { 0.0 }),
226 modulation_offset: AtomicF32::new(0.0),
227 default,
228
229 value_changed: None,
230
231 info: Box::new(ParamInfo::new(name)),
232 poly_modulation_id: None,
233 }
234 }
235
236 #[inline]
239 pub fn value(&self) -> bool {
240 self.modulated_plain_value()
241 }
242
243 pub fn with_poly_modulation_id(mut self, id: u32) -> Self {
255 self.poly_modulation_id = Some(id);
256 self
257 }
258
259 pub fn with_callback(mut self, callback: Arc<dyn Fn(bool) + Send + Sync>) -> Self {
264 self.value_changed = Some(callback);
265 self
266 }
267
268 pub fn with_value_to_string(
270 mut self,
271 callback: Arc<dyn Fn(bool) -> String + Send + Sync>,
272 ) -> Self {
273 self.info.value_to_string = Some(callback);
274 self
275 }
276
277 pub fn with_string_to_value(
281 mut self,
282 callback: Arc<dyn Fn(&str) -> Option<bool> + Send + Sync>,
283 ) -> Self {
284 self.info.string_to_value = Some(callback);
285 self
286 }
287
288 pub fn make_bypass(mut self) -> Self {
293 self.info.flags.insert(ParamFlags::BYPASS);
294 self
295 }
296
297 pub fn non_automatable(mut self) -> Self {
301 self.info.flags.insert(ParamFlags::NON_AUTOMATABLE);
302 self
303 }
304
305 pub fn hide(mut self) -> Self {
309 self.info.flags.insert(ParamFlags::HIDDEN);
310 self
311 }
312
313 pub fn hide_in_generic_ui(mut self) -> Self {
316 self.info.flags.insert(ParamFlags::HIDE_IN_GENERIC_UI);
317 self
318 }
319}