1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
//! NIH-plug can handle floating point, integer, boolean, and enum parameters. Parameters are
//! 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::{Debug, 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;
pub mod enums;
mod float;
mod integer;

pub mod internals;
pub mod persist;
pub mod range;
pub mod smoothing;

pub use boolean::BoolParam;
pub use enums::EnumParam;
pub use float::FloatParam;
pub use integer::IntParam;

bitflags::bitflags! {
    /// Flags for controlling a parameter's behavior.
    #[repr(transparent)]
    #[derive(Default)]
    pub struct ParamFlags: u32 {
        /// When applied to a [`BoolParam`], this will cause the parameter to be linked to the
        /// host's bypass control. Only a single parameter can be marked as a bypass parameter. If
        /// you don't have a bypass parameter, then NIH-plug will add one for you. You will need to
        /// implement this yourself if your plugin introduces latency.
        const BYPASS = 1 << 0;
        /// The parameter cannot be changed from an automation lane. The parameter can however still
        /// be manually changed by the user from either the plugin's own GUI or from the host's
        /// generic UI.
        const NON_AUTOMATABLE = 1 << 1;
        /// Hides the parameter in the host's generic UI for this plugin. This also implies
        /// `NON_AUTOMATABLE`. Setting this does not prevent you from changing the parameter in the
        /// plugin's editor GUI.
        const HIDDEN = 1 << 2;
        /// Don't show this parameter when generating a generic UI for the plugin using one of
        /// NIH-plug's generic UI widgets.
        const HIDE_IN_GENERIC_UI = 1 << 3;
    }
}

// See https://rust-lang.github.io/api-guidelines/future-proofing.html for more information
mod sealed {
    /// Dummy trait to prevent [`Param`] from being implemented outside of NIH-plug. This is not
    /// possible because of the way `ParamPtr` works, so it's best to just make it flat out impossible.
    pub trait Sealed {}
}
pub(crate) use sealed::Sealed;

/// Describes a single parameter of any type. Most parameter implementations also have a field
/// called `value` that and a field called `smoothed`. The former stores the latest unsmoothed
/// value, and the latter can be used to access the smoother. These two fields should be used in DSP
/// code to either get the parameter's current (smoothed) value. In UI code the getters from this
/// trait should be used instead.
///
/// # Sealed
///
/// This trait cannot be implemented outside of NIH-plug itself. If you want to create new
/// abstractions around parameters, consider wrapping them in a struct instead. Then use the
/// `#[nested(id_prefix = "foo")]` syntax from the [`Params`] trait to reuse that wrapper in
/// multiple places.
pub trait Param: Display + Debug + sealed::Sealed {
    /// The plain parameter type.
    type Plain: PartialEq;

    /// Get the human readable name for this parameter.
    fn name(&self) -> &str;

    /// Get the unit label for this parameter, if any.
    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 communicated to the plugin through
    /// [`NoteEvent::PolyModulation`][crate::prelude::NoteEvent::PolyModulation] and
    /// [`NoteEvent::MonoAutomation`][crate::prelude::NoteEvent::MonoAutomation] events. See the
    /// documentation on those events for more information.
    ///
    /// # Important
    ///
    /// After enabling polyphonic modulation, the plugin **must** start sending
    /// [`NoteEvent::VoiceTerminated`][crate::prelude::NoteEvent::VoiceTerminated] 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.
    fn modulated_plain_value(&self) -> Self::Plain;

    /// Get the normalized `[0, 1]` value for this parameter.
    fn modulated_normalized_value(&self) -> f32;

    /// Get the unnormalized value for this parameter before any (monophonic) modulation coming from
    /// the host has been applied. If the host is not currently modulating this parameter than this
    /// will be the same as [`modulated_plain_value()`][Self::modulated_plain_value()]. This may be
    /// useful for displaying modulation differently in plugin GUIs. Right now only CLAP plugins in
    /// Bitwig Studio use modulation.
    fn unmodulated_plain_value(&self) -> Self::Plain;

    /// Get the normalized `[0, 1]` value for this parameter before any (monophonic) modulation
    /// coming from the host has been applied. If the host is not currently modulating this
    /// parameter than this will be the same as
    /// [`modulated_normalized_value()`][Self::modulated_normalized_value()]. This may be useful for
    /// displaying modulation differently in plugin GUIs. Right now only CLAP plugins in Bitwig
    /// Studio use modulation.
    fn unmodulated_normalized_value(&self) -> f32;

