use std::{any::Any, ops::RangeInclusive};
use crate::{
parameter::{BooleanParameter, EnumParameter, FloatParameter, IntegerParameter},
Parameter, ParameterScaling, ParameterValueUpdate,
};
use fundsp::shared::Shared;
pub struct SharedParameterValue {
description: Box<dyn Parameter>,
range: RangeInclusive<f32>,
scaling: ParameterScaling,
value: Shared,
}
impl SharedParameterValue {
pub fn from_description(description: &dyn Parameter) -> Self {
let description_any = description as &dyn Any;
let range;
let scaling;
if let Some(float_param) = description_any.downcast_ref::<FloatParameter>() {
range = float_param.range().clone();
scaling = *float_param.scaling();
} else if let Some(integer_param) = description_any.downcast_ref::<IntegerParameter>() {
range = RangeInclusive::new(
*integer_param.range().start() as f32,
*integer_param.range().end() as f32,
);
scaling = ParameterScaling::Linear;
} else if let Some(enum_param) = description_any.downcast_ref::<EnumParameter>() {
range = RangeInclusive::new(0.0, (enum_param.values().len() - 1) as f32);
scaling = ParameterScaling::Linear;
} else if description_any.downcast_ref::<BooleanParameter>().is_some() {
range = RangeInclusive::new(0.0, 1.0);
scaling = ParameterScaling::Linear;
} else {
unreachable!("Unexpected parameter type")
}
let default_normalized = description.default_value();
let default_scaled = scaling.scale(default_normalized);
let default_value = range.start() + default_scaled * (range.end() - range.start());
let value = Shared::new(default_value);
let description = description.dyn_clone();
Self {
value,
range,
scaling,
description,
}
}
pub fn description(&self) -> &dyn Parameter {
self.description.as_ref()
}
#[inline(always)]
pub fn shared(&self) -> &Shared {
&self.value
}
#[inline(always)]
#[allow(unused)]
pub fn value(&self) -> f32 {
self.value.value()
}
pub fn set_value(&mut self, value: f32) {
assert!(self.range.contains(&value), "Value out of bounds");
self.value.set_value(value);
}
pub fn set_value_clamped(&mut self, value: f32) {
self.value
.set_value(value.clamp(*self.range.start(), *self.range.end()));
}
pub fn apply_update(&mut self, update: &ParameterValueUpdate) {
match update {
ParameterValueUpdate::Raw(raw) => {
if let Some(value) = (*raw).downcast_ref::<f32>() {
self.set_value_clamped(*value);
} else if let Some(value) = (*raw).downcast_ref::<f64>() {
self.set_value_clamped(*value as f32);
} else {
log::warn!(
"Invalid value type for float parameter '{}'",
self.description.id()
);
}
}
ParameterValueUpdate::Normalized(normalized) => {
let normalized = normalized.clamp(0.0, 1.0);
let normalized_scaled = self.scaling.scale(normalized);
let value = self.range.start()
+ normalized_scaled * (self.range.end() - self.range.start());
self.set_value(value);
}
}
}
}