From 44476ad696cba63b959bb7acd7c3b278b2b6c987 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Mon, 24 Apr 2023 14:37:14 +0200 Subject: [PATCH] Better describe the `Plugin` trait --- src/lib.rs | 3 +++ src/plugin.rs | 44 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ca947608..f023f28c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,9 @@ //! a call to [`nih_export_vst3!()`] and/or [`nih_export_clap!()`] in your `lib.rs` file to expose //! the plugin functionality. Some of these traits will require you to implement an additional //! trait containing API-specific information for the plugin. +//! +//! Check the `Plugin` trait's documentation for more information on NIH-plug's general structure +//! and approach with respect to declarativity. //! - NIH-plug comes with a bundler that creates plugin bundles for you based on the exported plugin //! formats and the operating system and architecture you're compiling for. Check out the //! readme for diff --git a/src/plugin.rs b/src/plugin.rs index 8e57f260..b36399f1 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -17,18 +17,44 @@ pub mod vst3; /// they can be deferred for later to avoid blocking realtime contexts. pub type TaskExecutor

= Box::BackgroundTask) + Send>; -/// Basic functionality that needs to be implemented by a plugin. The wrappers will use this to -/// expose the plugin in a particular plugin format. +/// The main plugin trait covering functionality common across most plugin formats. Most formats +/// also have another trait with more specific data and functionality that needs to be implemented +/// before the plugin can be exported to that format. The wrappers will use this to expose the +/// plugin in a particular plugin format. +/// +/// NIH-plug is semi-declarative, meaning that most information about a plugin is defined +/// declaratively but it also doesn't shy away from maintaining state when that is the path of least +/// resistance. As such, the definitions on this trait fall in one of the following classes: +/// +/// - `Plugin` objects are stateful. During their lifetime the plugin API wrappers will call the +/// various lifecycle methods defined below, with the `initialize()`, `reset()`, and `process()` +/// functions being the most important ones. +/// - Most of the rest of the trait statically describes the plugin. You will find this done in +/// three different ways: +/// - Most of this data, including the supported audio IO layouts, is simple enough that it can be +/// defined through compile-time constants. +/// - Some of the data is queried through a method as doing everything at compile time would +/// impose a lot of restrictions on code structure and meta programming without any real +/// benefits. In those cases the trait defines a method that is queried once and only once, +/// immediately after instantiating the `Plugin` through `Plugin::default()`. Examples of these +/// methods are [`Plugin::params()`], and +/// [`ClapPlugin::remote_controls()`][clap::ClapPlugin::remote_controls()]. +/// - Some of the data is defined through associated types. Rust currently sadly does not support +/// default values for associated types, but all of these types can be set to `()` if you wish +/// to ignore them. Examples of these types are [`Plugin::SysExMessage`] and +/// [`Plugin::BackgroundTask`]. +/// - Finally, there are some functions that return extension structs and handlers, similar to how +/// the `params()` function returns a data structure describing the plugin's parameters. Examples +/// of these are the [`Plugin::editor()`] and [`Plugin::task_executor()`] functions, and they're +/// also called once and only once after the plugin object has been created. This allows the audio +/// thread to have exclusive access to the `Plugin` object, and it makes it easier to compose +/// these extension structs since they're more loosely coupled to a specific `Plugin` +/// implementation. /// /// The main thing you need to do is define a `[Params]` struct containing all of your parameters. /// See the trait's documentation for more information on how to do that, or check out the examples. -/// Most of the other functionality is optional and comes with default trait method implementations. -/// -/// Some notable not yet implemented features include: -/// -/// - MIDI2 for CLAP, note expressions, polyphonic modulation and MIDI1, and MIDI SysEx are already -/// supported -/// - Audio thread thread pools (with host integration in CLAP) +/// The plugin also needs a `Default` implementation so it can be initialized. Most of the other +/// functionality is optional and comes with default trait method implementations. #[allow(unused_variables)] pub trait Plugin: Default + Send + 'static { /// The plugin's name.