Move the Params trait out of params::internals
This makes much more sense, since this trait is a cornerstone of NIH-plug.
This commit is contained in:
parent
4f74b4b4cc
commit
fb71d0fcce
|
@ -6,6 +6,13 @@ new and what's changed, this document lists all breaking changes in reverse
|
|||
chronological order. If a new feature did not require any changes to existing
|
||||
code then it will not be listed here.
|
||||
|
||||
## [2022-10-20]
|
||||
|
||||
- Some items have been moved out of `nih_plug::param::internals`. The main
|
||||
`Params` trait is now located under `nih_plug::param`, and the
|
||||
`PersistentTrait` trait, implementations, and helper functions are now part of
|
||||
a new `nih_plug::param::persist` module.
|
||||
|
||||
## [2022-10-13]
|
||||
|
||||
- The `#[nested]` parameter attribute has gained super powers and has its syntax
|
||||
|
|
|
@ -235,7 +235,7 @@ pub trait IcedEditor: 'static + Send + Sync + Sized {
|
|||
#[derive(Serialize, Deserialize)]
|
||||
pub struct IcedState {
|
||||
/// The window's size in logical pixels before applying `scale_factor`.
|
||||
#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]
|
||||
#[serde(with = "nih_plug::param::persist::serialize_atomic_cell")]
|
||||
size: AtomicCell<(u32, u32)>,
|
||||
/// Whether the editor's window is currently open.
|
||||
#[serde(skip)]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use baseview::{WindowHandle, WindowScalePolicy};
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use nih_plug::param::internals::PersistentField;
|
||||
use nih_plug::param::persist::PersistentField;
|
||||
use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
|
|
@ -220,7 +220,7 @@ pub struct Transport {
|
|||
}
|
||||
|
||||
/// A convenience helper for setting parameter values. Any changes made here will be broadcasted to
|
||||
/// the host and reflected in the plugin's [`Params`][crate::param::internals::Params] object. These
|
||||
/// the host and reflected in the plugin's [`Params`][crate::param::Params] object. These
|
||||
/// functions should only be called from the main thread.
|
||||
pub struct ParamSetter<'a> {
|
||||
pub raw_context: &'a dyn GuiContext,
|
||||
|
|
113
src/param.rs
113
src/param.rs
|
@ -1,10 +1,17 @@
|
|||
//! NIH-plug can handle floating point, integer, boolean, and enum parameters. Parameters are
|
||||
//! managed by creating a struct deriving the [`Params`][internals::Params] trait containing fields
|
||||
//! managed by creating a struct deriving the [`Params`][Params] trait containing fields
|
||||
//! for those parameter types, and then returning a reference to that object from your
|
||||
//! [`Plugin::params()`][crate::prelude::Plugin::params()] method. See the `Params` trait for more
|
||||
//! information.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Display;
|
||||
use std::sync::Arc;
|
||||
|
||||
use self::internals::ParamPtr;
|
||||
|
||||
// The proc-macro for deriving `Params`
|
||||
pub use nih_plug_derive::Params;
|
||||
|
||||
// Parameter types
|
||||
mod boolean;
|
||||
|
@ -158,7 +165,7 @@ pub trait Param: Display {
|
|||
/// Flags to control the parameter's behavior. See [`ParamFlags`].
|
||||
fn flags(&self) -> ParamFlags;
|
||||
|
||||
/// Internal implementation detail for implementing [`Params`][internals::Params]. This should
|
||||
/// Internal implementation detail for implementing [`Params`][Params]. This should
|
||||
/// not be used directly.
|
||||
fn as_ptr(&self) -> internals::ParamPtr;
|
||||
}
|
||||
|
@ -194,3 +201,105 @@ pub(crate) trait ParamMut: Param {
|
|||
/// reset to the current value.
|
||||
fn update_smoother(&self, sample_rate: f32, reset: bool);
|
||||
}
|
||||
|
||||
/// Describes a struct containing parameters and other persistent fields.
|
||||
///
|
||||
/// # Deriving `Params` and `#[id = "stable"]`
|
||||
///
|
||||
/// This trait can be derived on a struct containing [`FloatParam`][super::FloatParam] and other
|
||||
/// parameter fields by adding `#[derive(Params)]`. When deriving this trait, any of those parameter
|
||||
/// fields should have the `#[id = "stable"]` attribute, where `stable` is an up to 6 character long
|
||||
/// string (to avoid collisions) that will be used to identify the parameter internally so you can
|
||||
/// safely move it around and rename the field without breaking compatibility with old presets.
|
||||
///
|
||||
/// ## `#[persist = "key"]`
|
||||
///
|
||||
/// The struct can also contain other fields that should be persisted along with the rest of the
|
||||
/// preset data. These fields should be [`PersistentField`]s annotated with the `#[persist = "key"]`
|
||||
/// attribute containing types that can be serialized and deserialized with
|
||||
/// [Serde](https://serde.rs/).
|
||||
///
|
||||
/// ## `#[nested]`, `#[nested(group_name = "group name")]`
|
||||
///
|
||||
/// Finally, the `Params` object may include parameters from other objects. Setting a group name is
|
||||
/// optional, but some hosts can use this information to display the parameters in a tree structure.
|
||||
/// Parameter IDs and persisting keys still need to be **unique** when using nested parameter
|
||||
/// structs. This currently has the following caveats:
|
||||
///
|
||||
/// - Enforcing that parameter IDs and persist keys are unique does not work across nested structs.
|
||||
/// - Deserializing persisted fields will give false positives about fields not existing.
|
||||
///
|
||||
/// Take a look at the example gain example plugin to see how this is used.
|
||||
///
|
||||
/// ## `#[nested(id_prefix = "foo", group_name = "Foo")]`
|
||||
///
|
||||
/// Adding this attribute to a `Params` sub-object works similarly to the regular `#[nested]`
|
||||
/// attribute, but it also adds an ID to all parameters from the nested object. If a parameter in
|
||||
/// the nested nested object normally has parameter ID `bar`, the parameter's ID will now be renamed
|
||||
/// to `foo_bar`. _This makes it possible to reuse same parameter struct with different names and
|
||||
/// parameter indices._
|
||||
///
|
||||
/// This does **not** support persistent fields.
|
||||
///
|
||||
/// ## `#[nested(array, group_name = "Foo")]`
|
||||
///
|
||||
/// This can be applied to an array-like data structure and it works similar to a `nested` attribute
|
||||
/// with an `id_name`, except that it will iterate over the array and create unique indices for all
|
||||
/// nested parameters. If the nested parameters object has a parameter called `bar`, then that
|
||||
/// parameter will belong to the group `Foo {array_index + 1}`, and it will have the renamed
|
||||
/// parameter ID `bar_{array_index + 1}`.
|
||||
///
|
||||
/// This does **not** support persistent fields.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This implementation is safe when using from the wrapper because the plugin's returned `Params`
|
||||
/// object lives in an `Arc`, and the wrapper also holds a reference to this `Arc`.
|
||||
pub unsafe trait Params: 'static + Send + Sync {
|
||||
/// Create a mapping from unique parameter IDs to parameter pointers along with the name of the
|
||||
/// group/unit/module they are in, as a `(param_id, param_ptr, group)` triple. The order of the
|
||||
/// `Vec` determines the display order in the (host's) generic UI. The group name is either an
|
||||
/// empty string for top level parameters, or a slash/delimited `"group name 1/Group Name 2"` if
|
||||
/// this `Params` object contains nested child objects. All components of a group path must
|
||||
/// exist or you may encounter panics. The derive macro does this for every parameter field
|
||||
/// marked with `#[id = "stable"]`, and it also inlines all fields from nested child `Params`
|
||||
/// structs marked with `#[nested(...)]` while prefixing that group name before the parameter's
|
||||
/// original group name. Dereferencing the pointers stored in the values is only valid as long
|
||||
/// as this object is valid.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This uses `String` even though for the `Params` derive macro `&'static str` would have been
|
||||
/// fine to be able to support custom reusable Params implementations.
|
||||
fn param_map(&self) -> Vec<(String, ParamPtr, String)>;
|
||||
|
||||
/// Serialize all fields marked with `#[persist = "stable_name"]` into a hash map containing
|
||||
/// JSON-representations of those fields so they can be written to the plugin's state and
|
||||
/// recalled later. This uses [`serialize_field()`] under the hood.
|
||||
fn serialize_fields(&self) -> BTreeMap<String, String> {
|
||||
BTreeMap::new()
|
||||
}
|
||||
|
||||
/// Restore all fields marked with `#[persist = "stable_name"]` from a hashmap created by
|
||||
/// [`serialize_fields()`][Self::serialize_fields()]. All of these fields should be wrapped in a
|
||||
/// [`PersistentField`] with thread safe interior mutability, like an `RwLock` or a `Mutex`.
|
||||
/// This gets called when the plugin's state is being restored. This uses [deserialize_field()]
|
||||
/// under the hood.
|
||||
#[allow(unused_variables)]
|
||||
fn deserialize_fields(&self, serialized: &BTreeMap<String, String>) {}
|
||||
}
|
||||
|
||||
/// This may be useful when building generic UIs using nested `Params` objects.
|
||||
unsafe impl<P: Params> Params for Arc<P> {
|
||||
fn param_map(&self) -> Vec<(String, ParamPtr, String)> {
|
||||
self.as_ref().param_map()
|
||||
}
|
||||
|
||||
fn serialize_fields(&self) -> BTreeMap<String, String> {
|
||||
self.as_ref().serialize_fields()
|
||||
}
|
||||
|
||||
fn deserialize_fields(&self, serialized: &BTreeMap<String, String>) {
|
||||
self.as_ref().deserialize_fields(serialized)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
//! Implementation details for the parameter management.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{Param, ParamFlags, ParamMut};
|
||||
|
||||
pub use nih_plug_derive::Params;
|
||||
/// Re-export for use in the [`Params`] proc-macro.
|
||||
pub use serde_json::from_str as deserialize_field;
|
||||
/// Re-export for use in the [`Params`] proc-macro.
|
||||
|
@ -34,108 +30,6 @@ pub mod serialize_atomic_cell {
|
|||
}
|
||||
}
|
||||
|
||||
/// Describes a struct containing parameters and other persistent fields.
|
||||
///
|
||||
/// # Deriving `Params` and `#[id = "stable"]`
|
||||
///
|
||||
/// This trait can be derived on a struct containing [`FloatParam`][super::FloatParam] and other
|
||||
/// parameter fields by adding `#[derive(Params)]`. When deriving this trait, any of those parameter
|
||||
/// fields should have the `#[id = "stable"]` attribute, where `stable` is an up to 6 character long
|
||||
/// string (to avoid collisions) that will be used to identify the parameter internally so you can
|
||||
/// safely move it around and rename the field without breaking compatibility with old presets.
|
||||
///
|
||||
/// ## `#[persist = "key"]`
|
||||
///
|
||||
/// The struct can also contain other fields that should be persisted along with the rest of the
|
||||
/// preset data. These fields should be [`PersistentField`]s annotated with the `#[persist = "key"]`
|
||||
/// attribute containing types that can be serialized and deserialized with
|
||||
/// [Serde](https://serde.rs/).
|
||||
///
|
||||
/// ## `#[nested]`, `#[nested(group_name = "group name")]`
|
||||
///
|
||||
/// Finally, the `Params` object may include parameters from other objects. Setting a group name is
|
||||
/// optional, but some hosts can use this information to display the parameters in a tree structure.
|
||||
/// Parameter IDs and persisting keys still need to be **unique** when using nested parameter
|
||||
/// structs. This currently has the following caveats:
|
||||
///
|
||||
/// - Enforcing that parameter IDs and persist keys are unique does not work across nested structs.
|
||||
/// - Deserializing persisted fields will give false positives about fields not existing.
|
||||
///
|
||||
/// Take a look at the example gain example plugin to see how this is used.
|
||||
///
|
||||
/// ## `#[nested(id_prefix = "foo", group_name = "Foo")]`
|
||||
///
|
||||
/// Adding this attribute to a `Params` sub-object works similarly to the regular `#[nested]`
|
||||
/// attribute, but it also adds an ID to all parameters from the nested object. If a parameter in
|
||||
/// the nested nested object normally has parameter ID `bar`, the parameter's ID will now be renamed
|
||||
/// to `foo_bar`. _This makes it possible to reuse same parameter struct with different names and
|
||||
/// parameter indices._
|
||||
///
|
||||
/// This does **not** support persistent fields.
|
||||
///
|
||||
/// ## `#[nested(array, group_name = "Foo")]`
|
||||
///
|
||||
/// This can be applied to an array-like data structure and it works similar to a `nested` attribute
|
||||
/// with an `id_name`, except that it will iterate over the array and create unique indices for all
|
||||
/// nested parameters. If the nested parameters object has a parameter called `bar`, then that
|
||||
/// parameter will belong to the group `Foo {array_index + 1}`, and it will have the renamed
|
||||
/// parameter ID `bar_{array_index + 1}`.
|
||||
///
|
||||
/// This does **not** support persistent fields.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This implementation is safe when using from the wrapper because the plugin's returned `Params`
|
||||
/// object lives in an `Arc`, and the wrapper also holds a reference to this `Arc`.
|
||||
pub unsafe trait Params: 'static + Send + Sync {
|
||||
/// Create a mapping from unique parameter IDs to parameter pointers along with the name of the
|
||||
/// group/unit/module they are in, as a `(param_id, param_ptr, group)` triple. The order of the
|
||||
/// `Vec` determines the display order in the (host's) generic UI. The group name is either an
|
||||
/// empty string for top level parameters, or a slash/delimited `"group name 1/Group Name 2"` if
|
||||
/// this `Params` object contains nested child objects. All components of a group path must
|
||||
/// exist or you may encounter panics. The derive macro does this for every parameter field
|
||||
/// marked with `#[id = "stable"]`, and it also inlines all fields from nested child `Params`
|
||||
/// structs marked with `#[nested(...)]` while prefixing that group name before the parameter's
|
||||
/// original group name. Dereferencing the pointers stored in the values is only valid as long
|
||||
/// as this object is valid.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This uses `String` even though for the `Params` derive macro `&'static str` would have been
|
||||
/// fine to be able to support custom reusable Params implementations.
|
||||
fn param_map(&self) -> Vec<(String, ParamPtr, String)>;
|
||||
|
||||
/// Serialize all fields marked with `#[persist = "stable_name"]` into a hash map containing
|
||||
/// JSON-representations of those fields so they can be written to the plugin's state and
|
||||
/// recalled later. This uses [`serialize_field()`] under the hood.
|
||||
fn serialize_fields(&self) -> BTreeMap<String, String> {
|
||||
BTreeMap::new()
|
||||
}
|
||||
|
||||
/// Restore all fields marked with `#[persist = "stable_name"]` from a hashmap created by
|
||||
/// [`serialize_fields()`][Self::serialize_fields()]. All of these fields should be wrapped in a
|
||||
/// [`PersistentField`] with thread safe interior mutability, like an `RwLock` or a `Mutex`.
|
||||
/// This gets called when the plugin's state is being restored. This uses [deserialize_field()]
|
||||
/// under the hood.
|
||||
#[allow(unused_variables)]
|
||||
fn deserialize_fields(&self, serialized: &BTreeMap<String, String>) {}
|
||||
}
|
||||
|
||||
/// This may be useful when building generic UIs using nested `Params` objects.
|
||||
unsafe impl<P: Params> Params for Arc<P> {
|
||||
fn param_map(&self) -> Vec<(String, ParamPtr, String)> {
|
||||
self.as_ref().param_map()
|
||||
}
|
||||
|
||||
fn serialize_fields(&self) -> BTreeMap<String, String> {
|
||||
self.as_ref().serialize_fields()
|
||||
}
|
||||
|
||||
fn deserialize_fields(&self, serialized: &BTreeMap<String, String>) {
|
||||
self.as_ref().deserialize_fields(serialized)
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal pointers to parameters. This is an implementation detail used by the wrappers for type
|
||||
/// erasure.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::Arc;
|
|||
use crate::buffer::Buffer;
|
||||
use crate::context::{GuiContext, InitContext, ProcessContext};
|
||||
use crate::midi::MidiConfig;
|
||||
use crate::param::internals::Params;
|
||||
use crate::param::Params;
|
||||
use crate::wrapper::clap::features::ClapFeature;
|
||||
|
||||
/// Basic functionality that needs to be implemented by a plugin. The wrappers will use this to
|
||||
|
|
|
@ -15,9 +15,10 @@ pub use crate::context::{GuiContext, InitContext, ParamSetter, PluginApi, Proces
|
|||
// This also includes the derive macro
|
||||
pub use crate::midi::{control_change, MidiConfig, NoteEvent};
|
||||
pub use crate::param::enums::{Enum, EnumParam};
|
||||
pub use crate::param::internals::{ParamPtr, Params};
|
||||
pub use crate::param::internals::ParamPtr;
|
||||
pub use crate::param::range::{FloatRange, IntRange};
|
||||
pub use crate::param::smoothing::{Smoothable, Smoother, SmoothingStyle};
|
||||
pub use crate::param::Params;
|
||||
pub use crate::param::{BoolParam, FloatParam, IntParam, Param, ParamFlags};
|
||||
pub use crate::plugin::{
|
||||
AuxiliaryBuffers, AuxiliaryIOConfig, BufferConfig, BusConfig, ClapPlugin, Editor,
|
||||
|
|
|
@ -80,8 +80,8 @@ use crate::buffer::Buffer;
|
|||
use crate::context::Transport;
|
||||
use crate::event_loop::{EventLoop, MainThreadExecutor, TASK_QUEUE_CAPACITY};
|
||||
use crate::midi::{MidiConfig, NoteEvent};
|
||||
use crate::param::internals::{ParamPtr, Params};
|
||||
use crate::param::ParamFlags;
|
||||
use crate::param::internals::ParamPtr;
|
||||
use crate::param::{ParamFlags, Params};
|
||||
use crate::plugin::{
|
||||
AuxiliaryBuffers, BufferConfig, BusConfig, ClapPlugin, Editor, ParentWindowHandle, ProcessMode,
|
||||
ProcessStatus,
|
||||
|
|
|
@ -15,8 +15,8 @@ use super::config::WrapperConfig;
|
|||
use super::context::{WrapperGuiContext, WrapperInitContext, WrapperProcessContext};
|
||||
use crate::context::Transport;
|
||||
use crate::midi::NoteEvent;
|
||||
use crate::param::internals::{ParamPtr, Params};
|
||||
use crate::param::ParamFlags;
|
||||
use crate::param::internals::ParamPtr;
|
||||
use crate::param::{ParamFlags, Params};
|
||||
use crate::plugin::{
|
||||
AuxiliaryBuffers, AuxiliaryIOConfig, BufferConfig, BusConfig, Editor, ParentWindowHandle,
|
||||
Plugin, ProcessMode, ProcessStatus,
|
||||
|
|
|
@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize};
|
|||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::param::internals::{ParamPtr, Params};
|
||||
use crate::param::{Param, ParamMut};
|
||||
use crate::param::internals::ParamPtr;
|
||||
use crate::param::{Param, ParamMut, Params};
|
||||
use crate::plugin::{BufferConfig, Plugin};
|
||||
|
||||
// These state objects are also exposed directly to the plugin so it can do its own internal preset
|
||||
|
@ -45,7 +45,7 @@ pub struct PluginState {
|
|||
/// parameter automation though, depending on how the host implements that.
|
||||
pub params: BTreeMap<String, ParamValue>,
|
||||
/// Arbitrary fields that should be persisted together with the plugin's parameters. Any field
|
||||
/// on the [`Params`][crate::param::internals::Params] struct that's annotated with `#[persist =
|
||||
/// on the [`Params`][crate::param::Params] struct that's annotated with `#[persist =
|
||||
/// "stable_name"]` will be persisted this way.
|
||||
///
|
||||
/// The individual fields are also serialized as JSON so they can safely be restored
|
||||
|
|
|
@ -18,8 +18,8 @@ use crate::buffer::Buffer;
|
|||
use crate::context::Transport;
|
||||
use crate::event_loop::{EventLoop, MainThreadExecutor, OsEventLoop};
|
||||
use crate::midi::{MidiConfig, NoteEvent};
|
||||
use crate::param::internals::{ParamPtr, Params};
|
||||
use crate::param::ParamFlags;
|
||||
use crate::param::internals::ParamPtr;
|
||||
use crate::param::{ParamFlags, Params};
|
||||
use crate::plugin::{BufferConfig, BusConfig, Editor, ProcessMode, ProcessStatus, Vst3Plugin};
|
||||
use crate::wrapper::state::{self, PluginState};
|
||||
use crate::wrapper::util::{hash_param_id, process_wrapper};
|
||||
|
|
Loading…
Reference in a new issue