1
0
Fork 0

Store normalized values on the param structs

This will be necessary to implement CLAP modulation later.
This commit is contained in:
Robbert van der Helm 2022-05-01 17:34:59 +02:00
parent 54d2a4cd2c
commit cd628e80ee
5 changed files with 100 additions and 39 deletions

View file

@ -60,10 +60,7 @@ pub trait Param: Display {
fn plain_value(&self) -> Self::Plain; fn plain_value(&self) -> Self::Plain;
/// Get the normalized `[0, 1]` value for this parameter. /// Get the normalized `[0, 1]` value for this parameter.
#[inline] fn normalized_value(&self) -> f32;
fn normalized_value(&self) -> f32 {
self.preview_normalized(self.plain_value())
}
/// Get the unnormalized default value for this parameter. /// Get the unnormalized default value for this parameter.
fn default_plain_value(&self) -> Self::Plain; fn default_plain_value(&self) -> Self::Plain;
@ -112,9 +109,7 @@ pub trait Param: Display {
/// continuous parameters (i.e. [`FloatParam`]). /// continuous parameters (i.e. [`FloatParam`]).
/// ///
/// This does **not** update the smoother. /// This does **not** update the smoother.
fn set_normalized_value(&mut self, normalized: f32) { fn set_normalized_value(&mut self, normalized: f32);
self.set_plain_value(self.preview_plain(normalized))
}
/// Get the string representation for a normalized value. Used as part of the wrappers. Most /// Get the string representation for a normalized value. Used as part of the wrappers. Most
/// plugin formats already have support for units, in which case it shouldn't be part of this /// plugin formats already have support for units, in which case it shouldn't be part of this

View file

@ -9,8 +9,10 @@ use super::{Param, ParamFlags};
/// A simple boolean parameter. /// A simple boolean parameter.
#[repr(C, align(4))] #[repr(C, align(4))]
pub struct BoolParam { pub struct BoolParam {
/// The field's current value. Should be initialized with the default value. /// The field's current value.
pub value: bool, pub value: bool,
/// The field's current value normalized to the `[0, 1]` range.
normalized_value: f32,
/// The field's default value. /// The field's default value.
default: bool, default: bool,
@ -37,6 +39,7 @@ impl Default for BoolParam {
fn default() -> Self { fn default() -> Self {
Self { Self {
value: false, value: false,
normalized_value: 0.0,
default: false, default: false,
flags: ParamFlags::default(), flags: ParamFlags::default(),
value_changed: None, value_changed: None,
@ -73,6 +76,10 @@ impl Param for BoolParam {
self.value self.value
} }
fn normalized_value(&self) -> f32 {
self.normalized_value
}
#[inline] #[inline]
fn default_plain_value(&self) -> Self::Plain { fn default_plain_value(&self) -> Self::Plain {
self.default self.default
@ -92,8 +99,17 @@ impl Param for BoolParam {
fn set_plain_value(&mut self, plain: Self::Plain) { fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain; self.value = plain;
self.normalized_value = self.preview_normalized(plain);
if let Some(f) = &self.value_changed { if let Some(f) = &self.value_changed {
f(plain); f(self.value);
}
}
fn set_normalized_value(&mut self, normalized: f32) {
self.value = self.preview_plain(normalized);
self.normalized_value = normalized;
if let Some(f) = &self.value_changed {
f(self.value);
} }
} }

View file

@ -71,15 +71,14 @@ impl<T: Enum + PartialEq + Default> Default for EnumParam<T> {
Self { Self {
inner: EnumParamInner { inner: EnumParamInner {
inner: IntParam { inner: IntParam::new(
value: T::default().to_index() as i32, "",
default: T::default().to_index() as i32, T::default().to_index() as i32,
range: IntRange::Linear { IntRange::Linear {
min: 0, min: 0,
max: variants.len() as i32 - 1, max: variants.len() as i32 - 1,
}, },
..Default::default() ),
},
variants, variants,
}, },
_marker: PhantomData, _marker: PhantomData,
@ -115,6 +114,11 @@ impl<T: Enum + PartialEq> Param for EnumParam<T> {
T::from_index(self.inner.plain_value() as usize) T::from_index(self.inner.plain_value() as usize)
} }
#[inline]
fn normalized_value(&self) -> f32 {
self.inner.normalized_value()
}
#[inline] #[inline]
fn default_plain_value(&self) -> Self::Plain { fn default_plain_value(&self) -> Self::Plain {
T::from_index(self.inner.default_plain_value() as usize) T::from_index(self.inner.default_plain_value() as usize)
@ -136,6 +140,10 @@ impl<T: Enum + PartialEq> Param for EnumParam<T> {
self.inner.set_plain_value(T::to_index(plain) as i32) self.inner.set_plain_value(T::to_index(plain) as i32)
} }
fn set_normalized_value(&mut self, normalized: f32) {
self.inner.set_normalized_value(normalized)
}
fn normalized_value_to_string(&self, normalized: f32, include_unit: bool) -> String { fn normalized_value_to_string(&self, normalized: f32, include_unit: bool) -> String {
self.inner self.inner
.normalized_value_to_string(normalized, include_unit) .normalized_value_to_string(normalized, include_unit)
@ -174,7 +182,7 @@ impl Param for EnumParamInner {
type Plain = i32; type Plain = i32;
fn name(&self) -> &str { fn name(&self) -> &str {
&self.inner.name self.inner.name()
} }
fn unit(&self) -> &'static str { fn unit(&self) -> &'static str {
@ -186,6 +194,11 @@ impl Param for EnumParamInner {
self.inner.plain_value() self.inner.plain_value()
} }
#[inline]
fn normalized_value(&self) -> f32 {
self.inner.normalized_value()
}
#[inline] #[inline]
fn default_plain_value(&self) -> Self::Plain { fn default_plain_value(&self) -> Self::Plain {
self.inner.default_plain_value() self.inner.default_plain_value()
@ -207,6 +220,10 @@ impl Param for EnumParamInner {
self.inner.set_plain_value(plain) self.inner.set_plain_value(plain)
} }
fn set_normalized_value(&mut self, normalized: f32) {
self.inner.set_normalized_value(normalized)
}
fn normalized_value_to_string(&self, normalized: f32, _include_unit: bool) -> String { fn normalized_value_to_string(&self, normalized: f32, _include_unit: bool) -> String {
let index = self.preview_plain(normalized); let index = self.preview_plain(normalized);
self.variants[index as usize].to_string() self.variants[index as usize].to_string()
@ -253,15 +270,14 @@ impl<T: Enum + PartialEq + 'static> EnumParam<T> {
Self { Self {
inner: EnumParamInner { inner: EnumParamInner {
inner: IntParam { inner: IntParam::new(
value: T::to_index(default) as i32, name,
range: IntRange::Linear { T::to_index(default) as i32,
IntRange::Linear {
min: 0, min: 0,
max: variants.len() as i32 - 1, max: variants.len() as i32 - 1,
}, },
name: name.into(), ),
..Default::default()
},
variants, variants,
}, },
_marker: PhantomData, _marker: PhantomData,
@ -273,7 +289,7 @@ impl<T: Enum + PartialEq + 'static> EnumParam<T> {
/// multiple times in rapid succession, and it can be run from both the GUI and the audio /// multiple times in rapid succession, and it can be run from both the GUI and the audio
/// thread. /// thread.
pub fn with_callback(mut self, callback: Arc<dyn Fn(T) + Send + Sync>) -> Self { pub fn with_callback(mut self, callback: Arc<dyn Fn(T) + Send + Sync>) -> Self {
self.inner.inner.value_changed = Some(Arc::new(move |value| { self.inner.inner = self.inner.inner.with_callback(Arc::new(move |value| {
callback(T::from_index(value as usize)) callback(T::from_index(value as usize))
})); }));
self self

View file

@ -21,10 +21,10 @@ use super::{Param, ParamFlags};
// a partially written to value here. We should probably reconsider this at some point though. // a partially written to value here. We should probably reconsider this at some point though.
#[repr(C, align(4))] #[repr(C, align(4))]
pub struct FloatParam { pub struct FloatParam {
/// The field's current plain, unnormalized value. Should be initialized with the default value. /// The field's current plain, unnormalized value.
/// Storing parameter values like this instead of in a single contiguous array is bad for cache
/// locality, but it does allow for a much nicer declarative API.
pub value: f32, pub value: f32,
/// The field's current value normalized to the `[0, 1]` range.
normalized_value: f32,
/// The field's default plain, unnormalized value. /// The field's default plain, unnormalized value.
default: f32, default: f32,
/// An optional smoother that will automatically interpolate between the new automation values /// An optional smoother that will automatically interpolate between the new automation values
@ -69,6 +69,7 @@ impl Default for FloatParam {
fn default() -> Self { fn default() -> Self {
Self { Self {
value: 0.0, value: 0.0,
normalized_value: 0.0,
default: 0.0, default: 0.0,
smoothed: Smoother::none(), smoothed: Smoother::none(),
flags: ParamFlags::default(), flags: ParamFlags::default(),
@ -112,6 +113,11 @@ impl Param for FloatParam {
self.value self.value
} }
#[inline]
fn normalized_value(&self) -> Self::Plain {
self.normalized_value
}
#[inline] #[inline]
fn default_plain_value(&self) -> Self::Plain { fn default_plain_value(&self) -> Self::Plain {
self.default self.default
@ -146,8 +152,17 @@ impl Param for FloatParam {
fn set_plain_value(&mut self, plain: Self::Plain) { fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain; self.value = plain;
self.normalized_value = self.preview_normalized(plain);
if let Some(f) = &self.value_changed { if let Some(f) = &self.value_changed {
f(plain); f(self.value);
}
}
fn set_normalized_value(&mut self, normalized: f32) {
self.value = self.preview_plain(normalized);
self.normalized_value = normalized;
if let Some(f) = &self.value_changed {
f(self.value);
} }
} }
@ -218,6 +233,7 @@ impl FloatParam {
pub fn new(name: impl Into<String>, default: f32, range: FloatRange) -> Self { pub fn new(name: impl Into<String>, default: f32, range: FloatRange) -> Self {
Self { Self {
value: default, value: default,
normalized_value: range.normalize(default),
default, default,
range, range,
name: name.into(), name: name.into(),

View file

@ -21,18 +21,18 @@ use super::{Param, ParamFlags};
// a partially written to value here. We should probably reconsider this at some point though. // a partially written to value here. We should probably reconsider this at some point though.
#[repr(C, align(4))] #[repr(C, align(4))]
pub struct IntParam { pub struct IntParam {
/// The field's current plain, unnormalized value. Should be initialized with the default value. /// The field's current plain, unnormalized value.
/// Storing parameter values like this instead of in a single contiguous array is bad for cache
/// locality, but it does allow for a much nicer declarative API.
pub value: i32, pub value: i32,
/// The field's current value normalized to the `[0, 1]` range.
normalized_value: f32,
/// The field's default plain, unnormalized value. /// The field's default plain, unnormalized value.
pub(crate) default: i32, default: i32,
/// An optional smoother that will automatically interpolate between the new automation values /// An optional smoother that will automatically interpolate between the new automation values
/// set by the host. /// set by the host.
pub smoothed: Smoother<i32>, pub smoothed: Smoother<i32>,
/// Flags to control the parameter's behavior. See [`ParamFlags`]. /// Flags to control the parameter's behavior. See [`ParamFlags`].
pub(crate) flags: ParamFlags, flags: ParamFlags,
/// Optional callback for listening to value changes. The argument passed to this function is /// Optional callback for listening to value changes. The argument passed to this function is
/// the parameter's new **plain** value. This should not do anything expensive as it may be /// the parameter's new **plain** value. This should not do anything expensive as it may be
/// called multiple times in rapid succession. /// called multiple times in rapid succession.
@ -41,30 +41,31 @@ pub struct IntParam {
/// parameters struct, move a clone of that `Arc` into this closure, and then modify that. /// parameters struct, move a clone of that `Arc` into this closure, and then modify that.
/// ///
/// TODO: We probably also want to pass the old value to this function. /// TODO: We probably also want to pass the old value to this function.
pub(crate) value_changed: Option<Arc<dyn Fn(i32) + Send + Sync>>, value_changed: Option<Arc<dyn Fn(i32) + Send + Sync>>,
/// The distribution of the parameter's values. /// The distribution of the parameter's values.
pub(crate) range: IntRange, range: IntRange,
/// The parameter's human readable display name. /// The parameter's human readable display name.
pub(crate) name: String, name: String,
/// The parameter value's unit, added after `value_to_string` if that is set. NIH-plug will not /// The parameter value's unit, added after `value_to_string` if that is set. NIH-plug will not
/// automatically add a space before the unit. /// automatically add a space before the unit.
pub(crate) unit: &'static str, unit: &'static str,
/// Optional custom conversion function from a plain **unnormalized** value to a string. /// Optional custom conversion function from a plain **unnormalized** value to a string.
pub(crate) value_to_string: Option<Arc<dyn Fn(i32) -> String + Send + Sync>>, value_to_string: Option<Arc<dyn Fn(i32) -> String + Send + Sync>>,
/// Optional custom conversion function from a string to a plain **unnormalized** value. If the /// Optional custom conversion function from a string to a plain **unnormalized** value. If the
/// string cannot be parsed, then this should return a `None`. If this happens while the /// string cannot be parsed, then this should return a `None`. If this happens while the
/// parameter is being updated then the update will be canceled. /// parameter is being updated then the update will be canceled.
/// ///
/// The input string may or may not contain the unit, so you will need to be able to handle /// The input string may or may not contain the unit, so you will need to be able to handle
/// that. /// that.
pub(crate) string_to_value: Option<Arc<dyn Fn(&str) -> Option<i32> + Send + Sync>>, string_to_value: Option<Arc<dyn Fn(&str) -> Option<i32> + Send + Sync>>,
} }
impl Default for IntParam { impl Default for IntParam {
fn default() -> Self { fn default() -> Self {
Self { Self {
value: 0, value: 0,
normalized_value: 0.0,
default: 0, default: 0,
smoothed: Smoother::none(), smoothed: Smoother::none(),
flags: ParamFlags::default(), flags: ParamFlags::default(),
@ -98,10 +99,17 @@ impl Param for IntParam {
self.unit self.unit
} }
#[inline]
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.value self.value
} }
#[inline]
fn normalized_value(&self) -> f32 {
self.normalized_value
}
#[inline]
fn default_plain_value(&self) -> Self::Plain { fn default_plain_value(&self) -> Self::Plain {
self.default self.default
} }
@ -120,8 +128,17 @@ impl Param for IntParam {
fn set_plain_value(&mut self, plain: Self::Plain) { fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain; self.value = plain;
self.normalized_value = self.preview_normalized(plain);
if let Some(f) = &self.value_changed { if let Some(f) = &self.value_changed {
f(plain); f(self.value);
}
}
fn set_normalized_value(&mut self, normalized: f32) {
self.value = self.preview_plain(normalized);
self.normalized_value = normalized;
if let Some(f) = &self.value_changed {
f(self.value);
} }
} }
@ -180,6 +197,7 @@ impl IntParam {
pub fn new(name: impl Into<String>, default: i32, range: IntRange) -> Self { pub fn new(name: impl Into<String>, default: i32, range: IntRange) -> Self {
Self { Self {
value: default, value: default,
normalized_value: range.normalize(default),
default, default,
range, range,
name: name.into(), name: name.into(),