Avoid duplicate parameter callbacks and smoothing
REAPER seems to spam value set events when an automation lane is active, and it also always sends CLAP automation events twice.
This commit is contained in:
parent
efff43df21
commit
683c96bca0
10 changed files with 138 additions and 88 deletions
|
@ -198,24 +198,33 @@ pub(crate) trait ParamMut: Param {
|
||||||
/// [`modulate_value()`][Self::modulate_value()] has previously been called with a non zero
|
/// [`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.
|
/// value then this offset is taken into account to form the effective value.
|
||||||
///
|
///
|
||||||
|
/// Returns whether or not the value has changed. Any parameter callbacks are only run the value
|
||||||
|
/// has actually changed.
|
||||||
|
///
|
||||||
/// This does **not** update the smoother.
|
/// This does **not** update the smoother.
|
||||||
fn set_plain_value(&self, plain: Self::Plain);
|
fn set_plain_value(&self, plain: Self::Plain) -> bool;
|
||||||
|
|
||||||
/// Set this parameter based on a normalized value. The normalized value will be snapped to the
|
/// Set this parameter based on a normalized value. The normalized value will be snapped to the
|
||||||
/// step size for continuous parameters (i.e. [`FloatParam`]). If
|
/// step size for continuous parameters (i.e. [`FloatParam`]). If
|
||||||
/// [`modulate_value()`][Self::modulate_value()] has previously been called with a non zero
|
/// [`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.
|
/// value then this offset is taken into account to form the effective value.
|
||||||
///
|
///
|
||||||
|
/// Returns whether or not the value has changed. Any parameter callbacks are only run the value
|
||||||
|
/// has actually changed.
|
||||||
|
///
|
||||||
/// This does **not** update the smoother.
|
/// This does **not** update the smoother.
|
||||||
fn set_normalized_value(&self, normalized: f32);
|
fn set_normalized_value(&self, normalized: f32) -> bool;
|
||||||
|
|
||||||
/// Add a modulation offset to the value's unmodulated value. This value sticks until this
|
/// 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
|
/// 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
|
/// parameter's range. The normalized value will be snapped to the step size for continuous
|
||||||
/// parameters (i.e. [`FloatParam`]).
|
/// parameters (i.e. [`FloatParam`]).
|
||||||
///
|
///
|
||||||
|
/// Returns whether or not the value has changed. Any parameter callbacks are only run the value
|
||||||
|
/// has actually changed.
|
||||||
|
///
|
||||||
/// This does **not** update the smoother.
|
/// This does **not** update the smoother.
|
||||||
fn modulate_value(&self, modulation_offset: f32);
|
fn modulate_value(&self, modulation_offset: f32) -> bool;
|
||||||
|
|
||||||
/// Update the smoother state to point to the current value. Also used when initializing and
|
/// Update the smoother state to point to the current value. Also used when initializing and
|
||||||
/// restoring a plugin so everything is in sync. In that case the smoother should completely
|
/// restoring a plugin so everything is in sync. In that case the smoother should completely
|
||||||
|
|
|
@ -168,7 +168,7 @@ impl Param for BoolParam {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParamMut for BoolParam {
|
impl ParamMut for BoolParam {
|
||||||
fn set_plain_value(&self, plain: Self::Plain) {
|
fn set_plain_value(&self, plain: Self::Plain) -> bool {
|
||||||
let unmodulated_value = plain;
|
let unmodulated_value = plain;
|
||||||
let unmodulated_normalized_value = self.preview_normalized(plain);
|
let unmodulated_normalized_value = self.preview_normalized(plain);
|
||||||
|
|
||||||
|
@ -182,20 +182,28 @@ impl ParamMut for BoolParam {
|
||||||
(self.preview_plain(normalized_value), normalized_value)
|
(self.preview_plain(normalized_value), normalized_value)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.value.store(value, Ordering::Relaxed);
|
// REAPER spams automation events with the same value. This prevents callbacks from firing
|
||||||
|
// multiple times. This can be problematic when they're used to trigger expensive
|
||||||
|
// computations when a parameter changes.
|
||||||
|
let old_value = self.value.swap(value, Ordering::Relaxed);
|
||||||
|
if value != old_value {
|
||||||
self.normalized_value
|
self.normalized_value
|
||||||
.store(normalized_value, Ordering::Relaxed);
|
.store(normalized_value, Ordering::Relaxed);
|
||||||
self.unmodulated_value
|
self.unmodulated_value
|
||||||
.store(unmodulated_value, Ordering::Relaxed);
|
.store(unmodulated_value, Ordering::Relaxed);
|
||||||
self.unmodulated_normalized_value
|
self.unmodulated_normalized_value
|
||||||
.store(unmodulated_normalized_value, Ordering::Relaxed);
|
.store(unmodulated_normalized_value, Ordering::Relaxed);
|
||||||
|
|
||||||
if let Some(f) = &self.value_changed {
|
if let Some(f) = &self.value_changed {
|
||||||
f(value);
|
f(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_normalized_value(&self, normalized: f32) {
|
fn set_normalized_value(&self, normalized: f32) -> bool {
|
||||||
// NOTE: The double conversion here is to make sure the state is reproducible. State is
|
// NOTE: The double conversion here is to make sure the state is reproducible. State is
|
||||||
// saved and restored using plain values, and the new normalized value will be
|
// saved and restored using plain values, and the new normalized value will be
|
||||||
// different from `normalized`. This is not necessary for the modulation as these
|
// different from `normalized`. This is not necessary for the modulation as these
|
||||||
|
@ -203,12 +211,12 @@ impl ParamMut for BoolParam {
|
||||||
self.set_plain_value(self.preview_plain(normalized))
|
self.set_plain_value(self.preview_plain(normalized))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modulate_value(&self, modulation_offset: f32) {
|
fn modulate_value(&self, modulation_offset: f32) -> bool {
|
||||||
self.modulation_offset
|
self.modulation_offset
|
||||||
.store(modulation_offset, Ordering::Relaxed);
|
.store(modulation_offset, Ordering::Relaxed);
|
||||||
|
|
||||||
// TODO: This renormalizes this value, which is not necessary
|
// TODO: This renormalizes this value, which is not necessary
|
||||||
self.set_plain_value(self.unmodulated_plain_value());
|
self.set_plain_value(self.unmodulated_plain_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_smoother(&self, _sample_rate: f32, _init: bool) {
|
fn update_smoother(&self, _sample_rate: f32, _init: bool) {
|
||||||
|
|
|
@ -294,15 +294,15 @@ impl Param for EnumParamInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Enum + PartialEq> ParamMut for EnumParam<T> {
|
impl<T: Enum + PartialEq> ParamMut for EnumParam<T> {
|
||||||
fn set_plain_value(&self, plain: Self::Plain) {
|
fn set_plain_value(&self, plain: Self::Plain) -> bool {
|
||||||
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(&self, normalized: f32) {
|
fn set_normalized_value(&self, normalized: f32) -> bool {
|
||||||
self.inner.set_normalized_value(normalized)
|
self.inner.set_normalized_value(normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modulate_value(&self, modulation_offset: f32) {
|
fn modulate_value(&self, modulation_offset: f32) -> bool {
|
||||||
self.inner.modulate_value(modulation_offset)
|
self.inner.modulate_value(modulation_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,15 +312,15 @@ impl<T: Enum + PartialEq> ParamMut for EnumParam<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParamMut for EnumParamInner {
|
impl ParamMut for EnumParamInner {
|
||||||
fn set_plain_value(&self, plain: Self::Plain) {
|
fn set_plain_value(&self, plain: Self::Plain) -> bool {
|
||||||
self.inner.set_plain_value(plain)
|
self.inner.set_plain_value(plain)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_normalized_value(&self, normalized: f32) {
|
fn set_normalized_value(&self, normalized: f32) -> bool {
|
||||||
self.inner.set_normalized_value(normalized)
|
self.inner.set_normalized_value(normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modulate_value(&self, modulation_offset: f32) {
|
fn modulate_value(&self, modulation_offset: f32) -> bool {
|
||||||
self.inner.modulate_value(modulation_offset)
|
self.inner.modulate_value(modulation_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,7 +202,7 @@ impl Param for FloatParam {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParamMut for FloatParam {
|
impl ParamMut for FloatParam {
|
||||||
fn set_plain_value(&self, plain: Self::Plain) {
|
fn set_plain_value(&self, plain: Self::Plain) -> bool {
|
||||||
let unmodulated_value = plain;
|
let unmodulated_value = plain;
|
||||||
let unmodulated_normalized_value = self.preview_normalized(plain);
|
let unmodulated_normalized_value = self.preview_normalized(plain);
|
||||||
|
|
||||||
|
@ -216,20 +216,28 @@ impl ParamMut for FloatParam {
|
||||||
(self.preview_plain(normalized_value), normalized_value)
|
(self.preview_plain(normalized_value), normalized_value)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.value.store(value, Ordering::Relaxed);
|
// REAPER spams automation events with the same value. This prevents callbacks from firing
|
||||||
|
// multiple times. This can be problematic when they're used to trigger expensive
|
||||||
|
// computations when a parameter changes.
|
||||||
|
let old_value = self.value.swap(value, Ordering::Relaxed);
|
||||||
|
if value != old_value {
|
||||||
self.normalized_value
|
self.normalized_value
|
||||||
.store(normalized_value, Ordering::Relaxed);
|
.store(normalized_value, Ordering::Relaxed);
|
||||||
self.unmodulated_value
|
self.unmodulated_value
|
||||||
.store(unmodulated_value, Ordering::Relaxed);
|
.store(unmodulated_value, Ordering::Relaxed);
|
||||||
self.unmodulated_normalized_value
|
self.unmodulated_normalized_value
|
||||||
.store(unmodulated_normalized_value, Ordering::Relaxed);
|
.store(unmodulated_normalized_value, Ordering::Relaxed);
|
||||||
|
|
||||||
if let Some(f) = &self.value_changed {
|
if let Some(f) = &self.value_changed {
|
||||||
f(value);
|
f(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_normalized_value(&self, normalized: f32) {
|
fn set_normalized_value(&self, normalized: f32) -> bool {
|
||||||
// NOTE: The double conversion here is to make sure the state is reproducible. State is
|
// NOTE: The double conversion here is to make sure the state is reproducible. State is
|
||||||
// saved and restored using plain values, and the new normalized value will be
|
// saved and restored using plain values, and the new normalized value will be
|
||||||
// different from `normalized`. This is not necessary for the modulation as these
|
// different from `normalized`. This is not necessary for the modulation as these
|
||||||
|
@ -237,12 +245,12 @@ impl ParamMut for FloatParam {
|
||||||
self.set_plain_value(self.preview_plain(normalized))
|
self.set_plain_value(self.preview_plain(normalized))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modulate_value(&self, modulation_offset: f32) {
|
fn modulate_value(&self, modulation_offset: f32) -> bool {
|
||||||
self.modulation_offset
|
self.modulation_offset
|
||||||
.store(modulation_offset, Ordering::Relaxed);
|
.store(modulation_offset, Ordering::Relaxed);
|
||||||
|
|
||||||
// TODO: This renormalizes this value, which is not necessary
|
// TODO: This renormalizes this value, which is not necessary
|
||||||
self.set_plain_value(self.unmodulated_plain_value());
|
self.set_plain_value(self.unmodulated_plain_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_smoother(&self, sample_rate: f32, reset: bool) {
|
fn update_smoother(&self, sample_rate: f32, reset: bool) {
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl Param for IntParam {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParamMut for IntParam {
|
impl ParamMut for IntParam {
|
||||||
fn set_plain_value(&self, plain: Self::Plain) {
|
fn set_plain_value(&self, plain: Self::Plain) -> bool {
|
||||||
let unmodulated_value = plain;
|
let unmodulated_value = plain;
|
||||||
let unmodulated_normalized_value = self.preview_normalized(plain);
|
let unmodulated_normalized_value = self.preview_normalized(plain);
|
||||||
|
|
||||||
|
@ -196,20 +196,28 @@ impl ParamMut for IntParam {
|
||||||
(self.preview_plain(normalized_value), normalized_value)
|
(self.preview_plain(normalized_value), normalized_value)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.value.store(value, Ordering::Relaxed);
|
// REAPER spams automation events with the same value. This prevents callbacks from firing
|
||||||
|
// multiple times. This can be problematic when they're used to trigger expensive
|
||||||
|
// computations when a parameter changes.
|
||||||
|
let old_value = self.value.swap(value, Ordering::Relaxed);
|
||||||
|
if value != old_value {
|
||||||
self.normalized_value
|
self.normalized_value
|
||||||
.store(normalized_value, Ordering::Relaxed);
|
.store(normalized_value, Ordering::Relaxed);
|
||||||
self.unmodulated_value
|
self.unmodulated_value
|
||||||
.store(unmodulated_value, Ordering::Relaxed);
|
.store(unmodulated_value, Ordering::Relaxed);
|
||||||
self.unmodulated_normalized_value
|
self.unmodulated_normalized_value
|
||||||
.store(unmodulated_normalized_value, Ordering::Relaxed);
|
.store(unmodulated_normalized_value, Ordering::Relaxed);
|
||||||
|
|
||||||
if let Some(f) = &self.value_changed {
|
if let Some(f) = &self.value_changed {
|
||||||
f(value);
|
f(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_normalized_value(&self, normalized: f32) {
|
fn set_normalized_value(&self, normalized: f32) -> bool {
|
||||||
// NOTE: The double conversion here is to make sure the state is reproducible. State is
|
// NOTE: The double conversion here is to make sure the state is reproducible. State is
|
||||||
// saved and restored using plain values, and the new normalized value will be
|
// saved and restored using plain values, and the new normalized value will be
|
||||||
// different from `normalized`. This is not necessary for the modulation as these
|
// different from `normalized`. This is not necessary for the modulation as these
|
||||||
|
@ -217,12 +225,12 @@ impl ParamMut for IntParam {
|
||||||
self.set_plain_value(self.preview_plain(normalized))
|
self.set_plain_value(self.preview_plain(normalized))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modulate_value(&self, modulation_offset: f32) {
|
fn modulate_value(&self, modulation_offset: f32) -> bool {
|
||||||
self.modulation_offset
|
self.modulation_offset
|
||||||
.store(modulation_offset, Ordering::Relaxed);
|
.store(modulation_offset, Ordering::Relaxed);
|
||||||
|
|
||||||
// TODO: This renormalizes this value, which is not necessary
|
// TODO: This renormalizes this value, which is not necessary
|
||||||
self.set_plain_value(self.unmodulated_plain_value());
|
self.set_plain_value(self.unmodulated_plain_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_smoother(&self, sample_rate: f32, reset: bool) {
|
fn update_smoother(&self, sample_rate: f32, reset: bool) {
|
||||||
|
|
|
@ -74,8 +74,8 @@ impl ParamPtr {
|
||||||
param_ptr_forward!(pub unsafe fn string_to_normalized_value(&self, string: &str) -> Option<f32>);
|
param_ptr_forward!(pub unsafe fn string_to_normalized_value(&self, string: &str) -> Option<f32>);
|
||||||
param_ptr_forward!(pub unsafe fn flags(&self) -> ParamFlags);
|
param_ptr_forward!(pub unsafe fn flags(&self) -> ParamFlags);
|
||||||
|
|
||||||
param_ptr_forward!(pub(crate) unsafe fn set_normalized_value(&self, normalized: f32));
|
param_ptr_forward!(pub(crate) unsafe fn set_normalized_value(&self, normalized: f32) -> bool);
|
||||||
param_ptr_forward!(pub(crate) unsafe fn modulate_value(&self, modulation_offset: f32));
|
param_ptr_forward!(pub(crate) unsafe fn modulate_value(&self, modulation_offset: f32) -> bool);
|
||||||
param_ptr_forward!(pub(crate) unsafe fn update_smoother(&self, sample_rate: f32, reset: bool));
|
param_ptr_forward!(pub(crate) unsafe fn update_smoother(&self, sample_rate: f32, reset: bool));
|
||||||
|
|
||||||
// These functions involve casts since the plugin formats only do floating point types, so we
|
// These functions involve casts since the plugin formats only do floating point types, so we
|
||||||
|
|
|
@ -866,17 +866,20 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
let normalized_value = clap_plain_value as f32
|
let normalized_value = clap_plain_value as f32
|
||||||
/ unsafe { param_ptr.step_count() }.unwrap_or(1) as f32;
|
/ unsafe { param_ptr.step_count() }.unwrap_or(1) as f32;
|
||||||
|
|
||||||
// Also update the parameter's smoothing if applicable
|
if unsafe { param_ptr.set_normalized_value(normalized_value) } {
|
||||||
unsafe { param_ptr.set_normalized_value(normalized_value) };
|
|
||||||
if let Some(sample_rate) = sample_rate {
|
if let Some(sample_rate) = sample_rate {
|
||||||
unsafe { param_ptr.update_smoother(sample_rate, false) };
|
unsafe { param_ptr.update_smoother(sample_rate, false) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// The GUI needs to be informed about the changed parameter value. This
|
// The GUI needs to be informed about the changed parameter value. This
|
||||||
// triggers an `Editor::param_value_changed()` call on the GUI thread.
|
// triggers an `Editor::param_value_changed()` call on the GUI thread.
|
||||||
let task_posted =
|
let task_posted = self
|
||||||
self.schedule_gui(Task::ParameterValueChanged(hash, normalized_value));
|
.schedule_gui(Task::ParameterValueChanged(hash, normalized_value));
|
||||||
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
|
nih_debug_assert!(
|
||||||
|
task_posted,
|
||||||
|
"The task queue is full, dropping task..."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -884,15 +887,20 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
let normalized_delta = clap_plain_delta as f32
|
let normalized_delta = clap_plain_delta as f32
|
||||||
/ unsafe { param_ptr.step_count() }.unwrap_or(1) as f32;
|
/ unsafe { param_ptr.step_count() }.unwrap_or(1) as f32;
|
||||||
|
|
||||||
// Also update the parameter's smoothing if applicable
|
if unsafe { param_ptr.modulate_value(normalized_delta) } {
|
||||||
unsafe { param_ptr.modulate_value(normalized_delta) };
|
|
||||||
if let Some(sample_rate) = sample_rate {
|
if let Some(sample_rate) = sample_rate {
|
||||||
unsafe { param_ptr.update_smoother(sample_rate, false) };
|
unsafe { param_ptr.update_smoother(sample_rate, false) };
|
||||||
}
|
}
|
||||||
|
|
||||||
let task_posted = self
|
let task_posted = self.schedule_gui(Task::ParameterModulationChanged(
|
||||||
.schedule_gui(Task::ParameterModulationChanged(hash, normalized_delta));
|
hash,
|
||||||
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
|
normalized_delta,
|
||||||
|
));
|
||||||
|
nih_debug_assert!(
|
||||||
|
task_posted,
|
||||||
|
"The task queue is full, dropping task..."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -522,11 +522,17 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
|
||||||
while let Some((param_ptr, normalized_value)) =
|
while let Some((param_ptr, normalized_value)) =
|
||||||
self.unprocessed_param_changes.pop()
|
self.unprocessed_param_changes.pop()
|
||||||
{
|
{
|
||||||
unsafe { param_ptr.set_normalized_value(normalized_value) };
|
if unsafe { param_ptr.set_normalized_value(normalized_value) } {
|
||||||
unsafe { param_ptr.update_smoother(sample_rate, false) };
|
unsafe { param_ptr.update_smoother(sample_rate, false) };
|
||||||
let task_posted = self
|
let task_posted = self.schedule_gui(Task::ParameterValueChanged(
|
||||||
.schedule_gui(Task::ParameterValueChanged(param_ptr, normalized_value));
|
param_ptr,
|
||||||
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
|
normalized_value,
|
||||||
|
));
|
||||||
|
nih_debug_assert!(
|
||||||
|
task_posted,
|
||||||
|
"The task queue is full, dropping task..."
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// After processing audio, we'll check if the editor has sent us updated plugin
|
// After processing audio, we'll check if the editor has sent us updated plugin
|
||||||
|
|
|
@ -182,14 +182,20 @@ pub(crate) unsafe fn deserialize_object<P: Plugin>(
|
||||||
};
|
};
|
||||||
|
|
||||||
match (param_ptr, param_value) {
|
match (param_ptr, param_value) {
|
||||||
(ParamPtr::FloatParam(p), ParamValue::F32(v)) => (*p).set_plain_value(*v),
|
(ParamPtr::FloatParam(p), ParamValue::F32(v)) => {
|
||||||
(ParamPtr::IntParam(p), ParamValue::I32(v)) => (*p).set_plain_value(*v),
|
(*p).set_plain_value(*v);
|
||||||
(ParamPtr::BoolParam(p), ParamValue::Bool(v)) => (*p).set_plain_value(*v),
|
}
|
||||||
|
(ParamPtr::IntParam(p), ParamValue::I32(v)) => {
|
||||||
|
(*p).set_plain_value(*v);
|
||||||
|
}
|
||||||
|
(ParamPtr::BoolParam(p), ParamValue::Bool(v)) => {
|
||||||
|
(*p).set_plain_value(*v);
|
||||||
|
}
|
||||||
// Enums are either serialized based on the active variant's index (which may not be the
|
// Enums are either serialized based on the active variant's index (which may not be the
|
||||||
// same as the discriminator), or a custom set stable string ID. The latter allows the
|
// same as the discriminator), or a custom set stable string ID. The latter allows the
|
||||||
// variants to be reordered.
|
// variants to be reordered.
|
||||||
(ParamPtr::EnumParam(p), ParamValue::I32(variant_idx)) => {
|
(ParamPtr::EnumParam(p), ParamValue::I32(variant_idx)) => {
|
||||||
(*p).set_plain_value(*variant_idx)
|
(*p).set_plain_value(*variant_idx);
|
||||||
}
|
}
|
||||||
(ParamPtr::EnumParam(p), ParamValue::String(id)) => {
|
(ParamPtr::EnumParam(p), ParamValue::String(id)) => {
|
||||||
let deserialized_enum = (*p).set_from_id(id);
|
let deserialized_enum = (*p).set_from_id(id);
|
||||||
|
|
|
@ -448,18 +448,15 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
||||||
) -> tresult {
|
) -> tresult {
|
||||||
match self.param_by_hash.get(&hash) {
|
match self.param_by_hash.get(&hash) {
|
||||||
Some(param_ptr) => {
|
Some(param_ptr) => {
|
||||||
// Also update the parameter's smoothing if applicable
|
if unsafe { param_ptr.set_normalized_value(normalized_value) } {
|
||||||
match (param_ptr, sample_rate) {
|
if let Some(sample_rate) = sample_rate {
|
||||||
(_, Some(sample_rate)) => unsafe {
|
unsafe { param_ptr.update_smoother(sample_rate, false) };
|
||||||
param_ptr.set_normalized_value(normalized_value);
|
|
||||||
param_ptr.update_smoother(sample_rate, false);
|
|
||||||
},
|
|
||||||
_ => unsafe { param_ptr.set_normalized_value(normalized_value) },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let task_posted =
|
let task_posted =
|
||||||
self.schedule_gui(Task::ParameterValueChanged(hash, normalized_value));
|
self.schedule_gui(Task::ParameterValueChanged(hash, normalized_value));
|
||||||
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
|
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
|
||||||
|
}
|
||||||
|
|
||||||
kResultOk
|
kResultOk
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue