1
0
Fork 0

Add polyphonic modulation IDs to parameters

In a bit we should be able to use this with a new `PolyModulation` note
event to allow polyphonic modulation.
This commit is contained in:
Robbert van der Helm 2022-07-05 19:39:18 +02:00
parent 7ea2851775
commit 992fcfe969
6 changed files with 116 additions and 0 deletions

View file

@ -60,6 +60,21 @@ pub trait Param: Display {
/// Get the unit label for this parameter, if any. /// Get the unit label for this parameter, if any.
fn unit(&self) -> &'static str; fn unit(&self) -> &'static str;
/// Get this parameter's polyphonic modulation ID. If this is set for a parameter in a CLAP
/// plugin, then polyphonic modulation will be enabled for that parameter. Polyphonic modulation
/// is sent through [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`]
/// events containing a **normalized** value for this parameter. This value must be converted to
/// a plain value using [`preview_plain()`][Self::preview_plain()] before it can be used. The
/// plugin should use this value in place of the parameter's normal (smoothed) value for the
/// affected note, and it should apply smooth to these values as necessary.
///
/// # Important
///
/// After enabling polyphonic modulation, the plugin **must** start sending
/// [`NoteEvent::VoiceTerminated`][crate::prelude::NoteEvent::VoiceEnd] events to the host when a voice
/// has fully ended. This allows the host to reuse its modulation resources.
fn poly_modulation_id(&self) -> Option<u32>;
/// Get the unnormalized value for this parameter. /// Get the unnormalized value for this parameter.
fn plain_value(&self) -> Self::Plain; fn plain_value(&self) -> Self::Plain;

View file

@ -36,6 +36,12 @@ pub struct BoolParam {
/// The parameter's human readable display name. /// The parameter's human readable display name.
name: String, name: String,
/// If this parameter has been marked as polyphonically modulatable, then this will be a unique
/// integer identifying the parameter. Because this value is determined by the plugin itself,
/// the plugin can easily map
/// [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`] events to the
/// correct parameter by pattern matching on a constant.
poly_modulation_id: Option<u32>,
/// Optional custom conversion function from a boolean value to a string. /// Optional custom conversion function from a boolean value to a string.
value_to_string: Option<Arc<dyn Fn(bool) -> String + Send + Sync>>, value_to_string: Option<Arc<dyn Fn(bool) -> String + Send + Sync>>,
/// Optional custom conversion function from a string to a boolean value. If the string cannot /// Optional custom conversion function from a string to a boolean value. If the string cannot
@ -65,6 +71,10 @@ impl Param for BoolParam {
"" ""
} }
fn poly_modulation_id(&self) -> Option<u32> {
self.poly_modulation_id
}
#[inline] #[inline]
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.value self.value
@ -207,11 +217,27 @@ impl BoolParam {
value_changed: None, value_changed: None,
name: name.into(), name: name.into(),
poly_modulation_id: None,
value_to_string: None, value_to_string: None,
string_to_value: None, string_to_value: None,
} }
} }
/// Enable polyphonic modulation for this parameter. The ID is used to uniquely identify this
/// parameter in [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`]
/// events, and must thus be unique between _all_ polyphonically modulatable parameters. See the
/// event's documentation for more information on how to use this.
///
/// # Important
///
/// After enabling polyphonic modulation, the plugin **must** start sending
/// [`NoteEvent::VoiceTerminated`][crate::prelude::NoteEvent::VoiceEnd] events to the host when
/// a voice has fully ended. This allows the host to reuse its modulation resources.
pub fn with_poly_modulation_id(mut self, id: u32) -> Self {
self.poly_modulation_id = Some(id);
self
}
/// Run a callback whenever this parameter's value changes. The argument passed to this function /// Run a callback whenever this parameter's value changes. The argument passed to this function
/// is the parameter's new value. This should not do anything expensive as it may be called /// is the parameter's new value. This should not do anything expensive as it may be called
/// 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

View file

@ -117,6 +117,10 @@ impl<T: Enum + PartialEq> Param for EnumParam<T> {
self.inner.unit() self.inner.unit()
} }
fn poly_modulation_id(&self) -> Option<u32> {
self.inner.poly_modulation_id()
}
#[inline] #[inline]
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
T::from_index(self.inner.plain_value() as usize) T::from_index(self.inner.plain_value() as usize)
@ -195,6 +199,10 @@ impl Param for EnumParamInner {
"" ""
} }
fn poly_modulation_id(&self) -> Option<u32> {
self.inner.poly_modulation_id()
}
#[inline] #[inline]
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.inner.plain_value() self.inner.plain_value()
@ -326,6 +334,21 @@ impl<T: Enum + PartialEq + 'static> EnumParam<T> {
} }
} }
/// Enable polyphonic modulation for this parameter. The ID is used to uniquely identify this
/// parameter in [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`]
/// events, and must thus be unique between _all_ polyphonically modulatable parameters. See the
/// event's documentation for more information on how to use this.
///
/// # Important
///
/// After enabling polyphonic modulation, the plugin **must** start sending
/// [`NoteEvent::VoiceTerminated`][crate::prelude::NoteEvent::VoiceEnd] events to the host when
/// a voice has fully ended. This allows the host to reuse its modulation resources.
pub fn with_poly_modulation_id(mut self, id: u32) -> Self {
self.inner.inner = self.inner.inner.with_poly_modulation_id(id);
self
}
/// Run a callback whenever this parameter's value changes. The argument passed to this function /// Run a callback whenever this parameter's value changes. The argument passed to this function
/// is the parameter's new value. This should not do anything expensive as it may be called /// is the parameter's new value. This should not do anything expensive as it may be called
/// 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

View file

@ -64,6 +64,12 @@ pub struct FloatParam {
/// The parameter value's unit, added after [`value_to_string`][Self::value_to_string] if that /// The parameter value's unit, added after [`value_to_string`][Self::value_to_string] if that
/// is set. NIH-plug will not automatically add a space before the unit. /// is set. NIH-plug will not automatically add a space before the unit.
unit: &'static str, unit: &'static str,
/// If this parameter has been marked as polyphonically modulatable, then this will be a unique
/// integer identifying the parameter. Because this value is determined by the plugin itself,
/// the plugin can easily map
/// [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`] events to the
/// correct parameter by pattern matching on a constant.
poly_modulation_id: Option<u32>,
/// Optional custom conversion function from a plain **unnormalized** value to a string. /// Optional custom conversion function from a plain **unnormalized** value to a string.
value_to_string: Option<Arc<dyn Fn(f32) -> String + Send + Sync>>, value_to_string: Option<Arc<dyn Fn(f32) -> 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
@ -99,6 +105,10 @@ impl Param for FloatParam {
self.unit self.unit
} }
fn poly_modulation_id(&self) -> Option<u32> {
self.poly_modulation_id
}
#[inline] #[inline]
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.value self.value
@ -275,11 +285,26 @@ impl FloatParam {
step_size: None, step_size: None,
name: name.into(), name: name.into(),
unit: "", unit: "",
poly_modulation_id: None,
value_to_string: None, value_to_string: None,
string_to_value: None, string_to_value: None,
} }
} }
/// Enable polyphonic modulation for this parameter. The ID is used to uniquely identify this
/// parameter in [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`]
/// events, and must thus be unique between _all_ polyphonically modulatable parameters.
///
/// # Important
///
/// After enabling polyphonic modulation, the plugin **must** start sending
/// [`NoteEvent::VoiceTerminated`][crate::prelude::NoteEvent::VoiceEnd] events to the host when
/// a voice has fully ended. This allows the host to reuse its modulation resources.
pub fn with_poly_modulation_id(mut self, id: u32) -> Self {
self.poly_modulation_id = Some(id);
self
}
/// Set up a smoother that can gradually interpolate changes made to this parameter, preventing /// Set up a smoother that can gradually interpolate changes made to this parameter, preventing
/// clicks and zipper noises. /// clicks and zipper noises.
pub fn with_smoother(mut self, style: SmoothingStyle) -> Self { pub fn with_smoother(mut self, style: SmoothingStyle) -> Self {

View file

@ -60,6 +60,12 @@ pub struct IntParam {
/// 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.
unit: &'static str, unit: &'static str,
/// If this parameter has been marked as polyphonically modulatable, then this will be a unique
/// integer identifying the parameter. Because this value is determined by the plugin itself,
/// the plugin can easily map
/// [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`] events to the
/// correct parameter by pattern matching on a constant.
poly_modulation_id: Option<u32>,
/// Optional custom conversion function from a plain **unnormalized** value to a string. /// Optional custom conversion function from a plain **unnormalized** value to a string.
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
@ -91,6 +97,10 @@ impl Param for IntParam {
self.unit self.unit
} }
fn poly_modulation_id(&self) -> Option<u32> {
self.poly_modulation_id
}
#[inline] #[inline]
fn plain_value(&self) -> Self::Plain { fn plain_value(&self) -> Self::Plain {
self.value self.value
@ -239,11 +249,27 @@ impl IntParam {
range, range,
name: name.into(), name: name.into(),
unit: "", unit: "",
poly_modulation_id: None,
value_to_string: None, value_to_string: None,
string_to_value: None, string_to_value: None,
} }
} }
/// Enable polyphonic modulation for this parameter. The ID is used to uniquely identify this
/// parameter in [`NoteEvent::PolyModulation][crate::prelude::NoteEvent::PolyModulation`]
/// events, and must thus be unique between _all_ polyphonically modulatable parameters. See the
/// event's documentation for more information on how to use this.
///
/// # Important
///
/// After enabling polyphonic modulation, the plugin **must** start sending
/// [`NoteEvent::VoiceTerminated`][crate::prelude::NoteEvent::VoiceEnd] events to the host when
/// a voice has fully ended. This allows the host to reuse its modulation resources.
pub fn with_poly_modulation_id(mut self, id: u32) -> Self {
self.poly_modulation_id = Some(id);
self
}
/// Set up a smoother that can gradually interpolate changes made to this parameter, preventing /// Set up a smoother that can gradually interpolate changes made to this parameter, preventing
/// clicks and zipper noises. /// clicks and zipper noises.
pub fn with_smoother(mut self, style: SmoothingStyle) -> Self { pub fn with_smoother(mut self, style: SmoothingStyle) -> Self {

View file

@ -154,6 +154,7 @@ macro_rules! param_ptr_forward(
impl ParamPtr { impl ParamPtr {
param_ptr_forward!(pub unsafe fn name(&self) -> &str); param_ptr_forward!(pub unsafe fn name(&self) -> &str);
param_ptr_forward!(pub unsafe fn unit(&self) -> &'static str); param_ptr_forward!(pub unsafe fn unit(&self) -> &'static str);
param_ptr_forward!(pub unsafe fn poly_modulation_id(&self) -> Option<u32>);
param_ptr_forward!(pub unsafe fn normalized_value(&self) -> f32); param_ptr_forward!(pub unsafe fn normalized_value(&self) -> f32);
param_ptr_forward!(pub unsafe fn unmodulated_normalized_value(&self) -> f32); param_ptr_forward!(pub unsafe fn unmodulated_normalized_value(&self) -> f32);
param_ptr_forward!(pub unsafe fn default_normalized_value(&self) -> f32); param_ptr_forward!(pub unsafe fn default_normalized_value(&self) -> f32);