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;
/// Get the normalized `[0, 1]` value for this parameter.
#[inline]
fn normalized_value(&self) -> f32 {
self.preview_normalized(self.plain_value())
}
fn normalized_value(&self) -> f32;
/// Get the unnormalized default value for this parameter.
fn default_plain_value(&self) -> Self::Plain;
@ -112,9 +109,7 @@ pub trait Param: Display {
/// continuous parameters (i.e. [`FloatParam`]).
///
/// This does **not** update the smoother.
fn set_normalized_value(&mut self, normalized: f32) {
self.set_plain_value(self.preview_plain(normalized))
}
fn set_normalized_value(&mut self, normalized: f32);
/// 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

View file

@ -9,8 +9,10 @@ use super::{Param, ParamFlags};
/// A simple boolean parameter.
#[repr(C, align(4))]
pub struct BoolParam {
/// The field's current value. Should be initialized with the default value.
/// The field's current value.
pub value: bool,
/// The field's current value normalized to the `[0, 1]` range.
normalized_value: f32,
/// The field's default value.
default: bool,
@ -37,6 +39,7 @@ impl Default for BoolParam {
fn default() -> Self {
Self {
value: false,
normalized_value: 0.0,
default: false,
flags: ParamFlags::default(),
value_changed: None,
@ -73,6 +76,10 @@ impl Param for BoolParam {
self.value
}
fn normalized_value(&self) -> f32 {
self.normalized_value
}
#[inline]
fn default_plain_value(&self) -> Self::Plain {
self.default
@ -92,8 +99,17 @@ impl Param for BoolParam {
fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain;
self.normalized_value = self.preview_normalized(plain);
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 {
inner: EnumParamInner {
inner: IntParam {
value: T::default().to_index() as i32,
default: T::default().to_index() as i32,
range: IntRange::Linear {
inner: IntParam::new(
"",
T::default().to_index() as i32,
IntRange::Linear {
min: 0,
max: variants.len() as i32 - 1,
},
..Default::default()
},
),
variants,
},
_marker: PhantomData,
@ -115,6 +114,11 @@ impl<T: Enum + PartialEq> Param for EnumParam<T> {
T::from_index(self.inner.plain_value() as usize)
}
#[inline]
fn normalized_value(&self) -> f32 {
self.inner.normalized_value()
}
#[inline]
fn default_plain_value(&self) -> Self::Plain {
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)
}
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 {
self.inner
.normalized_value_to_string(normalized, include_unit)
@ -174,7 +182,7 @@ impl Param for EnumParamInner {
type Plain = i32;
fn name(&self) -> &str {
&self.inner.name
self.inner.name()
}
fn unit(&self) -> &'static str {
@ -186,6 +194,11 @@ impl Param for EnumParamInner {
self.inner.plain_value()
}
#[inline]
fn normalized_value(&self) -> f32 {
self.inner.normalized_value()
}
#[inline]
fn default_plain_value(&self) -> Self::Plain {
self.inner.default_plain_value()
@ -207,6 +220,10 @@ impl Param for EnumParamInner {
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 {
let index = self.preview_plain(normalized);
self.variants[index as usize].to_string()
@ -253,15 +270,14 @@ impl<T: Enum + PartialEq + 'static> EnumParam<T> {
Self {
inner: EnumParamInner {
inner: IntParam {
value: T::to_index(default) as i32,
range: IntRange::Linear {
inner: IntParam::new(
name,
T::to_index(default) as i32,
IntRange::Linear {
min: 0,
max: variants.len() as i32 - 1,
},
name: name.into(),
..Default::default()
},
),
variants,
},
_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
/// thread.
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))
}));
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.
#[repr(C, align(4))]
pub struct FloatParam {
/// The field's current plain, unnormalized value. Should be initialized with the default 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.
/// The field's current plain, unnormalized value.
pub value: f32,
/// The field's current value normalized to the `[0, 1]` range.
normalized_value: f32,
/// The field's default plain, unnormalized value.
default: f32,
/// An optional smoother that will automatically interpolate between the new automation values
@ -69,6 +69,7 @@ impl Default for FloatParam {
fn default() -> Self {
Self {
value: 0.0,
normalized_value: 0.0,
default: 0.0,
smoothed: Smoother::none(),
flags: ParamFlags::default(),
@ -112,6 +113,11 @@ impl Param for FloatParam {
self.value
}
#[inline]
fn normalized_value(&self) -> Self::Plain {
self.normalized_value
}
#[inline]
fn default_plain_value(&self) -> Self::Plain {
self.default
@ -146,8 +152,17 @@ impl Param for FloatParam {
fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain;
self.normalized_value = self.preview_normalized(plain);
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 {
Self {
value: default,
normalized_value: range.normalize(default),
default,
range,
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.
#[repr(C, align(4))]
pub struct IntParam {
/// The field's current plain, unnormalized value. Should be initialized with the default 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.
/// The field's current plain, unnormalized value.
pub value: i32,
/// The field's current value normalized to the `[0, 1]` range.
normalized_value: f32,
/// 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
/// set by the host.
pub smoothed: Smoother<i32>,
/// 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
/// the parameter's new **plain** value. This should not do anything expensive as it may be
/// 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.
///
/// 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.
pub(crate) range: IntRange,
range: IntRange,
/// 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
/// 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.
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
/// 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.
///
/// The input string may or may not contain the unit, so you will need to be able to handle
/// 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 {
fn default() -> Self {
Self {
value: 0,
normalized_value: 0.0,
default: 0,
smoothed: Smoother::none(),
flags: ParamFlags::default(),
@ -98,10 +99,17 @@ impl Param for IntParam {
self.unit
}
#[inline]
fn plain_value(&self) -> Self::Plain {
self.value
}
#[inline]
fn normalized_value(&self) -> f32 {
self.normalized_value
}
#[inline]
fn default_plain_value(&self) -> Self::Plain {
self.default
}
@ -120,8 +128,17 @@ impl Param for IntParam {
fn set_plain_value(&mut self, plain: Self::Plain) {
self.value = plain;
self.normalized_value = self.preview_normalized(plain);
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 {
Self {
value: default,
normalized_value: range.normalize(default),
default,
range,
name: name.into(),