    /// Get the unnormalized default value for this parameter.
    fn default_plain_value(&self) -> Self::Plain;

    /// Get the normalized `[0, 1]` default value for this parameter.
    #[inline]
    fn default_normalized_value(&self) -> f32 {
        self.preview_normalized(self.default_plain_value())
    }

    /// Get the number of steps for this parameter, if it is discrete. Used for the host's generic
    /// UI.
    fn step_count(&self) -> Option<usize>;

    /// Returns the previous step from a specific value for this parameter. This can be the same as
    /// `from` if the value is at the start of its range. This is mainly used for scroll wheel
    /// interaction in plugin GUIs. When the parameter is not discrete then a step should cover one
    /// hundredth of the normalized range instead.
    ///
    /// If `finer` is true, then the step size should be decreased if the parameter is continuous.
    fn previous_step(&self, from: Self::Plain, finer: bool) -> Self::Plain;

    /// Returns the next step from a specific value for this parameter. This can be the same as
    /// `from` if the value is at the end of its range. This is mainly used for scroll wheel
    /// interaction in plugin GUIs. When the parameter is not discrete then a step should cover one
    /// hundredth of the normalized range instead.
    ///
    /// If `finer` is true, then the step size should be decreased if the parameter is continuous.
    fn next_step(&self, from: Self::Plain, finer: bool) -> Self::Plain;

    /// The same as [`previous_step()`][Self::previous_step()], but for normalized values. This is
    /// mostly useful for GUI widgets.
    fn previous_normalized_step(&self, from: f32, finer: bool) -> f32 {
        self.preview_normalized(self.previous_step(self.preview_plain(from), finer))
    }

    /// The same as [`next_step()`][Self::next_step()], but for normalized values. This is mostly
    /// useful for GUI widgets.
    fn next_normalized_step(&self, from: f32, finer: bool) -> f32 {
        self.preview_normalized(self.next_step(self.preview_plain(from), finer))
    }

    /// 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
    /// string or some DAWs may show duplicate units.
    fn normalized_value_to_string(&self, normalized: f32, include_unit: bool) -> String;

    /// Get the string representation for a normalized value. Used as part of the wrappers.
    fn string_to_normalized_value(&self, string: &str) -> Option<f32>;

    /// Get the normalized value for a plain, unnormalized value, as a float. Used as part of the
    /// wrappers.
    fn preview_normalized(&self, plain: Self::Plain) -> f32;

    /// Get the plain, unnormalized value for a normalized value, as a float. Used as part of the
    /// wrappers. This **does** snap to step sizes for continuous parameters (i.e. [`FloatParam`]).
    fn preview_plain(&self, normalized: f32) -> Self::Plain;

    /// Get the plain, unnormalized value for this parameter after polyphonic modulation has been
    /// applied. This is a convenience method for calling [`preview_plain()`][Self::preview_plain()]
    /// with `unmodulated_normalized_value() + normalized_offset`.`
    #[inline]
    fn preview_modulated(&self, normalized_offset: f32) -> Self::Plain {
        self.preview_plain(self.unmodulated_normalized_value() + normalized_offset)
    }

    /// Flags to control the parameter's behavior. See [`ParamFlags`].
    fn flags(&self) -> ParamFlags;

    /// Internal implementation detail for implementing [`Params`][Params]. This should
    /// not be used directly.
    fn as_ptr(&self) -> internals::ParamPtr;
}

/// 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`]). 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.
    ///
    /// 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.
    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
    /// 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.
    ///
    /// 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.
    fn set_normalized_value(&self, normalized: f32) -> bool;

    /// 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`]).
    ///
    /// 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.
    fn modulate_value(&self, modulation_offset: f32) -> bool;

    /// 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
    /// 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`] 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`][persist::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.
///
/// 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`. The same thing happens with persistent field keys to support multiple copies of
/// the field. _This makes it possible to reuse the same parameter struct with different names and
/// parameter indices._
///
/// ## `#[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}`. The same thing applies to persistent field keys.
///
/// # 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 [`persist::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
    /// [`persist::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
    /// [`persist::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)
    }
}