Update rustdoc formatting for links
Apparently it showed this text verbatim, and not in monospace.
This commit is contained in:
parent
ca461d3d15
commit
f581294d7b
|
@ -5,6 +5,7 @@ use quote::quote;
|
|||
use std::collections::HashSet;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Derive the `Params` trait for your plugin's parameters struct. See the `Plugin` trait.
|
||||
#[proc_macro_derive(Params, attributes(id, persist, nested))]
|
||||
pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||
let ast = syn::parse_macro_input!(input as syn::DeriveInput);
|
||||
|
@ -265,6 +266,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
|||
.into()
|
||||
}
|
||||
|
||||
/// Derive the `Enum` trait for your simple enum parameters. See `EnumParam` for more information.
|
||||
#[proc_macro_derive(Enum, attributes(name))]
|
||||
pub fn derive_enum(input: TokenStream) -> TokenStream {
|
||||
let ast = syn::parse_macro_input!(input as syn::DeriveInput);
|
||||
|
|
|
@ -17,16 +17,16 @@ pub use egui;
|
|||
|
||||
pub mod widgets;
|
||||
|
||||
/// Create an [Editor] instance using an [::egui] GUI. Using the user state parameter is optional,
|
||||
/// but it can be useful for keeping track of some temporary GUI-only settings. See the `gui_gain`
|
||||
/// example for more information on how to use this. The [EguiState] passed to this function
|
||||
/// contains the GUI's intitial size, and this is kept in sync whenever the GUI gets resized. You
|
||||
/// can also use this to know if the GUI is open, so you can avoid performing potentially expensive
|
||||
/// calculations while the GUI is not open. If you want this size to be persisted when restoring a
|
||||
/// plugin instance, then you can store it in a `#[persist = "key"]` field on your parameters
|
||||
/// struct.
|
||||
/// Create an [`Editor`] instance using an [`egui`][::egui] GUI. Using the user state parameter is
|
||||
/// optional, but it can be useful for keeping track of some temporary GUI-only settings. See the
|
||||
/// `gui_gain` example for more information on how to use this. The [`EguiState`] passed to this
|
||||
/// function contains the GUI's intitial size, and this is kept in sync whenever the GUI gets
|
||||
/// resized. You can also use this to know if the GUI is open, so you can avoid performing
|
||||
/// potentially expensive calculations while the GUI is not open. If you want this size to be
|
||||
/// persisted when restoring a plugin instance, then you can store it in a `#[persist = "key"]`
|
||||
/// field on your parameters struct.
|
||||
///
|
||||
/// See [EguiState::from_size()].
|
||||
/// See [`EguiState::from_size()`].
|
||||
//
|
||||
// TODO: DPI scaling, this needs to be implemented on the framework level
|
||||
pub fn create_egui_editor<T, U>(
|
||||
|
@ -53,7 +53,7 @@ pub struct EguiState {
|
|||
}
|
||||
|
||||
impl EguiState {
|
||||
/// Initialize the GUI's state. This is passed to [create_egui_editor()].
|
||||
/// Initialize the GUI's state. This is passed to [`create_egui_editor()`].
|
||||
pub fn from_size(width: u32, height: u32) -> Arc<EguiState> {
|
||||
Arc::new(EguiState {
|
||||
size: AtomicCell::new((width, height)),
|
||||
|
@ -73,7 +73,7 @@ impl EguiState {
|
|||
}
|
||||
}
|
||||
|
||||
/// An [Editor] implementation that calls an egui draw loop.
|
||||
/// An [`Editor`] implementation that calls an egui draw loop.
|
||||
struct EguiEditor<T> {
|
||||
egui_state: Arc<EguiState>,
|
||||
/// The plugin's state. This is kept in between editor openenings.
|
||||
|
@ -146,7 +146,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The window handle used for [EguiEditor].
|
||||
/// The window handle used for [`EguiEditor`].
|
||||
struct EguiEditorHandle {
|
||||
egui_state: Arc<EguiState>,
|
||||
window: WindowHandle,
|
||||
|
|
|
@ -13,7 +13,7 @@ lazy_static! {
|
|||
static ref DRAG_AMOUNT_MEMORY_ID: egui::Id = egui::Id::new((file!(), 1));
|
||||
}
|
||||
|
||||
/// A slider widget similar to [egui::widgets::Slider] that knows about NIH-plug parameters ranges
|
||||
/// A slider widget similar to [`egui::widgets::Slider`] that knows about NIH-plug parameters ranges
|
||||
/// and can get values for it.
|
||||
///
|
||||
/// TODO: Vertical orientation
|
||||
|
@ -31,7 +31,7 @@ pub struct ParamSlider<'a, P: Param> {
|
|||
|
||||
impl<'a, P: Param> ParamSlider<'a, P> {
|
||||
/// Create a new slider for a parameter. Use the other methods to modify the slider before
|
||||
/// passing it to [Ui::add()].
|
||||
/// passing it to [`Ui::add()`].
|
||||
pub fn for_param(param: &'a P, setter: &'a ParamSetter<'a>) -> Self {
|
||||
Self {
|
||||
param,
|
||||
|
|
|
@ -108,7 +108,7 @@ pub fn chdir_workspace_root() -> Result<()> {
|
|||
/// Bundle a package using the provided `cargo build` arguments. Options from the `bundler.toml`
|
||||
/// file in the workspace's root are respected (see
|
||||
/// <https://github.com/robbert-vdh/nih-plug/blob/master/bundler.toml>). This requires the current
|
||||
/// working directory to have been set to the workspace's root using [chdir_workspace_root].
|
||||
/// working directory to have been set to the workspace's root using [`chdir_workspace_root()`].
|
||||
pub fn bundle(package: &str, args: &[String]) -> Result<()> {
|
||||
let bundle_name = match load_bundler_config()?.and_then(|c| c.get(package).cloned()) {
|
||||
Some(PackageConfig { name: Some(name) }) => name,
|
||||
|
@ -295,7 +295,7 @@ fn compilation_target(cross_compile_target: Option<&str>) -> Result<CompilationT
|
|||
}
|
||||
}
|
||||
|
||||
/// The base directory for the compiled binaries. This does not use [CompilationTarget] as we need
|
||||
/// The base directory for the compiled binaries. This does not use [`CompilationTarget`] as we need
|
||||
/// to be able to differentiate between native and cross-compilation.
|
||||
fn target_base(cross_compile_target: Option<&str>) -> Result<&'static str> {
|
||||
match cross_compile_target {
|
||||
|
|
|
@ -32,8 +32,8 @@ pub struct Biquad<T> {
|
|||
s2: T,
|
||||
}
|
||||
|
||||
/// The coefficients `[b0, b1, b2, a1, a2]` for [Biquad]. These coefficients are all prenormalized,
|
||||
/// i.e. they have been divided by `a0`.
|
||||
/// The coefficients `[b0, b1, b2, a1, a2]` for [`Biquad`]. These coefficients are all
|
||||
/// prenormalized, i.e. they have been divided by `a0`.
|
||||
///
|
||||
/// The type parameter T should be either an `f32` or a SIMD type.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
|
|
@ -57,7 +57,7 @@ struct Diopser {
|
|||
sample_rate: f32,
|
||||
|
||||
/// All of the all-pass filters, with vectorized coefficients so they can be calculated for
|
||||
/// multiple channels at once. [DiopserParams::num_stages] controls how many filters are
|
||||
/// multiple channels at once. [`DiopserParams::num_stages`] controls how many filters are
|
||||
/// actually active.
|
||||
#[cfg(feature = "simd")]
|
||||
filters: [filter::Biquad<f32x2>; MAX_NUM_FILTERS],
|
||||
|
@ -315,8 +315,9 @@ impl Plugin for Diopser {
|
|||
}
|
||||
|
||||
impl Diopser {
|
||||
/// Check if the filters need to be updated beased on [Self::should_update_filters] and the
|
||||
/// smoothing interval, and update them as needed.
|
||||
/// Check if the filters need to be updated beased on
|
||||
/// [`should_update_filters`][Self::should_update_filters] and the smoothing interval, and
|
||||
/// update them as needed.
|
||||
fn maybe_update_filters(&mut self, smoothing_interval: u32) {
|
||||
// In addition to updating the filters, we should also clear the filter's state when
|
||||
// changing a setting we can't neatly interpolate between.
|
||||
|
|
|
@ -18,7 +18,7 @@ struct Gain {
|
|||
|
||||
/// Needed to normalize the peak meter's response based on the sample rate.
|
||||
peak_meter_decay_weight: f32,
|
||||
/// The current data for the peak meter. This is stored as an [Arc] so we can share it between
|
||||
/// The current data for the peak meter. This is stored as an [`Arc`] so we can share it between
|
||||
/// the GUI and the audio processing parts. If you have more state to share, then it's a good
|
||||
/// idea to put all of that in a struct behind a single `Arc`.
|
||||
///
|
||||
|
|
|
@ -33,9 +33,9 @@ pub struct SamplesIter<'slice, 'sample: 'slice> {
|
|||
}
|
||||
|
||||
/// Can construct iterators over actual iterator over the channel data for a sample, yielded by
|
||||
/// [Samples]. Can be turned into an iterator, or [Channels::iter_mut()] can be used to iterate over
|
||||
/// the channel data multiple times, or more efficiently you can use [Channels::get_unchecked_mut()]
|
||||
/// to do the same thing.
|
||||
/// [`Samples`]. Can be turned into an iterator, or [`Channels::iter_mut()`] can be used to iterate
|
||||
/// over the channel data multiple times, or more efficiently you can use
|
||||
/// [`Channels::get_unchecked_mut()`] to do the same thing.
|
||||
pub struct Channels<'slice, 'sample: 'slice> {
|
||||
/// The raw output buffers.
|
||||
pub(self) buffers: *mut [&'sample mut [f32]],
|
||||
|
@ -43,7 +43,7 @@ pub struct Channels<'slice, 'sample: 'slice> {
|
|||
pub(self) _marker: PhantomData<&'slice mut [&'sample mut [f32]]>,
|
||||
}
|
||||
|
||||
/// The actual iterator over the channel data for a sample, yielded by [Channels].
|
||||
/// The actual iterator over the channel data for a sample, yielded by [`Channels`].
|
||||
pub struct ChannelsIter<'slice, 'sample: 'slice> {
|
||||
/// The raw output buffers.
|
||||
pub(self) buffers: *mut [&'sample mut [f32]],
|
||||
|
@ -55,8 +55,8 @@ pub struct ChannelsIter<'slice, 'sample: 'slice> {
|
|||
// Per-block per-channel per-sample iterators
|
||||
|
||||
/// An iterator over all samples in the buffer, slicing over the sample-dimension with a maximum
|
||||
/// size of [Self::max_block_size]. See [Buffer::iter_blocks()]. Yields both the block and the
|
||||
/// offset from the start of the buffer.
|
||||
/// size of `max_block_size`. See [`Buffer::iter_blocks()`]. Yields both the block and the offset
|
||||
/// from the start of the buffer.
|
||||
pub struct BlocksIter<'slice, 'sample: 'slice> {
|
||||
/// The raw output buffers.
|
||||
pub(self) buffers: *mut [&'sample mut [f32]],
|
||||
|
@ -65,8 +65,8 @@ pub struct BlocksIter<'slice, 'sample: 'slice> {
|
|||
pub(self) _marker: PhantomData<&'slice mut [&'sample mut [f32]]>,
|
||||
}
|
||||
|
||||
/// A block yielded by [BlocksIter]. Can be iterated over once or multiple times, and also supports
|
||||
/// direct access to the block's samples if needed.
|
||||
/// A block yielded by [`BlocksIter`]. Can be iterated over once or multiple times, and also
|
||||
/// supports direct access to the block's samples if needed.
|
||||
pub struct Block<'slice, 'sample: 'slice> {
|
||||
/// The raw output buffers.
|
||||
pub(self) buffers: *mut [&'sample mut [f32]],
|
||||
|
@ -75,8 +75,8 @@ pub struct Block<'slice, 'sample: 'slice> {
|
|||
pub(self) _marker: PhantomData<&'slice mut [&'sample mut [f32]]>,
|
||||
}
|
||||
|
||||
/// An iterator over all channels in a block yielded by [Block]. Analogous to [ChannelsIter] but for
|
||||
/// blocks.
|
||||
/// An iterator over all channels in a block yielded by [`Block`]. Analogous to [`ChannelsIter`] but
|
||||
/// for blocks.
|
||||
pub struct BlockChannelsIter<'slice, 'sample: 'slice> {
|
||||
/// The raw output buffers.
|
||||
pub(self) buffers: *mut [&'sample mut [f32]],
|
||||
|
@ -262,11 +262,12 @@ impl<'a> Buffer<'a> {
|
|||
/// SIMD.
|
||||
///
|
||||
/// The parameter smoothers can also produce smoothed values for an entire block using
|
||||
/// [crate::Smoother::next_block()]. Before using this, you will need to call
|
||||
/// [crate::Plugin::initialize_block_smoothers()] with the same `max_block_size` in your
|
||||
/// initialization function first.
|
||||
/// [`Smoother::next_block()`][crate::Smoother::next_block()]. Before using this, you will need
|
||||
/// to call
|
||||
/// [`Plugin::initialize_block_smoothers()`][crate::Plugin::initialize_block_smoothers()] with
|
||||
/// the same `max_block_size` in your initialization function first.
|
||||
///
|
||||
/// You can use this to obtain block-slices from a buffer so you can pass them to a libraryq:
|
||||
/// You can use this to obtain block-slices from a buffer so you can pass them to a library:
|
||||
///
|
||||
/// ```ignore
|
||||
/// for block in buffer.iter_blocks(128) {
|
||||
|
@ -309,7 +310,7 @@ impl<'slice, 'sample> Channels<'slice, 'sample> {
|
|||
}
|
||||
|
||||
/// A resetting iterator. This lets you iterate over the same channels multiple times. Otherwise
|
||||
/// you don't need to use this function as [Channels] already implements [Iterator].
|
||||
/// you don't need to use this function as [`Channels`] already implements [Iterator].
|
||||
pub fn iter_mut(&mut self) -> ChannelsIter<'slice, 'sample> {
|
||||
ChannelsIter {
|
||||
buffers: self.buffers,
|
||||
|
@ -333,7 +334,7 @@ impl<'slice, 'sample> Channels<'slice, 'sample> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The same as [Self::get_mut], but without any bounds checking.
|
||||
/// The same as [`get_mut()`][Self::get_mut()], but without any bounds checking.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -390,7 +391,7 @@ impl<'slice, 'sample> Channels<'slice, 'sample> {
|
|||
}
|
||||
|
||||
/// Write data from a SIMD vector to this sample's channel data. This takes the padding added by
|
||||
/// [Self::to_simd()] into account.
|
||||
/// [`to_simd()`][Self::to_simd()] into account.
|
||||
#[cfg(feature = "simd")]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
#[inline]
|
||||
|
@ -438,8 +439,8 @@ impl<'slice, 'sample> Block<'slice, 'sample> {
|
|||
}
|
||||
|
||||
/// A resetting iterator. This lets you iterate over the same block multiple times. Otherwise
|
||||
/// you don't need to use this function as [Block] already implements [Iterator]. You can also
|
||||
/// use the direct accessor functions on this block instead.
|
||||
/// you don't need to use this function as [`Block`] already implements [`Iterator`]. You can
|
||||
/// also use the direct accessor functions on this block instead.
|
||||
pub fn iter_mut(&mut self) -> BlockChannelsIter<'slice, 'sample> {
|
||||
BlockChannelsIter {
|
||||
buffers: self.buffers,
|
||||
|
@ -450,7 +451,7 @@ impl<'slice, 'sample> Block<'slice, 'sample> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Access a channel by index. Useful when you would otherwise iterate over this [Block]
|
||||
/// Access a channel by index. Useful when you would otherwise iterate over this [`Block`]
|
||||
/// multiple times.
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self, channel_index: usize) -> Option<&mut [f32]> {
|
||||
|
@ -464,7 +465,7 @@ impl<'slice, 'sample> Block<'slice, 'sample> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The same as [Self::get_mut], but without any bounds checking.
|
||||
/// The same as [`get_mut()`][Self::get_mut], but without any bounds checking.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -533,7 +534,7 @@ impl<'slice, 'sample> Block<'slice, 'sample> {
|
|||
}
|
||||
|
||||
/// Write data from a SIMD vector to this sample's channel data for a specific sample in this
|
||||
/// block. This takes the padding added by [Self::to_simd()] into account.
|
||||
/// block. This takes the padding added by [`to_simd()`][Self::to_simd()] into account.
|
||||
///
|
||||
/// Returns `false` if `sample_index` is out of bounds.
|
||||
#[cfg(feature = "simd")]
|
||||
|
|
|
@ -7,7 +7,8 @@ use crate::plugin::NoteEvent;
|
|||
// TODO: ProcessContext for parameter automation and sending events
|
||||
|
||||
/// General callbacks the plugin can make during its lifetime. This is passed to the plugin during
|
||||
/// [crate::plugin::Plugin::initialize()] and as part of [crate::plugin::Plugin::process()].
|
||||
/// [`Plugin::initialize()`][crate::plugin::Plugin::initialize()] and as part of
|
||||
/// [`Plugin::process()`][crate::plugin::Plugin::process()].
|
||||
//
|
||||
// # Safety
|
||||
//
|
||||
|
@ -32,16 +33,16 @@ pub trait ProcessContext {
|
|||
}
|
||||
|
||||
/// Callbacks the plugin can make when the user interacts with its GUI such as updating parameter
|
||||
/// values. This is passed to the plugin during [crate::Editor::spawn()]. All of these functions
|
||||
/// assume they're being called from the main GUI thread.
|
||||
/// values. This is passed to the plugin during [`Editor::spawn()`][crate::Editor::spawn()]. All of
|
||||
/// these functions assume they're being called from the main GUI thread.
|
||||
//
|
||||
// # Safety
|
||||
//
|
||||
// The implementing wrapper can assume that everything is being called from the main thread. Since
|
||||
// NIH-plug doesn't own the GUI event loop, this invariant cannot be part of the interface.
|
||||
pub trait GuiContext: Send + Sync + 'static {
|
||||
/// Inform the host a parameter will be automated. Create a [ParamSetter] and use
|
||||
/// [ParamSetter::begin_set_parameter] instead for a safe, user friendly API.
|
||||
/// Inform the host a parameter will be automated. Create a [`ParamSetter`] and use
|
||||
/// [`ParamSetter::begin_set_parameter()`] instead for a safe, user friendly API.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -50,7 +51,8 @@ pub trait GuiContext: Send + Sync + 'static {
|
|||
unsafe fn raw_begin_set_parameter(&self, param: ParamPtr);
|
||||
|
||||
/// Inform the host a parameter is being automated with an already normalized value. Create a
|
||||
/// [ParamSetter] and use [ParamSetter::set_parameter] instead for a safe, user friendly API.
|
||||
/// [`ParamSetter`] and use [`ParamSetter::set_parameter()`] instead for a safe, user friendly
|
||||
/// API.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -58,8 +60,8 @@ pub trait GuiContext: Send + Sync + 'static {
|
|||
/// mostly marked as unsafe for API reasons.
|
||||
unsafe fn raw_set_parameter_normalized(&self, param: ParamPtr, normalized: f32);
|
||||
|
||||
/// Inform the host a parameter has been automated. Create a [ParamSetter] and use
|
||||
/// [ParamSetter::end_set_parameter] instead for a safe, user friendly API.
|
||||
/// Inform the host a parameter has been automated. Create a [`ParamSetter`] and use
|
||||
/// [`ParamSetter::end_set_parameter()`] instead for a safe, user friendly API.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -68,8 +70,8 @@ pub trait GuiContext: Send + Sync + 'static {
|
|||
unsafe fn raw_end_set_parameter(&self, param: ParamPtr);
|
||||
|
||||
/// Retrieve the default value for a parameter, in case you forgot. This does not perform a
|
||||
/// callback Create a [ParamSetter] and use [ParamSetter::default_param_value] instead for a
|
||||
/// safe, user friendly API.
|
||||
/// callback Create a [`ParamSetter`] and use [`ParamSetter::default_param_value()`] instead for
|
||||
/// a safe, user friendly API.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -91,16 +93,17 @@ impl<'a> ParamSetter<'a> {
|
|||
}
|
||||
|
||||
/// Inform the host that you will start automating a parmater. This needs to be called before
|
||||
/// calling [Self::set_parameter()] for the specified parameter.
|
||||
/// calling [`set_parameter()`][Self::set_parameter()] for the specified parameter.
|
||||
pub fn begin_set_parameter<P: Param>(&self, param: &P) {
|
||||
unsafe { self.context.raw_begin_set_parameter(param.as_ptr()) };
|
||||
}
|
||||
|
||||
/// Set a parameter to the specified parameter value. You will need to call
|
||||
/// [Self::begin_set_parameter()] before and [Self::end_set_parameter()] after calling this so
|
||||
/// the host can properly record automation for the parameter. This can be called multiple times
|
||||
/// in a row before calling [Self::end_set_parameter()], for instance when moving a slider
|
||||
/// around.
|
||||
/// [`begin_set_parameter()`][Self::begin_set_parameter()] before and
|
||||
/// [`end_set_parameter()`][Self::end_set_parameter()] after calling this so the host can
|
||||
/// properly record automation for the parameter. This can be called multiple times in a row
|
||||
/// before calling [`end_set_parameter()`][Self::end_set_parameter()], for instance when moving
|
||||
/// a slider around.
|
||||
///
|
||||
/// This function assumes you're already calling this from a GUI thread. Calling any of these
|
||||
/// functions from any other thread may result in unexpected behavior.
|
||||
|
@ -111,20 +114,20 @@ impl<'a> ParamSetter<'a> {
|
|||
}
|
||||
|
||||
/// Set a parameter to an already normalized value. Works exactly the same as
|
||||
/// [Self::set_parameter] and needs to follow the same rules, but this may be useful when
|
||||
/// implementing a GUI.
|
||||
/// [`set_parameter()`][Self::set_parameter()] and needs to follow the same rules, but this may
|
||||
/// be useful when implementing a GUI.
|
||||
///
|
||||
/// This does not perform any snapping. Consider converting the normalized value to a plain
|
||||
/// value and setting that with [Self::set_parameter()] instead so the normalized value known to
|
||||
/// the host matches `param.normalized_value()`.
|
||||
/// value and setting that with [`set_parameter()`][Self::set_parameter()] instead so the
|
||||
/// normalized value known to the host matches `param.normalized_value()`.
|
||||
pub fn set_parameter_normalized<P: Param>(&self, param: &P, normalized: f32) {
|
||||
let ptr = param.as_ptr();
|
||||
unsafe { self.context.raw_set_parameter_normalized(ptr, normalized) };
|
||||
}
|
||||
|
||||
/// Inform the host that you are done automating a parameter. This needs to be called after one
|
||||
/// or more [Self::set_parameter()] calls for a parameter so the host knows the automation
|
||||
/// gesture has finished.
|
||||
/// or more [`set_parameter()`][Self::set_parameter()] calls for a parameter so the host knows
|
||||
/// the automation gesture has finished.
|
||||
pub fn end_set_parameter<P: Param>(&self, param: &P) {
|
||||
unsafe { self.context.raw_end_set_parameter(param.as_ptr()) };
|
||||
}
|
||||
|
@ -138,7 +141,8 @@ impl<'a> ParamSetter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The same as [Self::default_normalized_param_value], but without the normalization.
|
||||
/// The same as [`default_normalized_param_value()`][Self::default_normalized_param_value()],
|
||||
/// but without the normalization.
|
||||
pub fn default_param_value<P: Param>(&self, param: &P) -> P::Plain {
|
||||
param.preview_plain(self.default_normalized_param_value(param))
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::thread::{self, JoinHandle, ThreadId};
|
|||
use super::{EventLoop, MainThreadExecutor};
|
||||
use crate::nih_log;
|
||||
|
||||
/// See [super::EventLoop].
|
||||
/// See [`EventLoop`][super::EventLoop].
|
||||
#[cfg_attr(
|
||||
target_os = "macos",
|
||||
deprecated = "macOS needs to have its own event loop implementation, this implementation may not work correctly"
|
||||
|
@ -24,12 +24,12 @@ pub(crate) struct LinuxEventLoop<T, E> {
|
|||
/// queue.
|
||||
main_thread_id: ThreadId,
|
||||
|
||||
/// A thread that act as our worker thread. When [Self::do_maybe_async()] is called, this thread will be
|
||||
/// woken up to execute the task on the executor. This is wrapped in an `Option` so the thread
|
||||
/// can be taken out of it and joined when this struct gets dropped.
|
||||
/// A thread that act as our worker thread. When [`do_maybe_async()`][Self::do_maybe_async()] is
|
||||
/// called, this thread will be woken up to execute the task on the executor. This is wrapped in
|
||||
/// an `Option` so the thread can be taken out of it and joined when this struct gets dropped.
|
||||
worker_thread: Option<JoinHandle<()>>,
|
||||
/// A channel for waking up the worker thread and having it perform one of the tasks from
|
||||
/// [Message].
|
||||
/// [`Message`].
|
||||
worker_thread_channel: channel::Sender<Message<T>>,
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,8 @@ impl<T, E> Drop for LinuxEventLoop<T, E> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The worker thread used in [EventLoop] that executes incmoing tasks on the event loop's executor.
|
||||
/// The worker thread used in [`EventLoop`] that executes incmoing tasks on the event loop's
|
||||
/// executor.
|
||||
fn worker_thread<T, E>(receiver: channel::Receiver<Message<T>>, executor: Weak<E>)
|
||||
where
|
||||
T: Send,
|
||||
|
|
|
@ -33,7 +33,7 @@ const NOTIFY_MESSAGE_ID: u32 = WM_USER;
|
|||
/// casted from a regular pointer.
|
||||
type PollCallback = Box<dyn Fn()>;
|
||||
|
||||
/// See [super::EventLoop].
|
||||
/// See [`EventLoop`][super::EventLoop].
|
||||
pub(crate) struct WindowsEventLoop<T, E> {
|
||||
/// The thing that ends up executing these tasks. The tasks are usually executed from the worker
|
||||
/// thread, but if the current thread is the main thread then the task cna also be executed
|
||||
|
|
15
src/param.rs
15
src/param.rs
|
@ -37,7 +37,7 @@ pub trait Param: Display {
|
|||
fn plain_value(&self) -> Self::Plain;
|
||||
|
||||
/// Set this parameter based on a plain, unnormalized value. This does **not** snap to step
|
||||
/// sizes for continuous parameters (i.e. [FloatParam]).
|
||||
/// sizes for continuous parameters (i.e. [`FloatParam`]).
|
||||
///
|
||||
/// This does **not** update the smoother.
|
||||
fn set_plain_value(&mut self, plain: Self::Plain);
|
||||
|
@ -46,7 +46,7 @@ pub trait Param: Display {
|
|||
fn normalized_value(&self) -> f32;
|
||||
|
||||
/// Set this parameter based on a normalized value. This **does** snap to step sizes for
|
||||
/// continuous parameters (i.e. [FloatParam]).
|
||||
/// continuous parameters (i.e. [`FloatParam`]).
|
||||
///
|
||||
/// This does **not** update the smoother.
|
||||
fn set_normalized_value(&mut self, normalized: f32);
|
||||
|
@ -64,7 +64,7 @@ pub trait Param: Display {
|
|||
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]).
|
||||
/// wrappers. This **does** snap to step sizes for continuous parameters (i.e. [`FloatParam`]).
|
||||
fn preview_plain(&self, normalized: f32) -> Self::Plain;
|
||||
|
||||
/// Set this parameter based on a string. Returns whether the updating succeeded. That can fail
|
||||
|
@ -78,11 +78,12 @@ pub trait Param: Display {
|
|||
/// reset to the current value.
|
||||
fn update_smoother(&mut self, sample_rate: f32, reset: bool);
|
||||
|
||||
/// Allocate memory for block-based smoothing. The [crate::Plugin::initialize_block_smoothers()]
|
||||
/// method will do this for every smoother.
|
||||
/// Allocate memory for block-based smoothing. The
|
||||
/// [`Plugin::initialize_block_smoothers()`][crate::Plugin::initialize_block_smoothers()] method
|
||||
/// will do this for every smoother.
|
||||
fn initialize_block_smoother(&mut self, max_block_size: usize);
|
||||
|
||||
/// Internal implementation detail for implementing [internals::Params]. This should not be used
|
||||
/// directly.
|
||||
/// Internal implementation detail for implementing [`Params`][internals::Params]. This should
|
||||
/// not be used directly.
|
||||
fn as_ptr(&self) -> internals::ParamPtr;
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ impl Param for BoolParam {
|
|||
}
|
||||
|
||||
impl BoolParam {
|
||||
/// Build a new [Self]. Use the other associated functions to modify the behavior of the
|
||||
/// Build a new [`BoolParam`]. Use the other associated functions to modify the behavior of the
|
||||
/// parameter.
|
||||
pub fn new(name: &'static str, default: bool) -> Self {
|
||||
Self {
|
||||
|
|
|
@ -33,15 +33,17 @@ pub trait Enum {
|
|||
fn variants() -> &'static [&'static str];
|
||||
|
||||
/// Get the variant index (which may not be the same as the discriminator) corresponding to the
|
||||
/// active variant. The index needs to correspond to the name in [Self::variants()].
|
||||
/// active variant. The index needs to correspond to the name in
|
||||
/// [`variants()`][Self::variants()].
|
||||
fn to_index(self) -> usize;
|
||||
|
||||
/// Get the variant corresponding to the variant with the same index in [Self::variants()]. This
|
||||
/// must always return a value. If the index is out of range, return the first variatn.
|
||||
/// Get the variant corresponding to the variant with the same index in
|
||||
/// [`variants()`][Self::variants()]. This must always return a value. If the index is out of
|
||||
/// range, return the first variatn.
|
||||
fn from_index(index: usize) -> Self;
|
||||
}
|
||||
|
||||
/// An [IntParam]-backed categorical parameter that allows convenient conversion to and from a
|
||||
/// An [`IntParam`]-backed categorical parameter that allows convenient conversion to and from a
|
||||
/// simple enum. This enum must derive the re-exported [Enum] trait. Check the trait's documentation
|
||||
/// for more information on how this works.
|
||||
pub struct EnumParam<T: Enum> {
|
||||
|
@ -50,12 +52,12 @@ pub struct EnumParam<T: Enum> {
|
|||
inner: EnumParamInner,
|
||||
|
||||
/// `T` is only used on the plugin side to convert back to an enum variant. Internally
|
||||
/// everything works through the variants field on [EnumParamInner].
|
||||
/// everything works through the variants field on [`EnumParamInner`].
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
/// The type-erased internals for [EnumParam] so that the wrapper can interact with it. Acts like an
|
||||
/// [IntParam] but with different conversions from strings to values.
|
||||
/// The type-erased internals for [`EnumParam`] so that the wrapper can interact with it. Acts like
|
||||
/// an [`IntParam`] but with different conversions from strings to values.
|
||||
pub struct EnumParamInner {
|
||||
/// The integer parameter backing this enum parameter.
|
||||
pub(crate) inner: IntParam,
|
||||
|
|
|
@ -12,7 +12,7 @@ use super::Param;
|
|||
/// process.
|
||||
///
|
||||
/// You can either initialize the struct directly, using `..Default::default()` to fill in the
|
||||
/// unused fields, or you can use the builder interface with [Self::new()].
|
||||
/// unused fields, or you can use the builder interface with [`FloatParam::new()`].
|
||||
//
|
||||
// XXX: To keep the API simple and to allow the optimizer to do its thing, the values are stored as
|
||||
// plain primitive values that are modified through the `*mut` pointers from the plugin's
|
||||
|
@ -44,13 +44,13 @@ pub struct FloatParam {
|
|||
/// The distribution of the parameter's values.
|
||||
pub range: FloatRange,
|
||||
/// The distance between discrete steps in this parameter. Mostly useful for quantizing GUI
|
||||
/// input. If this is set and if [Self::value_to_string] is not set, then this is also used when
|
||||
/// formatting the parameter. This must be a positive, nonzero number.
|
||||
/// input. If this is set and if [`value_to_string`][Self::value_to_string] is not set, then
|
||||
/// this is also used when formatting the parameter. This must be a positive, nonzero number.
|
||||
pub step_size: Option<f32>,
|
||||
/// The parameter's human readable display name.
|
||||
pub name: &'static str,
|
||||
/// 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.
|
||||
/// 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.
|
||||
pub unit: &'static str,
|
||||
/// Optional custom conversion function from a plain **unnormalized** value to a string.
|
||||
pub value_to_string: Option<Arc<dyn Fn(f32) -> String + Send + Sync>>,
|
||||
|
@ -197,7 +197,7 @@ impl Param for FloatParam {
|
|||
}
|
||||
|
||||
impl FloatParam {
|
||||
/// Build a new [Self]. Use the other associated functions to modify the behavior of the
|
||||
/// Build a new [`FloatParam`]. Use the other associated functions to modify the behavior of the
|
||||
/// parameter.
|
||||
pub fn new(name: &'static str, default: f32, range: FloatRange) -> Self {
|
||||
Self {
|
||||
|
@ -225,7 +225,7 @@ impl FloatParam {
|
|||
}
|
||||
|
||||
/// Display a unit when rendering this parameter to a string. Appended after the
|
||||
/// [Self::value_to_string] function if that is also set. NIH-plug will not
|
||||
/// [`value_to_string`][Self::value_to_string] function if that is also set. NIH-plug will not
|
||||
/// automatically add a space before the unit.
|
||||
pub fn with_unit(mut self, unit: &'static str) -> Self {
|
||||
self.unit = unit;
|
||||
|
@ -233,8 +233,8 @@ impl FloatParam {
|
|||
}
|
||||
|
||||
/// Set the distance between steps of a [FloatParam]. Mostly useful for quantizing GUI input. If
|
||||
/// this is set and if [Self::value_to_string] is not set, then this is also used when
|
||||
/// formatting the parameter. This must be a positive, nonzero number.
|
||||
/// this is set and if [`value_to_string`][Self::value_to_string] is not set, then this is also
|
||||
/// used when formatting the parameter. This must be a positive, nonzero number.
|
||||
pub fn with_step_size(mut self, step_size: f32) -> Self {
|
||||
self.step_size = Some(step_size);
|
||||
self
|
||||
|
|
|
@ -12,7 +12,7 @@ use super::Param;
|
|||
/// process.
|
||||
///
|
||||
/// You can either initialize the struct directly, using `..Default::default()` to fill in the
|
||||
/// unused fields, or you can use the builder interface with [Self::new()].
|
||||
/// unused fields, or you can use the builder interface with [`IntParam::new()`].
|
||||
//
|
||||
// XXX: To keep the API simple and to allow the optimizer to do its thing, the values are stored as
|
||||
// plain primitive values that are modified through the `*mut` pointers from the plugin's
|
||||
|
@ -176,7 +176,7 @@ impl Param for IntParam {
|
|||
}
|
||||
|
||||
impl IntParam {
|
||||
/// Build a new [Self]. Use the other associated functions to modify the behavior of the
|
||||
/// Build a new [`IntParam`]. Use the other associated functions to modify the behavior of the
|
||||
/// parameter.
|
||||
pub fn new(name: &'static str, default: i32, range: IntRange) -> Self {
|
||||
Self {
|
||||
|
@ -204,7 +204,7 @@ impl IntParam {
|
|||
}
|
||||
|
||||
/// Display a unit when rendering this parameter to a string. Appended after the
|
||||
/// [Self::value_to_string] function if that is also set. NIH-plug will not
|
||||
/// [`value_to_string`][Self::value_to_string] function if that is also set. NIH-plug will not
|
||||
/// automatically add a space before the unit.
|
||||
pub fn with_unit(mut self, unit: &'static str) -> Self {
|
||||
self.unit = unit;
|
||||
|
|
|
@ -5,21 +5,21 @@ use std::pin::Pin;
|
|||
|
||||
use super::Param;
|
||||
|
||||
/// Re-export for use in the [Params] proc-macro.
|
||||
/// 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.
|
||||
/// Re-export for use in the [`Params`] proc-macro.
|
||||
pub use serde_json::to_string as serialize_field;
|
||||
|
||||
/// Describes a struct containing parameters and other persistent fields. The idea is that we can
|
||||
/// have a normal struct containing [super::FloatParam] and other parameter types with attributes
|
||||
/// assigning a unique identifier to each parameter. We can then build a mapping from those
|
||||
/// parameter IDs to the parameters using the [Params::param_map()] function. That way we can have
|
||||
/// easy to work with JUCE-style parameter objects in the plugin without needing to manually
|
||||
/// register each parameter, like you would in JUCE. When deriving this trait, any of those
|
||||
/// have a normal struct containing [`FloatParam`][super::FloatParam] and other parameter types with
|
||||
/// attributes assigning a unique identifier to each parameter. We can then build a mapping from
|
||||
/// those parameter IDs to the parameters using the [`Params::param_map()`] function. That way we
|
||||
/// can have easy to work with JUCE-style parameter objects in the plugin without needing to
|
||||
/// manually register each parameter, like you would in JUCE. When deriving this trait, any of those
|
||||
/// parameters should have the `#[id = "stable"]` attribute, where `stable` is an up to 6 character
|
||||
/// (to avoid collisions) string that will be used for the parameter's internal identifier.
|
||||
///
|
||||
/// The other persistent parameters should be [PersistentField]s containing types that can be
|
||||
/// The other persistent parameters should be [`PersistentField`]s containing types that can be
|
||||
/// serialized and deserialized with Serde. When deriving this trait, any of those fields should be
|
||||
/// marked with `#[persist = "key"]`.
|
||||
///
|
||||
|
@ -54,13 +54,14 @@ pub trait Params {
|
|||
|
||||
/// 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.
|
||||
/// recalled later. This uses [`serialize_field()`] under the hood.
|
||||
fn serialize_fields(&self) -> HashMap<String, String>;
|
||||
|
||||
/// Restore all fields marked with `#[persist = "stable_name"]` from a hashmap created by
|
||||
/// [Self::serialize_fields()]. All of thse 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.
|
||||
/// [`serialize_fields()`][Self::serialize_fields()]. All of thse 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.
|
||||
fn deserialize_fields(&self, serialized: &HashMap<String, String>);
|
||||
}
|
||||
|
||||
|
@ -96,17 +97,17 @@ where
|
|||
F: Fn(&T) -> R;
|
||||
}
|
||||
|
||||
/// Generate a [ParamPtr] function that forwards the function call to the underlying `Param`. We
|
||||
/// Generate a [`ParamPtr`] function that forwards the function call to the underlying `Param`. We
|
||||
/// can't have an `.as_param()` function since the return type would differ depending on the
|
||||
/// underlying parameter type, so instead we need to type erase all of the functions individually.
|
||||
macro_rules! param_ptr_forward(
|
||||
(pub unsafe fn $method:ident(&self $(, $arg_name:ident: $arg_ty:ty)*) $(-> $ret:ty)?) => {
|
||||
/// Calls the corresponding method on the underlying [Param] object.
|
||||
/// Calls the corresponding method on the underlying [`Param`] object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Calling this function is only safe as long as the object this [ParamPtr] was created for
|
||||
/// is still alive.
|
||||
/// Calling this function is only safe as long as the object this [`ParamPtr`] was created
|
||||
/// for is still alive.
|
||||
pub unsafe fn $method(&self $(, $arg_name: $arg_ty)*) $(-> $ret)? {
|
||||
match &self {
|
||||
ParamPtr::FloatParam(p) => (**p).$method($($arg_name),*),
|
||||
|
@ -119,12 +120,12 @@ macro_rules! param_ptr_forward(
|
|||
// XXX: Is there a way to combine these two? Hygienic macros don't let you call `&self` without
|
||||
// it being defined in the macro.
|
||||
(pub unsafe fn $method:ident(&mut self $(, $arg_name:ident: $arg_ty:ty)*) $(-> $ret:ty)?) => {
|
||||
/// Calls the corresponding method on the underlying [Param] object.
|
||||
/// Calls the corresponding method on the underlying [`Param`] object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Calling this function is only safe as long as the object this [ParamPtr] was created for
|
||||
/// is still alive.
|
||||
/// Calling this function is only safe as long as the object this [`ParamPtr`] was created
|
||||
/// for is still alive.
|
||||
pub unsafe fn $method(&mut self $(, $arg_name: $arg_ty)*) $(-> $ret)? {
|
||||
match &self {
|
||||
ParamPtr::FloatParam(p) => (**p).$method($($arg_name),*),
|
||||
|
|
|
@ -7,13 +7,13 @@ pub enum FloatRange {
|
|||
Linear { min: f32, max: f32 },
|
||||
/// The range is skewed by a factor. Values above 1.0 will make the end of the range wider,
|
||||
/// while values between 0 and 1 will skew the range towards the start. Use
|
||||
/// [FloatRange::skew_factor()] for a more intuitively way to calculate the skew factor where
|
||||
/// [`FloatRange::skew_factor()`] for a more intuitively way to calculate the skew factor where
|
||||
/// positive values skew the range towards the end while negative values skew the range toward
|
||||
/// the start.
|
||||
Skewed { min: f32, max: f32, factor: f32 },
|
||||
/// The same as [FloatRange::Skewed], but with the skewing happening from a central point. This
|
||||
/// central point is rescaled to be at 50% of the parameter's range for convenience of use. Git
|
||||
/// blame this comment to find a version that doesn't do this.
|
||||
/// The same as [`FloatRange::Skewed`], but with the skewing happening from a central point.
|
||||
/// This central point is rescaled to be at 50% of the parameter's range for convenience of use.
|
||||
/// Git blame this comment to find a version that doesn't do this.
|
||||
SymmetricalSkewed {
|
||||
min: f32,
|
||||
max: f32,
|
||||
|
@ -44,7 +44,7 @@ impl Default for IntRange {
|
|||
}
|
||||
|
||||
impl FloatRange {
|
||||
/// Calculate a skew factor for [FloatRange::Skewed] and [FloatRange::SymmetricalSkewed].
|
||||
/// Calculate a skew factor for [`FloatRange::Skewed`] and [`FloatRange::SymmetricalSkewed`].
|
||||
/// Positive values make the end of the range wider while negative make the start of the range
|
||||
/// wider.
|
||||
pub fn skew_factor(factor: f32) -> f32 {
|
||||
|
|
|
@ -42,7 +42,8 @@ pub struct Smoother<T> {
|
|||
target: T,
|
||||
|
||||
/// A dense buffer containing smoothed values for an entire block of audio. Useful when using
|
||||
/// [crate::Buffer::iter_blocks()] to process small blocks of audio multiple times.
|
||||
/// [`Buffer::iter_blocks()`][crate::Buffer::iter_blocks()] to process small blocks of audio
|
||||
/// multiple times.
|
||||
block_values: AtomicRefCell<Vec<T>>,
|
||||
}
|
||||
|
||||
|
@ -74,15 +75,15 @@ impl<T: Default> Smoother<T> {
|
|||
Default::default()
|
||||
}
|
||||
|
||||
/// Whether calling [Self::next()] will yield a new value or an old value. Useful if you need to
|
||||
/// recompute something wheenver this parameter changes.
|
||||
/// Whether calling [`next()`][Self::next()] will yield a new value or an old value. Useful if
|
||||
/// you need to recompute something wheenver this parameter changes.
|
||||
pub fn is_smoothing(&self) -> bool {
|
||||
self.steps_left.load(Ordering::Relaxed) > 0
|
||||
}
|
||||
|
||||
/// Allocate memory to store smoothed values for an entire block of audio. Call this in
|
||||
/// [crate::Plugin::initialize()] with the same max block size you are going to pass to
|
||||
/// [crate::Buffer::iter_blocks()].
|
||||
/// [`Plugin::initialize()`][crate::Plugin::initialize()] with the same max block size you are
|
||||
/// going to pass to [`Buffer::iter_blocks()`][crate::Buffer::iter_blocks()].
|
||||
pub fn initialize_block_smoother(&mut self, max_block_size: usize) {
|
||||
self.block_values
|
||||
.borrow_mut()
|
||||
|
@ -135,10 +136,11 @@ impl Smoother<f32> {
|
|||
}
|
||||
|
||||
/// Produce smoothed values for an entire block of audio. Used in conjunction with
|
||||
/// [crate::Buffer::iter_blocks()]. Make sure to call
|
||||
/// [crate::Plugin::initialize_block_smoothers()] with the same maximum buffer block size as the
|
||||
/// one passed to `iter_blocks()` in your [crate::Plugin::initialize()] function first to
|
||||
/// allocate memory for the block smoothing.
|
||||
/// [`Buffer::iter_blocks()`][crate::Buffer::iter_blocks()]. Make sure to call
|
||||
/// [`Plugin::initialize_block_smoothers()`][crate::Plugin::initialize_block_smoothers()] with
|
||||
/// the same maximum buffer block size as the one passed to `iter_blocks()` in your
|
||||
/// [`Plugin::initialize()`][crate::Plugin::initialize()] function first to allocate memory for
|
||||
/// the block smoothing.
|
||||
///
|
||||
/// Returns a `None` value if the block length exceed's the allocated capacity.
|
||||
///
|
||||
|
@ -163,10 +165,10 @@ impl Smoother<f32> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// [Self::next()], but with the ability to skip forward in the smoother. [Self::next()] is
|
||||
/// equivalent to calling this function with a `steps` value of 1. Calling this function with a
|
||||
/// `steps` value of `n` means will cause you to skip the next `n - 1` values and return the
|
||||
/// `n`th value.
|
||||
/// [`next()`][Self::next()], but with the ability to skip forward in the smoother.
|
||||
/// [`next()`][Self::next()] is equivalent to calling this function with a `steps` value of 1.
|
||||
/// Calling this function with a `steps` value of `n` means will cause you to skip the next `n -
|
||||
/// 1` values and return the `n`th value.
|
||||
#[inline]
|
||||
pub fn next_step(&self, steps: u32) -> f32 {
|
||||
nih_debug_assert_ne!(steps, 0);
|
||||
|
@ -236,10 +238,11 @@ impl Smoother<i32> {
|
|||
}
|
||||
|
||||
/// Produce smoothed values for an entire block of audio. Used in conjunction with
|
||||
/// [crate::Buffer::iter_blocks()]. Make sure to call
|
||||
/// [crate::Plugin::initialize_block_smoothers()] with the same maximum buffer block size as the
|
||||
/// one passed to `iter_blocks()` in your [crate::Plugin::initialize()] function first to
|
||||
/// allocate memory for the block smoothing.
|
||||
/// [`Buffer::iter_blocks()`][crate::Buffer::iter_blocks()]. Make sure to call
|
||||
/// [`Plugin::initialize_block_smoothers()`][crate::Plugin::initialize_block_smoothers()] with
|
||||
/// the same maximum buffer block size as the one passed to `iter_blocks()` in your
|
||||
/// [`Plugin::initialize()`][crate::Plugin::initialize()] function first to allocate memory for
|
||||
/// the block smoothing.
|
||||
///
|
||||
/// Returns a `None` value if the block length exceed's the allocated capacity.
|
||||
///
|
||||
|
@ -260,10 +263,10 @@ impl Smoother<i32> {
|
|||
}))
|
||||
}
|
||||
|
||||
/// [Self::next()], but with the ability to skip forward in the smoother. [Self::next()] is
|
||||
/// equivalent to calling this function with a `steps` value of 1. Calling this function with a
|
||||
/// `steps` value of `n` means will cause you to skip the next `n - 1` values and return the
|
||||
/// `n`th value.
|
||||
/// [`next()`][Self::next()], but with the ability to skip forward in the smoother.
|
||||
/// [`next()`][Self::next()] is equivalent to calling this function with a `steps` value of 1.
|
||||
/// Calling this function with a `steps` value of `n` means will cause you to skip the next `n -
|
||||
/// 1` values and return the `n`th value.
|
||||
pub fn next_step(&self, steps: u32) -> i32 {
|
||||
nih_debug_assert_ne!(steps, 0);
|
||||
|
||||
|
|
|
@ -54,10 +54,11 @@ pub trait Plugin: Default + Send + Sync + 'static {
|
|||
fn params(&self) -> Pin<&dyn Params>;
|
||||
|
||||
/// The plugin's editor, if it has one. The actual editor instance is created in
|
||||
/// [Editor::spawn]. A plugin editor likely wants to interact with the plugin's parameters and
|
||||
/// other shared data, so you'll need to move [Arc] pointing to any data you want to access into
|
||||
/// the editor. You can later modify the parameters through the [crate::GuiContext] and
|
||||
/// [crate::ParamSetter] after the editor GUI has been created.
|
||||
/// [`Editor::spawn()`]. A plugin editor likely wants to interact with the plugin's parameters
|
||||
/// and other shared data, so you'll need to move [`Arc`] pointing to any data you want to
|
||||
/// access into the editor. You can later modify the parameters through the
|
||||
/// [`GuiContext`][crate::GuiContext] and [`ParamSetter`][crate::ParamSetter] after the editor
|
||||
/// GUI has been created.
|
||||
fn editor(&self) -> Option<Box<dyn Editor>> {
|
||||
None
|
||||
}
|
||||
|
@ -97,14 +98,16 @@ pub trait Plugin: Default + Send + Sync + 'static {
|
|||
/// abort the program when any allocation accurs in the process function while running in debug
|
||||
/// mode.
|
||||
///
|
||||
/// The framework provides convenient iterators on the [Buffer] object to process audio either
|
||||
/// The framework provides convenient iterators on the [`Buffer`] object to process audio either
|
||||
/// either per-sample per-channel, or per-block per-channel per-sample. The first approach is
|
||||
/// preferred for plugins that don't require block-based processing because of their use of
|
||||
/// per-sample SIMD or excessive branching. The parameter smoothers can also work in both modes:
|
||||
/// use [crate::Smoother::next()] for per-sample processing, and [crate::Smoother::next_block()]
|
||||
/// for block-based processing. In order to use block-based smoothing, you will need to call
|
||||
/// [Self::initialize_block_smoothers()] in your [Self::initialize()] function first to reserve
|
||||
/// enough capacity in the smoothers.
|
||||
/// use [`Smoother::next()`][crate::Smoother::next()] for per-sample processing, and
|
||||
/// [`Smoother::next_block()`][crate::Smoother::next_block()] for block-based processing. In
|
||||
/// order to use block-based smoothing, you will need to call
|
||||
/// [`initialize_block_smoothers()`][Self::initialize_block_smoothers()] in your
|
||||
/// [`initialize()`][Self::initialize()] function first to reserve enough capacity in the
|
||||
/// smoothers.
|
||||
///
|
||||
/// TODO: Provide a way to access auxiliary input channels if the IO configuration is
|
||||
/// assymetric
|
||||
|
@ -113,10 +116,10 @@ pub trait Plugin: Default + Send + Sync + 'static {
|
|||
fn process(&mut self, buffer: &mut Buffer, context: &mut impl ProcessContext) -> ProcessStatus;
|
||||
|
||||
/// Convenience function to allocate memory for block-based smoothing. Since this allocates
|
||||
/// memory, this should be called in [Self::initialize()]. If you are going to use
|
||||
/// [Buffer::iter_blocks] and want to use parameter smoothing in those blocks, then call this
|
||||
/// function with the same maximum block size first before calling
|
||||
/// [crate::Smoother::next_block()].
|
||||
/// memory, this should be called in [`initialize()`][Self::initialize()]. If you are going to
|
||||
/// use [`Buffer::iter_blocks()`] and want to use parameter smoothing in those blocks, then call
|
||||
/// this function with the same maximum block size first before calling
|
||||
/// [`Smoother::next_block()`][crate::Smoother::next_block()].
|
||||
fn initialize_block_smoothers(&mut self, max_block_size: usize) {
|
||||
for param in self.params().param_map().values_mut() {
|
||||
unsafe { param.initialize_block_smoother(max_block_size) };
|
||||
|
@ -152,13 +155,13 @@ pub trait Vst3Plugin: Plugin {
|
|||
///
|
||||
/// This will be shuffled into a different byte order on Windows for project-compatibility.
|
||||
const VST3_CLASS_ID: [u8; 16];
|
||||
/// One or more categories, separated by pipe characters (`|`), up to 127 characters. Anything
|
||||
/// One or more categories, separated by pipe characters (`|), up to 127 characters. Anything
|
||||
/// logner than that will be truncated. See the VST3 SDK for examples of common categories:
|
||||
/// <https://github.com/steinbergmedia/vst3_pluginterfaces/blob/2ad397ade5b51007860bedb3b01b8afd2c5f6fba/vst/ivstaudioprocessor.h#L49-L90>
|
||||
const VST3_CATEGORIES: &'static str;
|
||||
|
||||
/// [Self::VST3_CLASS_ID] in the correct order for the current platform so projects and presets
|
||||
/// can be shared between platforms. This should not be overridden.
|
||||
/// [`VST3_CLASS_ID`][Self::VST3_CLASS_ID`] in the correct order for the current platform so
|
||||
/// projects and presets can be shared between platforms. This should not be overridden.
|
||||
const PLATFORM_VST3_CLASS_ID: [u8; 16] = swap_vst3_uid_byte_order(Self::VST3_CLASS_ID);
|
||||
}
|
||||
|
||||
|
@ -185,16 +188,16 @@ const fn swap_vst3_uid_byte_order(mut uid: [u8; 16]) -> [u8; 16] {
|
|||
uid
|
||||
}
|
||||
|
||||
/// An editor for a [Plugin].
|
||||
/// An editor for a [`Plugin`].
|
||||
pub trait Editor: Send + Sync {
|
||||
/// Create an instance of the plugin's editor and embed it in the parent window. As explained in
|
||||
/// [Plugin::editor], you can then read the parameter values directly from your [crate::Params]
|
||||
/// [`Plugin::editor()`], you can then read the parameter values directly from your [`Params`]
|
||||
/// object, and modifying the values can be done using the functions on the
|
||||
/// [crate::ParamSetter]. When you change a parameter value that way it will be broadcasted to
|
||||
/// the host and also updated in your [Params] struct.
|
||||
/// [`ParamSetter`][crate::ParamSetter]. When you change a parameter value that way it will be
|
||||
/// broadcasted to the host and also updated in your [`Params`] struct.
|
||||
///
|
||||
/// This function should return a handle to the editor, which will be dropped when the editor
|
||||
/// gets closed. Implement the [Drop] trait on the returned handle if you need to explicitly
|
||||
/// gets closed. Implement the [`Drop`] trait on the returned handle if you need to explicitly
|
||||
/// handle the editor's closing behavior.
|
||||
///
|
||||
/// The wrapper guarantees that a previous handle has been dropped before this function is
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn db_to_gain(dbs: f32) -> f32 {
|
|||
}
|
||||
|
||||
/// Convert a voltage gain ratio to decibels. Gain ratios that aren't positive will be treated as
|
||||
/// [MINUS_INFINITY_DB].
|
||||
/// [`MINUS_INFINITY_DB`].
|
||||
pub fn gain_to_db(gain: f32) -> f32 {
|
||||
if gain > 0.0 {
|
||||
gain.log10() * 20.0
|
||||
|
|
|
@ -10,14 +10,14 @@ use crate::param::internals::ParamPtr;
|
|||
use crate::plugin::{ClapPlugin, NoteEvent};
|
||||
use crate::GuiContext;
|
||||
|
||||
/// A [GuiContext] implementation for the wrapper. This is passed to the plugin in
|
||||
/// [crate::Editor::spawn()] so it can interact with the rest of the plugin and with the host for
|
||||
/// things like setting parameters.
|
||||
/// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in
|
||||
/// [`Editor::spawn()`][crate::Editor::spawn()] so it can interact with the rest of the plugin and
|
||||
/// with the host for things like setting parameters.
|
||||
pub(crate) struct WrapperGuiContext<P: ClapPlugin> {
|
||||
pub(super) wrapper: Arc<Wrapper<P>>,
|
||||
}
|
||||
|
||||
/// A [ProcessContext] implementation for the wrapper. This is a separate object so it can hold on
|
||||
/// A [`ProcessContext`] implementation for the wrapper. This is a separate object so it can hold on
|
||||
/// to lock guards for event queues. Otherwise reading these events would require constant
|
||||
/// unnecessary atomic operations to lock the uncontested RwLocks.
|
||||
pub(crate) struct WrapperProcessContext<'a, P: ClapPlugin> {
|
||||
|
|
|
@ -11,7 +11,8 @@ use crate::plugin::ClapPlugin;
|
|||
/// A static descriptor for a plugin. This is used in both the descriptor and on the plugin object
|
||||
/// itself.
|
||||
///
|
||||
/// This cannot be cloned as [Self::clap_features_ptrs] contains pointers to [Self::clap_features].
|
||||
/// This cannot be cloned as [`Self::clap_features_ptrs`] contains pointers to
|
||||
/// [Self::clap_features].
|
||||
pub struct PluginDescriptor<P: ClapPlugin> {
|
||||
// We need [CString]s for all of `ClapPlugin`'s `&str` fields
|
||||
clap_id: CString,
|
||||
|
|
|
@ -8,7 +8,7 @@ macro_rules! check_null_ptr {
|
|||
};
|
||||
}
|
||||
|
||||
/// The same as [check_null_ptr!], but with a custom message.
|
||||
/// The same as [`check_null_ptr!`], but with a custom message.
|
||||
macro_rules! check_null_ptr_msg {
|
||||
($msg:expr, $ret:expr, $ptr:expr $(, $ptrs:expr)* $(, )?) => {
|
||||
if $ptr.is_null() $(|| $ptrs.is_null())* {
|
||||
|
|
|
@ -90,7 +90,7 @@ pub struct Wrapper<P: ClapPlugin> {
|
|||
/// The wrapped plugin instance.
|
||||
plugin: RwLock<P>,
|
||||
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
||||
/// to instantiate this in advance so we don't need to lock the entire [Plugin] object when
|
||||
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
||||
/// creating an editor.
|
||||
editor: Option<Arc<dyn Editor>>,
|
||||
/// A handle for the currently active editor instance. The plugin should implement `Drop` on
|
||||
|
@ -112,8 +112,8 @@ pub struct Wrapper<P: ClapPlugin> {
|
|||
/// TODO: Maybe load these lazily at some point instead of needing to spool them all to this
|
||||
/// queue first
|
||||
input_events: AtomicRefCell<VecDeque<NoteEvent>>,
|
||||
/// The current latency in samples, as set by the plugin through the [ProcessContext]. uses the
|
||||
/// latency extnesion
|
||||
/// The current latency in samples, as set by the plugin through the [`ProcessContext`]. uses
|
||||
/// the latency extnesion
|
||||
pub current_latency: AtomicU32,
|
||||
/// Contains slices for the plugin's outputs. You can't directly create a nested slice form
|
||||
/// apointer to pointers, so this needs to be preallocated in the setup call and kept around
|
||||
|
@ -171,9 +171,10 @@ pub struct Wrapper<P: ClapPlugin> {
|
|||
/// Mappings from string parameter indentifiers to parameter hashes. Useful for debug logging
|
||||
/// and when storing and restoring plugin state.
|
||||
param_id_to_hash: HashMap<&'static str, u32>,
|
||||
/// The inverse mapping from [Self::param_by_hash]. This is needed to be able to have an
|
||||
/// ergonomic parameter setting API that uses references to the parameters instead of having to
|
||||
/// add a setter function to the parameter (or even worse, have it be completely untyped).
|
||||
/// The inverse mapping from [`param_by_hash`][Self::param_by_hash]. This is needed to be able
|
||||
/// to have an ergonomic parameter setting API that uses references to the parameters instead of
|
||||
/// having to add a setter function to the parameter (or even worse, have it be completely
|
||||
/// untyped).
|
||||
pub param_ptr_to_hash: HashMap<ParamPtr, u32>,
|
||||
/// A queue of parameter changes that should be output in either the next process call or in the
|
||||
/// next parameter flush.
|
||||
|
@ -190,18 +191,19 @@ pub struct Wrapper<P: ClapPlugin> {
|
|||
/// A queue of tasks that still need to be performed. Because CLAP lets the plugin request a
|
||||
/// host callback directly, we don't need to use the OsEventLoop we use in our other plugin
|
||||
/// implementations. Instead, we'll post tasks to this queue, ask the host to call
|
||||
/// [Self::on_main_thread] on the main thread, and then continue to pop tasks off this queue
|
||||
/// there until it is empty.
|
||||
/// [`on_main_thread()`][Self::on_main_thread()] on the main thread, and then continue to pop
|
||||
/// tasks off this queue there until it is empty.
|
||||
tasks: ArrayQueue<Task>,
|
||||
/// The ID of the main thread. In practice this is the ID of the thread that created this
|
||||
/// object. If the host supports the thread check extension (and [Self::thread_check] thus
|
||||
/// contains a value), then that extension is used instead.
|
||||
/// object. If the host supports the thread check extension (and
|
||||
/// [`host_thread_check`][Self::host_thread_check] thus contains a value), then that extension
|
||||
/// is used instead.
|
||||
main_thread_id: ThreadId,
|
||||
}
|
||||
|
||||
/// Tasks that can be sent from the plugin to be executed on the main thread in a non-blocking
|
||||
/// realtime safe way. Instead of using a random thread or the OS' event loop like in the Linux
|
||||
/// implementation, this uses [clap_host::request_callback()] instead.
|
||||
/// implementation, this uses [`clap_host::request_callback()`] instead.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Task {
|
||||
/// Inform the host that the latency has changed.
|
||||
|
@ -223,11 +225,11 @@ pub struct OutputParamChange {
|
|||
/// The internal hash for the parameter.
|
||||
pub param_hash: u32,
|
||||
/// The 'plain' value as reported to CLAP. This is the normalized value multiplied by
|
||||
/// [crate::Param::step_size].
|
||||
/// [`Param::step_size()`][crate::Param::step_size()].
|
||||
pub clap_plain_value: f64,
|
||||
}
|
||||
|
||||
/// Because CLAP has this [clap_host::request_host_callback()] function, we don't need to use
|
||||
/// Because CLAP has this [`clap_host::request_host_callback()`] function, we don't need to use
|
||||
/// `OsEventLoop` and can instead just request a main thread callback directly.
|
||||
impl<P: ClapPlugin> EventLoop<Task, Wrapper<P>> for Wrapper<P> {
|
||||
fn new_and_spawn(_executor: std::sync::Weak<Self>) -> Self {
|
||||
|
@ -613,8 +615,8 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Handle an incoming CLAP event. You must clear [Self::input_events] first before calling this
|
||||
/// from the process function.
|
||||
/// Handle an incoming CLAP event. You must clear [`input_events`][Self::input_events] first
|
||||
/// before calling this from the process function.
|
||||
///
|
||||
/// To save on mutex operations when handing MIDI events, the lock guard for the input events
|
||||
/// need to be passed into this function.
|
||||
|
|
|
@ -26,7 +26,7 @@ pub(crate) struct State {
|
|||
/// parmaeter automation though, depending on how the host impelments that.
|
||||
pub params: HashMap<String, ParamValue>,
|
||||
/// Arbitrary fields that should be persisted together with the plugin's parameters. Any field
|
||||
/// on the [crate::param::internals::Params] struct that's annotated with `#[persist =
|
||||
/// on the [`Params`][crate::param::internals::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
|
||||
|
|
|
@ -50,7 +50,7 @@ pub fn strlcpy(dest: &mut [c_char], src: &str) {
|
|||
dest[copy_len] = 0;
|
||||
}
|
||||
|
||||
/// The same as [strlcpy()], but for VST3's fun UTF-16 strings instead.
|
||||
/// The same as [`strlcpy()`], but for VST3's fun UTF-16 strings instead.
|
||||
pub fn u16strlcpy(dest: &mut [TChar], src: &str) {
|
||||
if dest.is_empty() {
|
||||
return;
|
||||
|
|
|
@ -10,14 +10,14 @@ use crate::event_loop::EventLoop;
|
|||
use crate::param::internals::ParamPtr;
|
||||
use crate::plugin::{NoteEvent, Vst3Plugin};
|
||||
|
||||
/// A [GuiContext] implementation for the wrapper. This is passed to the plugin in
|
||||
/// [crate::Editor::spawn()] so it can interact with the rest of the plugin and with the host for
|
||||
/// things like setting parameters.
|
||||
/// A [`GuiContext`] implementation for the wrapper. This is passed to the plugin in
|
||||
/// [`Editor::spawn()`][crate::Editor::spawn()] so it can interact with the rest of the plugin and
|
||||
/// with the host for things like setting parameters.
|
||||
pub(crate) struct WrapperGuiContext<P: Vst3Plugin> {
|
||||
pub(super) inner: Arc<WrapperInner<P>>,
|
||||
}
|
||||
|
||||
/// A [ProcessContext] implementation for the wrapper. This is a separate object so it can hold on
|
||||
/// A [`ProcessContext`] implementation for the wrapper. This is a separate object so it can hold on
|
||||
/// to lock guards for event queues. Otherwise reading these events would require constant
|
||||
/// unnecessary atomic operations to lock the uncontested locks.
|
||||
pub(crate) struct WrapperProcessContext<'a, P: Vst3Plugin> {
|
||||
|
|
|
@ -24,16 +24,16 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
|||
/// The wrapped plugin instance.
|
||||
pub plugin: RwLock<P>,
|
||||
/// The plugin's editor, if it has one. This object does not do anything on its own, but we need
|
||||
/// to instantiate this in advance so we don't need to lock the entire [Plugin] object when
|
||||
/// to instantiate this in advance so we don't need to lock the entire [`Plugin`] object when
|
||||
/// creating an editor.
|
||||
pub editor: Option<Arc<dyn Editor>>,
|
||||
|
||||
/// The host's `IComponentHandler` instance, if passed through
|
||||
/// `IEditController::set_component_handler`.
|
||||
/// The host's [`IComponentHandler`] instance, if passed through
|
||||
/// [`IEditController::set_component_handler`].
|
||||
pub component_handler: AtomicRefCell<Option<VstPtr<dyn IComponentHandler>>>,
|
||||
|
||||
/// Our own [IPlugView] instance. This is set while the editor is actually visible (which is
|
||||
/// different form the lifetimei of [super::WrapperView] itself).
|
||||
/// Our own [`IPlugView`] instance. This is set while the editor is actually visible (which is
|
||||
/// different form the lifetime of [`WrapperView`][super::WrapperView] itself).
|
||||
pub plug_view: RwLock<Option<ObjectPtr<WrapperView<P>>>>,
|
||||
|
||||
/// A realtime-safe task queue so the plugin can schedule tasks that need to be run later on the
|
||||
|
@ -58,7 +58,7 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
|||
pub bypass_state: AtomicBool,
|
||||
/// The last process status returned by the plugin. This is used for tail handling.
|
||||
pub last_process_status: AtomicCell<ProcessStatus>,
|
||||
/// The current latency in samples, as set by the plugin through the [ProcessContext].
|
||||
/// The current latency in samples, as set by the plugin through the [`ProcessContext`].
|
||||
pub current_latency: AtomicU32,
|
||||
/// Contains slices for the plugin's outputs. You can't directly create a nested slice form
|
||||
/// apointer to pointers, so this needs to be preallocated in the setup call and kept around
|
||||
|
@ -84,9 +84,10 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
|||
/// Mappings from string parameter indentifiers to parameter hashes. Useful for debug logging
|
||||
/// and when storing and restorign plugin state.
|
||||
pub param_id_to_hash: HashMap<&'static str, u32>,
|
||||
/// The inverse mapping from [Self::param_by_hash]. This is needed to be able to have an
|
||||
/// ergonomic parameter setting API that uses references to the parameters instead of having to
|
||||
/// add a setter function to the parameter (or even worse, have it be completely untyped).
|
||||
/// The inverse mapping from [`param_by_hash`][Self::param_by_hash]. This is needed to be able
|
||||
/// to have an ergonomic parameter setting API that uses references to the parameters instead of
|
||||
/// having to add a setter function to the parameter (or even worse, have it be completely
|
||||
/// untyped).
|
||||
pub param_ptr_to_hash: HashMap<ParamPtr, u32>,
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,7 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Task {
|
||||
/// Trigger a restart with the given restart flags. This is a bit set of the flags from
|
||||
/// [vst3_sys::vst::RestartFlags].
|
||||
/// [`vst3_sys::vst::RestartFlags`].
|
||||
TriggerRestart(i32),
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ macro_rules! check_null_ptr {
|
|||
};
|
||||
}
|
||||
|
||||
/// The same as [check_null_ptr!], but with a custom message.
|
||||
/// The same as [`check_null_ptr!`], but with a custom message.
|
||||
macro_rules! check_null_ptr_msg {
|
||||
($msg:expr, $ptr:expr $(, $ptrs:expr)* $(, )?) => {
|
||||
if $ptr.is_null() $(|| $ptrs.is_null())* {
|
||||
|
@ -35,8 +35,8 @@ pub struct VstPtr<T: vst3_sys::ComInterface + ?Sized> {
|
|||
ptr: vst3_sys::VstPtr<T>,
|
||||
}
|
||||
|
||||
/// The same as [VstPtr] with shared semnatics, but for objects we defined ourself since VstPtr only
|
||||
/// works for interfaces.
|
||||
/// The same as [`VstPtr`] with shared semnatics, but for objects we defined ourself since VstPtr
|
||||
/// only works for interfaces.
|
||||
#[repr(transparent)]
|
||||
pub struct ObjectPtr<T: IUnknown> {
|
||||
ptr: *const T,
|
||||
|
|
|
@ -28,7 +28,7 @@ const VST3_PLATFORM_UIVIEW: &str = "UIView";
|
|||
#[allow(unused)]
|
||||
const VST3_PLATFORM_X11_WINDOW: &str = "X11EmbedWindowID";
|
||||
|
||||
/// The plugin's [IPlugView] instance created in [IEditController::create_view] if `P` has an
|
||||
/// The plugin's [`IPlugView`] instance created in [`IEditController::create_view()`] if `P` has an
|
||||
/// editor. This is managed separately so the lifetime bounds match up.
|
||||
#[VST3(implements(IPlugView))]
|
||||
pub(crate) struct WrapperView<P: Vst3Plugin> {
|
||||
|
|
|
@ -334,7 +334,7 @@ impl<P: Vst3Plugin> IEditController for Wrapper<P> {
|
|||
u16strlcpy(&mut info.title, param_ptr.name());
|
||||
u16strlcpy(&mut info.short_title, param_ptr.name());
|
||||
u16strlcpy(&mut info.units, param_ptr.unit());
|
||||
// TODO: The host assumes these steps are distirbuted linearly, so this may cause weird
|
||||
// TODO: The host assumes these steps are distributed linearly, so this may cause weird
|
||||
// behavior with skewed integers
|
||||
info.step_count = param_ptr.step_count().unwrap_or(0) as i32;
|
||||
info.default_normalized_value = *default_value as f64;
|
||||
|
|
Loading…
Reference in a new issue