From 8239169aaf825bb36dafbabc5e99cd923753060c Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 13 May 2022 15:08:05 +0200 Subject: [PATCH] Add some pointers for getting started to the docs --- README.md | 20 +++++------ src/lib.rs | 82 ++++++++++++++++++++++++++++++++++++++++++-- src/param/float.rs | 9 ++--- src/param/integer.rs | 4 +-- src/util/stft.rs | 2 +- 5 files changed, 98 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 50c01f97..a79b4bca 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,18 @@ [![Docs](https://github.com/robbert-vdh/nih-plug/actions/workflows/docs.yml/badge.svg?branch=master)](https://nih-plug.robbertvanderhelm.nl/) This is a work in progress API-agnostic audio plugin framework written in Rust -to do some experiments with, as well as a small collection of plugins. The idea -is to have a statefull but simple plugin API that gets rid of as much -unnecessary ceremony wherever possible, while also keeping the amount of magic -to minimum. Since this is not quite meant for general use just yet, the plugin -API surface is currently limited to the functionality that I either needed -myself or that was requested by others. See the [current -features](#current-features) section for more information on the project's -current status. +as well as a small collection of plugins. The idea is to have a statefull but +simple plugin API that gets rid of as much unnecessary ceremony wherever +possible, while also keeping the amount of magic to minimum. Since this is not +quite meant for general use just yet, the plugin API surface is currently +limited to the functionality that I either needed myself or that was requested +by others. See the [current features](#current-features) section for more +information on the project's current status. Come join us on the [Rust Audio Discord](https://discord.gg/ykxU3rt4Cb), or -check out the [documentation](https://nih-plug.robbertvanderhelm.nl/) (work in -progress). +check out the work in progress +[documentation](https://nih-plug.robbertvanderhelm.nl/) for some pointers on how +to get started. ### Table of contents diff --git a/src/lib.rs b/src/lib.rs index b272ed65..c0d54bb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,83 @@ -//! Documentation is currently a work in progress. Import everything from the [`prelude`] module and -//! check out the example plugins to get started. +//! Documentation is still a work in progress. The best way to learn right now is to browse through +//! the examples and to browse through these docs. There is no full guide yet, but here are some +//! pointers to get started: +//! +//! - All useful functionality is exported through the [`prelude`] module. Add +//! `use nih_plug::prelude::*;` to the top of your `lib.rs` file to get started. +//! - Make sure to check out the macros from the [`debug`] module. These should be used instead of, +//! `println!()`/`eprint!()`, `dbg!()` and similar macros, and they are re-exported from the +//! prelude. NIH-plug sets up a flexible logger for you that all of these functions will output +//! to. By default, the output is logged to STDERR unless you're running Windows and a Windows +//! debugger is attached, in which case the output is logged to the debug console instead. The +//! `NIH_LOG` environment variable controls whether output is logged to STDERR, the Windows debug +//! console, or to a file. Check the [`nih_log!()`] macro for more information. +//! - The abovementioned debug module also contains non-fatal debug-assertions macros that are only +//! evaluated during debug builds. The framework uses these all over the place to check for +//! invariants, so it's important to test your plugins using debug builds while developing. +//! - Check out the features list in NIH-plug's `Cargo.toml` file for optional features you can +//! enable. This includes things like SIMD support for the buffer adapters and panicking on +//! allocations during DSP code in debug mode. +//! +//! - An NIH-plug plugin consists of an implementation of the [`Plugin`][prelude::Plugin] trait and +//! 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. +//! - 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 +//! [`nih_plug_xtask`](https://github.com/robbert-vdh/nih-plug/tree/master/nih_plug_xtask) for +//! instructions on how to use this within your own project. +//! - It's also possible to export a standalone application from a plugin using the +//! [`nih_export_standalone()`][prelude::nih_export_standalone()] function. Check that function's +//! documentation to learn how to do this. This requires enabling the `standalone` crate feature. +//! - Everything is described in more detail on the [`Plugin`][prelude::Plugin] trait and everything +//! linked from there, but a plugin's general lifecycle involves the following function calls. +//! +//! 1. When the host loads the plugin, your plugin object will be instantiated using its +//! [`Default`] implementation. The plugin should refrain from performing expensive +//! calculations or IO at this point. +//! 2. The host or the plugin wrapper will call +//! [`Plugin::accepts_bus_config()`][prelude::Plugin::accepts_bus_config()] several times with +//! different IO configuratinos to poll whether your plugin supports certain IO configurations. +//! The plugin should not do any work at this point and just reply with boolean whether it +//! supports the configuration or not. +//! 3. After that, [`Plugin::initialize()`][prelude::Plugin::initialize()] will be called with the +//! the selected IO configuration and the audio buffer settings. Here you should allocate any +//! data structures you need or precompute data that depends on the sample rate or maximum +//! buffer size. This is the only place where you can safely allocate memory. +//! 4. The [`Plugin::reset()`][prelude::Plugin::reset()] function is always called immediately +//! after `initialize()`. This is where you should clear out coefficients, envelopes, phases, +//! and other runtime data. The reason for this split is that this function may be called at +//! any time by the host from the audio thread, and it thus needs to be realtime safe. +//! +//! Whenever a preset is loaded, both of these functions will be called again. +//! 5. After that the [`Plugin::process()`][prelude::Plugin::process()] function will be called +//! repeatedly until the plugin is deactivated. Here the plugin receives a +//! [`Buffer`][prelude::Buffer] object that contains the input audio (if the plugin has inputs) +//! which the plugin should overwrite with output audio. Check the documentation on the +//! `Buffer` object for all of the ways you can use this API. You can access note events, +//! transport data, and more through the [`ProcessContext`][prelude::ProcessContext] that's +//! also passed to the process function. +//! +//! - Plugin parameters are managed automatically by creating a struct deriving the +//! [`Params`][prelude::Params] trait and returning a handle to it from the +//! [`Plugin::params()`][prelude::Plugin::params()] function. Any +//! [`FloatParam`][prelude::FloatParam], [`IntParam`][prelude::IntParam], +//! [`BoolParam`][prelude::BoolParam] or [`EnumParam`][prelude::EnumParam] fields on that struct +//! will automatically be registered as a parameter if they have an `#[id = "foobar"]` attribute. +//! The string `"foobar"` here uniquely identifies the parameter, making it possible to reorder +//! and rename parameters as long as this string stays constant. You can also store persistent +//! non-parameter data and other parameter objects in a `Params` struct. Check out the trait's +//! documentation for more details, and also be sure to take a look at the [example +//! plugins](https://github.com/robbert-vdh/nih-plug/tree/master/plugins). +//! - After calling `.with_smoother()` during an integer or floating point parameter's creation, +//! you can use `param.smoothed` to access smoothed values for that parameter. Be sure to check +//! out the [`Smoother`][prelude::Smoother] API for more details. If you want to generate entire +//! blocks of smoothed values, be sure to call the predefined +//! `[Plugin::initialize_block_smoothers()]` method from your plugin's `initialize()` function. +//! +//! There's a whole lot more to discuss, but once you understand the above you should be able to +//! figure out the rest by reading through the examples and the API documetnation. Good luck! #![cfg_attr(feature = "docs", feature(doc_auto_cfg))] #![cfg_attr(feature = "simd", feature(portable_simd))] diff --git a/src/param/float.rs b/src/param/float.rs index 14fc874a..a1cea599 100644 --- a/src/param/float.rs +++ b/src/param/float.rs @@ -309,16 +309,17 @@ impl FloatParam { } /// Display a unit when rendering this parameter to a string. Appended after the - /// [`value_to_string`][Self::value_to_string] function if that is also set. NIH-plug will not - /// automatically add a space before the unit. + /// [`value_to_string`][Self::with_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; self } /// Set the distance between steps of a [FloatParam]. Mostly useful for quantizing GUI 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. + /// this is set and a [`value_to_string`][Self::with_value_to_string()] function 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 diff --git a/src/param/integer.rs b/src/param/integer.rs index 61c0b332..3b763a1a 100644 --- a/src/param/integer.rs +++ b/src/param/integer.rs @@ -270,8 +270,8 @@ impl IntParam { } /// Display a unit when rendering this parameter to a string. Appended after the - /// [`value_to_string`][Self::value_to_string] function if that is also set. NIH-plug will not - /// automatically add a space before the unit. + /// [`value_to_string`][Self::with_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; self diff --git a/src/util/stft.rs b/src/util/stft.rs index ecf77a11..21b97464 100644 --- a/src/util/stft.rs +++ b/src/util/stft.rs @@ -262,7 +262,7 @@ impl StftHelper { /// next block before `process_cb()` is called. /// /// Since there are a couple different ways to do it, any window functions needs to be applied - /// in the callbacks. Check the [`nih_plug::util::window`] module for more information. + /// in the callbacks. Check the [`nih_plug::util::window`][crate::util::window] module for more information. /// /// For efficiency's sake this function will reuse the same vector for all calls to /// `process_cb`. This means you can only access a single channel's worth of windowed data at a