From 49e683e396e6cba7e1dc787999637b41d30051de Mon Sep 17 00:00:00 2001
From: Robbert van der Helm <mail@robbertvanderhelm.nl>
Date: Tue, 14 Jun 2022 15:44:42 +0200
Subject: [PATCH] Add a cli for controlling the standalone settings

---
 src/wrapper/standalone.rs         | 38 ++++++++++++-------------------
 src/wrapper/standalone/wrapper.rs | 20 ++++++++++++----
 2 files changed, 30 insertions(+), 28 deletions(-)

diff --git a/src/wrapper/standalone.rs b/src/wrapper/standalone.rs
index 5636acb0..37b3a732 100644
--- a/src/wrapper/standalone.rs
+++ b/src/wrapper/standalone.rs
@@ -1,6 +1,8 @@
 //! 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 clap::{FromArgMatches, IntoApp};
+
 use self::wrapper::{Wrapper, WrapperConfig, WrapperError};
 use super::util::setup_logger;
 use crate::plugin::Plugin;
@@ -42,13 +44,6 @@ mod wrapper;
 ///
 /// If the wrapped plugin fails to initialize or throws an error during audio processing, then this
 /// function will return `false`.
-///
-/// # TODOs
-///
-/// The aforementioned command line options have not yet been implemented. Currently there's also no
-/// way to change these options at runtime, for instance through the plugin's GUI. And lastly
-/// there's no way to interact with parameters outside of what's exposed through the plugin's GUI.
-/// We should implement a REPL at some point for interacting with the plugin.
 pub fn nih_export_standalone<P: Plugin>() -> bool {
     nih_export_standalone_with_args::<P, _>(std::env::args())
 }
@@ -56,26 +51,20 @@ pub fn nih_export_standalone<P: Plugin>() -> bool {
 /// The same as [`nih_export_standalone()`], but with the arguments taken from an iterator instead
 /// of using [`std::env::args()`].
 pub fn nih_export_standalone_with_args<P: Plugin, Args: IntoIterator<Item = String>>(
-    _args: Args,
+    args: Args,
 ) -> bool {
     setup_logger();
 
-    // TODO: Do something with the arguments
-
-    // FIXME: The configuration should be set based on the command line arguments
-    let config = WrapperConfig {
-        input_channels: 2,
-        output_channels: 2,
-        sample_rate: 44100.0,
-        period_size: 512,
-
-        // TODO: When adding command line options, ignore this option on macOS
-        dpi_scale: 1.0,
-
-        tempo: 120.0,
-        timesig_num: 4,
-        timesig_denom: 4,
-    };
+    // Instead of parsing this directly, we need to take a bit of a roundabout approach to get the
+    // plugin's name and vendor in here since they'd otherwise be taken from NIH-plug's own
+    // `Cargo.toml` file.
+    let config = WrapperConfig::from_arg_matches(
+        &WrapperConfig::command()
+            .name(P::NAME)
+            .author(P::VENDOR)
+            .get_matches_from(args),
+    )
+    .unwrap_or_else(|err| err.exit());
 
     nih_log!(
         "Audio and MIDI IO has not yet been implemented in the standalone targets. So if you're \
@@ -93,6 +82,7 @@ pub fn nih_export_standalone_with_args<P: Plugin, Args: IntoIterator<Item = Stri
         }
     };
 
+    // TODO: Add a repl while the application is running to interact with parameters
     match wrapper.run() {
         Ok(()) => true,
         Err(err) => {
diff --git a/src/wrapper/standalone/wrapper.rs b/src/wrapper/standalone/wrapper.rs
index 9e96f776..ecb03206 100644
--- a/src/wrapper/standalone/wrapper.rs
+++ b/src/wrapper/standalone/wrapper.rs
@@ -1,5 +1,6 @@
 use atomic_refcell::AtomicRefCell;
 use baseview::{EventStatus, Window, WindowHandler, WindowOpenOptions};
+use clap::Parser;
 use crossbeam::channel;
 use crossbeam::queue::ArrayQueue;
 use parking_lot::RwLock;
@@ -27,28 +28,39 @@ use crate::wrapper::state::{self, PluginState};
 const EVENT_QUEUE_CAPACITY: usize = 2048;
 
 /// Configuration for a standalone plugin that would normally be provided by the DAW.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Parser)]
+#[clap(about = None, long_about = None)]
 pub struct WrapperConfig {
     /// The number of input channels.
+    #[clap(value_parser, short = 'i', long, default_value = "2")]
     pub input_channels: u32,
     /// The number of output channels.
+    #[clap(value_parser, short = 'o', long, default_value = "2")]
     pub output_channels: u32,
     /// The audio backend's sample rate.
+    #[clap(value_parser, short = 'r', long, default_value = "44100")]
     pub sample_rate: f32,
     /// The audio backend's period size.
+    #[clap(value_parser, short = 'p', long, default_value = "512")]
     pub period_size: u32,
 
-    /// The editor's DPI scaling factor. Currently baseview has no way to report this to us, so
-    /// we'll expose it as a command line option instead.
+    /// The editor's DPI scaling factor.
     ///
     /// This option is ignored on macOS.
+    //
+    // Currently baseview has no way to report this to us, so we'll expose it as a command line
+    // option instead.
+    #[clap(value_parser, long, default_value = "1.0")]
     pub dpi_scale: f32,
 
-    /// The current tempo.
+    /// The transport's tempo.
+    #[clap(value_parser, long, default_value = "120")]
     pub tempo: f32,
     /// The time signature's numerator.
+    #[clap(value_parser, long, default_value = "4")]
     pub timesig_num: u32,
     /// The time signature's denominator.
+    #[clap(value_parser, long, default_value = "4")]
     pub timesig_denom: u32,
 }