1use atomic_float::AtomicF32;
4use std::fmt::{Debug, Display};
5use std::sync::Arc;
6use std::sync::atomic::Ordering;
7
8use crate::nice_debug_assert;
9
10use super::internals::ParamPtr;
11use super::range::FloatRange;
12use super::smoothing::{Smoother, SmoothingStyle};
13use super::{InternalParamMut, Param, ParamFlags, ParamInfo};
14
15pub struct FloatParam {
18 value: AtomicF32,
20 normalized_value: AtomicF32,
22 unmodulated_value: AtomicF32,
25 unmodulated_normalized_value: AtomicF32,
28 modulation_offset: AtomicF32,
32 default: f32,
34 pub smoothed: Smoother<f32>,
37
38 value_changed: Option<Arc<dyn Fn(f32) + Send + Sync>>,
47
48 range: FloatRange,
50 step_size: Option<f32>,
54 info: Box<ParamInfo<f32>>,
56 poly_modulation_id: Option<u32>,
62}
63
64impl Display for FloatParam {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 match (&self.info.value_to_string, &self.step_size) {
67 (Some(func), _) => write!(f, "{}{}", func(self.value()), self.info.unit),
68 (None, Some(step_size)) => {
69 let num_digits = decimals_from_step_size(*step_size);
70 write!(f, "{:.num_digits$}{}", self.value(), self.info.unit)
71 }
72 _ => write!(f, "{}{}", self.value(), self.info.unit),
73 }
74 }
75}
76
77impl Debug for FloatParam {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 if self.modulated_plain_value() != self.unmodulated_plain_value() {
81 write!(f, "{}: {} (modulated)", self.info.name, self)
82 } else {
83 write!(f, "{}: {}", self.info.name, self)
84 }
85 }
86}
87
88impl super::Sealed for FloatParam {}
90
91impl Param for FloatParam {
92 type Plain = f32;
93
94 fn name(&self) -> &str {
95 &self.info.name
96 }
97
98 fn unit(&self) -> &'static str {
99 self.info.unit
100 }
101
102 fn poly_modulation_id(&self) -> Option<u32> {
103 self.poly_modulation_id
104 }
105
106 #[inline]
107 fn modulated_plain_value(&self) -> Self::Plain {
108 self.value.load(Ordering::Relaxed)
109 }
110
111 #[inline]
112 fn modulated_normalized_value(&self) -> f32 {
113 self.normalized_value.load(Ordering::Relaxed)
114 }
115
116 #[inline]
117 fn unmodulated_plain_value(&self) -> Self::Plain {
118 self.unmodulated_value.load(Ordering::Relaxed)
119 }
120
121 #[inline]
122 fn unmodulated_normalized_value(&self) -> f32 {
123 self.unmodulated_normalized_value.load(Ordering::Relaxed)
124 }
125
126 #[inline]
127 fn default_plain_value(&self) -> Self::Plain {
128 self.default
129 }
130
131 fn step_count(&self) -> Option<usize> {
132 None
133 }
134
135 fn previous_step(&self, from: Self::Plain, finer: bool) -> Self::Plain {
136 self.range.previous_step(from, self.step_size, finer)
137 }
138
139 fn next_step(&self, from: Self::Plain, finer: bool) -> Self::Plain {
140 self.range.next_step(from, self.step_size, finer)
141 }
142
143 fn normalized_value_to_string(&self, normalized: f32, include_unit: bool) -> String {
144 let value = self.preview_plain(normalized);
145 match (&self.info.value_to_string, &self.step_size, include_unit) {
146 (Some(f), _, true) => format!("{}{}", f(value), self.info.unit),
147 (Some(f), _, false) => f(value),
148 (None, Some(step_size), true) => {
149 let num_digits = decimals_from_step_size(*step_size);
150 format!("{:.num_digits$}{}", value, self.info.unit)
151 }
152 (None, Some(step_size), false) => {
153 let num_digits = decimals_from_step_size(*step_size);
154 format!("{value:.num_digits$}")
155 }
156 (None, None, true) => format!("{}{}", value, self.info.unit),
157 (None, None, false) => format!("{value}"),
158 }
159 }
160
161 fn string_to_normalized_value(&self, string: &str) -> Option<f32> {
162 let value = match &self.info.string_to_value {
163 Some(f) => f(string.trim()),
164 None => string.trim().trim_end_matches(self.info.unit).parse().ok(),
166 }?;
167
168 Some(self.preview_normalized(value))
169 }
170
171 #[inline]
172 fn preview_normalized(&self, plain: Self::Plain) -> f32 {
173 self.range.normalize(plain)
174 }
175
176 #[inline]
177 fn preview_plain(&self, normalized: f32) -> Self::Plain {
178 let value = self.range.unnormalize(normalized);
179 match &self.step_size {
180 Some(step_size) => self.range.snap_to_step(value, *step_size as Self::Plain),
181 None => value,
182 }
183 }
184
185 fn flags(&self) -> ParamFlags {
186 self.info.flags
187 }
188
189 fn as_ptr(&self) -> ParamPtr {
190 ParamPtr::FloatParam(self as *const _ as *mut _)
191 }
192}
193
194impl InternalParamMut for FloatParam {
195 unsafe fn _internal_set_plain_value(&self, plain: Self::Plain) -> bool {
196 let unmodulated_value = plain;
197 let unmodulated_normalized_value = self.preview_normalized(plain);
198
199 let modulation_offset = self.modulation_offset.load(Ordering::Relaxed);
200 let (value, normalized_value) = if modulation_offset == 0.0 {
201 (unmodulated_value, unmodulated_normalized_value)
202 } else {
203 let normalized_value =
204 (unmodulated_normalized_value + modulation_offset).clamp(0.0, 1.0);
205
206 (self.preview_plain(normalized_value), normalized_value)
207 };
208
209 let old_value = self.value.swap(value, Ordering::Relaxed);
213 if value != old_value {
214 self.normalized_value
215 .store(normalized_value, Ordering::Relaxed);
216 self.unmodulated_value
217 .store(unmodulated_value, Ordering::Relaxed);
218 self.unmodulated_normalized_value
219 .store(unmodulated_normalized_value, Ordering::Relaxed);
220 if let Some(f) = &self.value_changed {
221 f(value);
222 }
223
224 true
225 } else {
226 false
227 }
228 }
229
230 unsafe fn _internal_set_normalized_value(&self, normalized: f32) -> bool {
231 unsafe { self._internal_set_plain_value(self.preview_plain(normalized)) }
236 }
237
238 unsafe fn _internal_modulate_value(&self, modulation_offset: f32) -> bool {
239 self.modulation_offset
240 .store(modulation_offset, Ordering::Relaxed);
241
242 unsafe { self._internal_set_plain_value(self.unmodulated_plain_value()) }
244 }
245
246 unsafe fn _internal_update_smoother(&self, sample_rate: f32, reset: bool) {
247 if reset {
248 self.smoothed.reset(self.modulated_plain_value());
249 } else {
250 self.smoothed
251 .set_target(sample_rate, self.modulated_plain_value());
252 }
253 }
254}
255
256impl FloatParam {
257 pub fn new(name: impl Into<String>, default: f32, range: FloatRange) -> Self {
260 range.assert_validity();
261
262 Self {
263 value: AtomicF32::new(default),
264 normalized_value: AtomicF32::new(range.normalize(default)),
265 unmodulated_value: AtomicF32::new(default),
266 unmodulated_normalized_value: AtomicF32::new(range.normalize(default)),
267 modulation_offset: AtomicF32::new(0.0),
268 default,
269 smoothed: Smoother::none(),
270
271 value_changed: None,
272
273 range,
274 step_size: None,
275 info: Box::new(ParamInfo::new(name)),
276 poly_modulation_id: None,
277 }
278 }
279
280 #[inline]
283 pub fn value(&self) -> f32 {
284 self.modulated_plain_value()
285 }
286
287 #[inline]
289 pub fn range(&self) -> FloatRange {
290 self.range
291 }
292
293 pub fn with_poly_modulation_id(mut self, id: u32) -> Self {
305 self.poly_modulation_id = Some(id);
306 self
307 }
308
309 pub fn with_smoother(mut self, style: SmoothingStyle) -> Self {
312 let goes_through_zero = match (&style, &self.range) {
315 (
316 SmoothingStyle::Logarithmic(_),
317 FloatRange::Linear { min, max }
318 | FloatRange::Skewed { min, max, .. }
319 | FloatRange::SymmetricalSkewed { min, max, .. },
320 ) => *min == 0.0 || *max == 0.0 || min.signum() != max.signum(),
321 _ => false,
322 };
323 nice_debug_assert!(
324 !goes_through_zero,
325 "Logarithmic smoothing does not work with ranges that go through zero"
326 );
327
328 self.smoothed = Smoother::new(style);
329 self
330 }
331
332 pub fn with_callback(mut self, callback: Arc<dyn Fn(f32) + Send + Sync>) -> Self {
337 self.value_changed = Some(callback);
338 self
339 }
340
341 pub fn with_unit(mut self, unit: &'static str) -> Self {
345 self.info.unit = unit;
346 self
347 }
348
349 pub fn with_step_size(mut self, step_size: f32) -> Self {
354 self.step_size = Some(step_size);
355 self
356 }
357
358 pub fn with_value_to_string(
361 mut self,
362 callback: Arc<dyn Fn(f32) -> String + Send + Sync>,
363 ) -> Self {
364 self.info.value_to_string = Some(callback);
365 self
366 }
367
368 pub fn with_string_to_value(
375 mut self,
376 callback: Arc<dyn Fn(&str) -> Option<f32> + Send + Sync>,
377 ) -> Self {
378 self.info.string_to_value = Some(callback);
379 self
380 }
381
382 pub fn non_automatable(mut self) -> Self {
386 self.info.flags.insert(ParamFlags::NON_AUTOMATABLE);
387 self
388 }
389
390 pub fn hide(mut self) -> Self {
394 self.info.flags.insert(ParamFlags::HIDDEN);
395 self
396 }
397
398 pub fn hide_in_generic_ui(mut self) -> Self {
401 self.info.flags.insert(ParamFlags::HIDE_IN_GENERIC_UI);
402 self
403 }
404}
405
406fn decimals_from_step_size(step_size: f32) -> usize {
410 const SCALE: f32 = 1_000_000.0; let step_size = (step_size * SCALE).round() / SCALE;
412
413 let mut num_digits = 0;
414 for decimals in 0..f32::DIGITS as i32 {
415 if step_size * 10.0f32.powi(decimals) >= 1.0 {
416 num_digits = decimals;
417 break;
418 }
419 }
420
421 num_digits as usize
422}