Make parameter modulation stick after automation
This is how it's supposed to be implemented in CLAP.
This commit is contained in:
parent
10ae8e1d05
commit
06c5e4b04a
5 changed files with 82 additions and 38 deletions
15
src/param.rs
15
src/param.rs
|
@ -145,20 +145,25 @@ pub trait Param: Display {
|
|||
/// Contains the setters for parameters. These should not be exposed to plugins to avoid confusion.
|
||||
pub(crate) trait ParamMut: Param {
|
||||
/// Set this parameter based on a plain, unnormalized value. This does not snap to step sizes
|
||||
/// for continuous parameters (i.e. [`FloatParam`]).
|
||||
/// for continuous parameters (i.e. [`FloatParam`]). If
|
||||
/// [`modulate_value()`][Self::modulate_value()] has previously been called with a non zero
|
||||
/// value then this offset is taken into account to form the effective value.
|
||||
///
|
||||
/// This does **not** update the smoother.
|
||||
fn set_plain_value(&mut self, plain: Self::Plain);
|
||||
|
||||
/// Set this parameter based on a normalized value. The normalized value will be snapped to the
|
||||
/// step size for continuous parameters (i.e. [`FloatParam`]).
|
||||
/// step size for continuous parameters (i.e. [`FloatParam`]). If
|
||||
/// [`modulate_value()`][Self::modulate_value()] has previously been called with a non zero
|
||||
/// value then this offset is taken into account to form the effective value.
|
||||
///
|
||||
/// This does **not** update the smoother.
|
||||
fn set_normalized_value(&mut self, normalized: f32);
|
||||
|
||||
/// Add a modulation offset to the value's unmodulated value. Out of bound values will be
|
||||
/// clamped to the parameter's range. The normalized value will be snapped to the step size for
|
||||
/// continuous parameters (i.e. [`FloatParam`]).
|
||||
/// Add a modulation offset to the value's unmodulated value. This value sticks until this
|
||||
/// function is called again with a 0.0 value. Out of bound values will be clamped to the
|
||||
/// parameter's range. The normalized value will be snapped to the step size for continuous
|
||||
/// parameters (i.e. [`FloatParam`]).
|
||||
///
|
||||
/// This does **not** update the smoother.
|
||||
fn modulate_value(&mut self, modulation_offset: f32);
|
||||
|
|
|
@ -19,6 +19,10 @@ pub struct BoolParam {
|
|||
/// The field's value normalized to the `[0, 1]` range before any monophonic automation coming
|
||||
/// from the host has been applied. This will always be the same as `value` for VST3 plugins.
|
||||
unmodulated_normalized_value: f32,
|
||||
/// A value in `[-1, 1]` indicating the amount of modulation applied to
|
||||
/// `unmodulated_normalized_`. This needs to be stored separately since the normalied values are
|
||||
/// clamped, and this value persists after new automation events.
|
||||
modulation_offset: f32,
|
||||
/// The field's default value.
|
||||
default: bool,
|
||||
|
||||
|
@ -144,8 +148,14 @@ impl ParamMut for BoolParam {
|
|||
fn set_plain_value(&mut self, plain: Self::Plain) {
|
||||
self.unmodulated_value = plain;
|
||||
self.unmodulated_normalized_value = self.preview_normalized(plain);
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
if self.modulation_offset == 0.0 {
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
} else {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + self.modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
}
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
|
@ -154,20 +164,22 @@ impl ParamMut for BoolParam {
|
|||
fn set_normalized_value(&mut self, normalized: f32) {
|
||||
self.unmodulated_value = self.preview_plain(normalized);
|
||||
self.unmodulated_normalized_value = normalized;
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
if self.modulation_offset == 0.0 {
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
} else {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + self.modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
}
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
}
|
||||
|
||||
fn modulate_value(&mut self, modulation_offset: f32) {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
self.modulation_offset = modulation_offset;
|
||||
self.set_normalized_value(self.unmodulated_normalized_value);
|
||||
}
|
||||
|
||||
fn update_smoother(&mut self, _sample_rate: f32, _init: bool) {
|
||||
|
@ -184,6 +196,7 @@ impl BoolParam {
|
|||
normalized_value: if default { 1.0 } else { 0.0 },
|
||||
unmodulated_value: default,
|
||||
unmodulated_normalized_value: if default { 1.0 } else { 0.0 },
|
||||
modulation_offset: 0.0,
|
||||
default,
|
||||
|
||||
flags: ParamFlags::default(),
|
||||
|
|
|
@ -31,6 +31,10 @@ pub struct FloatParam {
|
|||
/// The field's value normalized to the `[0, 1]` range before any monophonic automation coming
|
||||
/// from the host has been applied. This will always be the same as `value` for VST3 plugins.
|
||||
unmodulated_normalized_value: f32,
|
||||
/// A value in `[-1, 1]` indicating the amount of modulation applied to
|
||||
/// `unmodulated_normalized_`. This needs to be stored separately since the normalied values are
|
||||
/// clamped, and this value persists after new automation events.
|
||||
modulation_offset: f32,
|
||||
/// The field's default plain, unnormalized value.
|
||||
default: f32,
|
||||
/// An optional smoother that will automatically interpolate between the new automation values
|
||||
|
@ -204,8 +208,14 @@ impl ParamMut for FloatParam {
|
|||
fn set_plain_value(&mut self, plain: Self::Plain) {
|
||||
self.unmodulated_value = plain;
|
||||
self.unmodulated_normalized_value = self.preview_normalized(plain);
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
if self.modulation_offset == 0.0 {
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
} else {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + self.modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
}
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
|
@ -214,20 +224,22 @@ impl ParamMut for FloatParam {
|
|||
fn set_normalized_value(&mut self, normalized: f32) {
|
||||
self.unmodulated_value = self.preview_plain(normalized);
|
||||
self.unmodulated_normalized_value = normalized;
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
if self.modulation_offset == 0.0 {
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
} else {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + self.modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
}
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
}
|
||||
|
||||
fn modulate_value(&mut self, modulation_offset: f32) {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
self.modulation_offset = modulation_offset;
|
||||
self.set_normalized_value(self.unmodulated_normalized_value);
|
||||
}
|
||||
|
||||
fn update_smoother(&mut self, sample_rate: f32, reset: bool) {
|
||||
|
@ -248,6 +260,7 @@ impl FloatParam {
|
|||
normalized_value: range.normalize(default),
|
||||
unmodulated_value: default,
|
||||
unmodulated_normalized_value: range.normalize(default),
|
||||
modulation_offset: 0.0,
|
||||
default,
|
||||
smoothed: Smoother::none(),
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ pub struct IntParam {
|
|||
/// The field's value normalized to the `[0, 1]` range before any monophonic automation coming
|
||||
/// from the host has been applied. This will always be the same as `value` for VST3 plugins.
|
||||
unmodulated_normalized_value: f32,
|
||||
/// A value in `[-1, 1]` indicating the amount of modulation applied to
|
||||
/// `unmodulated_normalized_`. This needs to be stored separately since the normalied values are
|
||||
/// clamped, and this value persists after new automation events.
|
||||
modulation_offset: f32,
|
||||
/// The field's default plain, unnormalized value.
|
||||
default: i32,
|
||||
/// An optional smoother that will automatically interpolate between the new automation values
|
||||
|
@ -169,8 +173,14 @@ impl ParamMut for IntParam {
|
|||
fn set_plain_value(&mut self, plain: Self::Plain) {
|
||||
self.unmodulated_value = plain;
|
||||
self.unmodulated_normalized_value = self.preview_normalized(plain);
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
if self.modulation_offset == 0.0 {
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
} else {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + self.modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
}
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
|
@ -179,20 +189,22 @@ impl ParamMut for IntParam {
|
|||
fn set_normalized_value(&mut self, normalized: f32) {
|
||||
self.unmodulated_value = self.preview_plain(normalized);
|
||||
self.unmodulated_normalized_value = normalized;
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
if self.modulation_offset == 0.0 {
|
||||
self.value = self.unmodulated_value;
|
||||
self.normalized_value = self.unmodulated_normalized_value;
|
||||
} else {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + self.modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
}
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
}
|
||||
|
||||
fn modulate_value(&mut self, modulation_offset: f32) {
|
||||
self.normalized_value =
|
||||
(self.unmodulated_normalized_value + modulation_offset).clamp(0.0, 1.0);
|
||||
self.value = self.preview_plain(self.normalized_value);
|
||||
if let Some(f) = &self.value_changed {
|
||||
f(self.value);
|
||||
}
|
||||
self.modulation_offset = modulation_offset;
|
||||
self.set_normalized_value(self.unmodulated_normalized_value);
|
||||
}
|
||||
|
||||
fn update_smoother(&mut self, sample_rate: f32, reset: bool) {
|
||||
|
@ -213,6 +225,7 @@ impl IntParam {
|
|||
normalized_value: range.normalize(default),
|
||||
unmodulated_value: default,
|
||||
unmodulated_normalized_value: range.normalize(default),
|
||||
modulation_offset: 0.0,
|
||||
default,
|
||||
smoothed: Smoother::none(),
|
||||
|
||||
|
|
|
@ -249,9 +249,9 @@ pub enum ClapParamUpdate {
|
|||
/// Set the parameter to this plain value. In our wrapper the plain values are the normalized
|
||||
/// values multiplied by the step count for discrete parameters.
|
||||
PlainValueSet(f64),
|
||||
/// Set a normalized offset for the parameter's plain value. A `PlainValueSet` clears out any
|
||||
/// modulation, and subsequent modulation events replace the previous one. In other words, this
|
||||
/// is not additive. These values should also be divided by the step size.
|
||||
/// Set a normalized offset for the parameter's plain value. Subsequent modulation events
|
||||
/// override the previous one, but `PlainValueSet`s do not override the existing modulation.
|
||||
/// These values should also be divided by the step size.
|
||||
PlainValueMod(f64),
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue