From f3db4a9ed02da7157e6a8c2a4d556164c09266c4 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 22 Apr 2022 17:00:59 +0200 Subject: [PATCH] Add a (not yet functional) standalone exporter --- .github/workflows/test.yml | 2 +- Cargo.toml | 9 ++++++-- README.md | 2 ++ nih_plug_xtask/src/lib.rs | 2 ++ src/plugin.rs | 1 - src/prelude.rs | 2 ++ src/wrapper.rs | 2 ++ src/wrapper/standalone.rs | 35 +++++++++++++++++++++++++++++++ src/wrapper/standalone/wrapper.rs | 19 +++++++++++++++++ 9 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/wrapper/standalone.rs create mode 100644 src/wrapper/standalone/wrapper.rs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 474aa396..7fb173ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -61,7 +61,7 @@ jobs: command: build # Don't use --all-features as that will enable a whole bunch of # conflicting iced features - args: --workspace --features "simd" + args: --workspace --features "simd,standalone" - name: Run the tests uses: actions-rs/cargo@v1 with: diff --git a/Cargo.toml b/Cargo.toml index 230157f5..7880c032 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,13 +35,18 @@ members = [ [features] default = ["vst3"] + # Enabling this feature will cause the plugin to terminate when allocations # occur in the processing function while compiling in debug mode. Keep in mind # that most panic handlers will also allocate, so temporarily disabling this # feature may be necessary when debugging panics in DSP code. assert_process_allocs = ["dep:assert_no_alloc"] -# Enables the `nih_export_vst3()` macro. Enabled by default. This feature exists -# mostly for GPL-compliance reasons, since even if you don't use the VST3 +# Enables an export target for standalone binaries through the +# `nih_export_standalone()` function. Disabled by default, as this requires +# building additional dependencies for audio and MIDI handling. +standalone = [] +# Enables the `nih_export_vst3!()` macro. Enabled by default. This feature +# exists mostly for GPL-compliance reasons, since even if you don't use the VST3 # wrapper you might otherwise still include a couple (unused) symbols from the # `vst3-sys` create. vst3 = ["dep:vst3-sys"] diff --git a/README.md b/README.md index b550973f..bf47b58e 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ for download links. - Supports both VST3 and [CLAP](https://github.com/free-audio/clap) by simply adding the corresponding `nih_export_!(Foo)` macro to your plugin's library. +- Standalone binaries can be made by calling `nih_export_standalone(Foo)` from + your `main()` function. - Declarative parameter handling without any boilerplate. - Define parameters for your plugin by adding `FloatParam`, `IntParam`, `BoolParam`, and `EnumParam` fields to your parameter struct, assign diff --git a/nih_plug_xtask/src/lib.rs b/nih_plug_xtask/src/lib.rs index 321b5a27..1295c7e8 100644 --- a/nih_plug_xtask/src/lib.rs +++ b/nih_plug_xtask/src/lib.rs @@ -175,6 +175,8 @@ pub fn bundle(package: &str, args: &[String]) -> Result<()> { } } + // TODO: Add support for binary targets. This would simply copy/reflink the binary to the + // `bundled` directory to make it easier to ship all versions of a plugin. let compilation_target = compilation_target(cross_compile_target.as_deref())?; let lib_path = target_base(cross_compile_target.as_deref())? .join(if is_release_build { "release" } else { "debug" }) diff --git a/src/plugin.rs b/src/plugin.rs index 3e584665..0cfac489 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -22,7 +22,6 @@ use crate::param::internals::Params; /// - Multiple output busses /// - Special handling for offline processing /// - MIDI SysEx and MIDI2 for CLAP, note expressions and MIDI1 are already supported -/// - An export target for a standalone application #[allow(unused_variables)] pub trait Plugin: Default + Send + Sync + 'static { const NAME: &'static str; diff --git a/src/prelude.rs b/src/prelude.rs index f78bed04..05275172 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,6 +9,8 @@ pub use crate::nih_trace; #[cfg(feature = "vst3")] pub use crate::nih_export_vst3; +#[cfg(feature = "standalone")] +pub use crate::wrapper::standalone::{nih_export_standalone, nih_export_standalone_with_args}; pub use crate::formatters; pub use crate::util; diff --git a/src/wrapper.rs b/src/wrapper.rs index 2551e6e8..d2e745ed 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -5,6 +5,8 @@ pub mod clap; pub mod state; pub(crate) mod util; +#[cfg(feature = "standalone")] +pub mod standalone; #[cfg(feature = "vst3")] pub mod vst3; diff --git a/src/wrapper/standalone.rs b/src/wrapper/standalone.rs new file mode 100644 index 00000000..2eff5dca --- /dev/null +++ b/src/wrapper/standalone.rs @@ -0,0 +1,35 @@ +//! A standalone plugin target that directly connects to the system's audio and MIDI ports instead +//! of relying on a plugin host. This is mostly useful for quickly testing GUI changes. + +use self::wrapper::Wrapper; +use crate::plugin::Plugin; + +mod wrapper; + +/// Open an NIH-plug plugin as a standalone application. If the plugin has an editor, this will open +/// the editor and block until the editor is closed. Otherwise this will block until SIGINT is +/// received. This is mainly useful for quickly testing plugin GUIs. You should call this function +/// from a `main()` function. +/// +/// By default this will connect to the 'default' audio and MIDI ports. Use the command line options +/// to change this. `--help` lists all available options. +/// +/// # TODO +/// +/// The aforementioned command line options have not yet been implemented. +// +// TODO: Actually implement command line flags for changing the IO configuration +// TODO: Add a way to set the IO configuration at runtime, for instance through the plugin's GUI +pub fn nih_export_standalone() { + nih_export_standalone_with_args::(std::env::args()) +} + +pub fn nih_export_standalone_with_args>(args: Args) { + // TODO: Do something with the arguments + + Wrapper::

::new(); + + // TODO: Open the editor if available, do IO things + // TODO: If the plugin has an editor, block until the editor is closed. Otherwise block + // indefinitely or until SIGINT (how do signal handlers work in Rust?) +} diff --git a/src/wrapper/standalone/wrapper.rs b/src/wrapper/standalone/wrapper.rs new file mode 100644 index 00000000..c6c7eb84 --- /dev/null +++ b/src/wrapper/standalone/wrapper.rs @@ -0,0 +1,19 @@ +use parking_lot::RwLock; + +use crate::plugin::Plugin; + +pub struct Wrapper { + /// The wrapped plugin instance. + plugin: RwLock

, +} + +impl Wrapper

{ + /// Instantiate a new instance of the standalone wrapper. + // + // TODO: This should take some arguments for the audio and MIDI IO. + pub fn new() -> Self { + Wrapper { + plugin: RwLock::new(P::default()), + } + } +}