diff --git a/CHANGELOG.md b/CHANGELOG.md index 74bf96f1..dba9bed4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,20 @@ Since there is no stable release yet, the changes are organized per day in reverse chronological order. The main purpose of this document in its current state is to list breaking changes. +## [2023-04-24] + +### Breaking changes + +- `Plugin::editor()` and `Plugin::task_executor()` now take `&mut self` instead + of `&self` to make it easier to move data into these functions without + involving interior mutability. + +### Changed + +- The `Plugin` trait's documentation has been updated to better clarify the + structure and to more explicitly mention that the non-lifecycle methods are + called once immediately after creating the plugin object. + ## [2023-04-22] ### Added diff --git a/plugins/crisp/src/lib.rs b/plugins/crisp/src/lib.rs index 668b5060..0cb88449 100644 --- a/plugins/crisp/src/lib.rs +++ b/plugins/crisp/src/lib.rs @@ -317,7 +317,7 @@ impl Plugin for Crisp { self.params.clone() } - fn editor(&self, _async_executor: AsyncExecutor) -> Option> { + fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { editor::create(self.params.clone(), self.params.editor_state.clone()) } diff --git a/plugins/diopser/src/lib.rs b/plugins/diopser/src/lib.rs index 28b6ca8c..aa01deb1 100644 --- a/plugins/diopser/src/lib.rs +++ b/plugins/diopser/src/lib.rs @@ -126,7 +126,7 @@ impl Plugin for Diopser { self.params.clone() } - fn editor(&self, _async_executor: AsyncExecutor) -> Option> { + fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { editor::create( editor::Data { params: self.params.clone(), diff --git a/plugins/examples/gain_gui_egui/src/lib.rs b/plugins/examples/gain_gui_egui/src/lib.rs index d7687bd0..e0d891fd 100644 --- a/plugins/examples/gain_gui_egui/src/lib.rs +++ b/plugins/examples/gain_gui_egui/src/lib.rs @@ -100,7 +100,7 @@ impl Plugin for Gain { self.params.clone() } - fn editor(&self, _async_executor: AsyncExecutor) -> Option> { + fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { let params = self.params.clone(); let peak_meter = self.peak_meter.clone(); create_egui_editor( diff --git a/plugins/examples/gain_gui_iced/src/lib.rs b/plugins/examples/gain_gui_iced/src/lib.rs index 53ae1e23..15a30ca5 100644 --- a/plugins/examples/gain_gui_iced/src/lib.rs +++ b/plugins/examples/gain_gui_iced/src/lib.rs @@ -97,7 +97,7 @@ impl Plugin for Gain { self.params.clone() } - fn editor(&self, _async_executor: AsyncExecutor) -> Option> { + fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { editor::create( self.params.clone(), self.peak_meter.clone(), diff --git a/plugins/examples/gain_gui_vizia/src/lib.rs b/plugins/examples/gain_gui_vizia/src/lib.rs index b9353c80..00a0dcd9 100644 --- a/plugins/examples/gain_gui_vizia/src/lib.rs +++ b/plugins/examples/gain_gui_vizia/src/lib.rs @@ -96,7 +96,7 @@ impl Plugin for Gain { self.params.clone() } - fn editor(&self, _async_executor: AsyncExecutor) -> Option> { + fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { editor::create( self.params.clone(), self.peak_meter.clone(), diff --git a/plugins/spectral_compressor/src/lib.rs b/plugins/spectral_compressor/src/lib.rs index 39277492..b5e81b50 100644 --- a/plugins/spectral_compressor/src/lib.rs +++ b/plugins/spectral_compressor/src/lib.rs @@ -317,7 +317,7 @@ impl Plugin for SpectralCompressor { self.params.clone() } - fn editor(&self, _async_executor: AsyncExecutor) -> Option> { + fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { editor::create( self.params.editor_state.clone(), editor::Data { diff --git a/src/plugin.rs b/src/plugin.rs index b36399f1..a7132391 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -131,25 +131,36 @@ pub trait Plugin: Default + Send + 'static { // NOTE: Sadly it's not yet possible to default this and the `async_executor()` function to // `()`: https://github.com/rust-lang/rust/issues/29661 type BackgroundTask: Send; - /// A function that executes the plugin's tasks. Queried once when the plugin instance is - /// created. See [`BackgroundTask`][Self::BackgroundTask]. - fn task_executor(&self) -> TaskExecutor { + /// A function that executes the plugin's tasks. When implementing this you will likely want to + /// pattern match on the task type, and then send any resulting data back over a channel or + /// triple buffer. See [`BackgroundTask`][Self::BackgroundTask]. + /// + /// Queried only once immediately after the plugin instance is created. This function takes + /// `&mut self` to make it easier to move data into the closure. + fn task_executor(&mut self) -> TaskExecutor { // In the default implementation we can simply ignore the value Box::new(|_| ()) } /// The plugin's parameters. The host will update the parameter values before calling - /// `process()`. These parameters are identified by strings that should never change when the - /// plugin receives an update. + /// `process()`. These string parameter IDs parameters should never change as they are used to + /// distinguish between parameters. + /// + /// Queried only once immediately after the plugin instance is created. fn params(&self) -> Arc; - /// 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 - /// [`GuiContext`][crate::prelude::GuiContext] and [`ParamSetter`][crate::prelude::ParamSetter] after the editor - /// GUI has been created. - fn editor(&self, async_executor: AsyncExecutor) -> Option> { + /// Returns an extension struct for interacting with the plugin's editor, if it has one. Later + /// the host may call [`Editor::spawn()`] to create an editor instance. To read the current + /// parameter values, you will need to clone and move the `Arc` containing your `Params` object + /// into the editor. You can later modify the parameters through the + /// [`GuiContext`][crate::prelude::GuiContext] and [`ParamSetter`][crate::prelude::ParamSetter] + /// after the editor GUI has been created. NIH-plug comes with wrappers for several common GUI + /// frameworks that may have their own ways of interacting with parameters. See the repo's + /// readme for more information. + /// + /// Queried only once immediately after the plugin instance is created. This function takes + /// `&mut self` to make it easier to move data into the `Editor` implementation. + fn editor(&mut self, async_executor: AsyncExecutor) -> Option> { None } diff --git a/src/wrapper/clap/wrapper.rs b/src/wrapper/clap/wrapper.rs index 63867a3b..a05837da 100644 --- a/src/wrapper/clap/wrapper.rs +++ b/src/wrapper/clap/wrapper.rs @@ -426,7 +426,7 @@ impl MainThreadExecutor> for Wrapper

{ impl Wrapper

{ pub fn new(host_callback: *const clap_host) -> Arc { - let plugin = P::default(); + let mut plugin = P::default(); let task_executor = Mutex::new(plugin.task_executor()); // This is used to allow the plugin to restore preset data from its editor, see the comment diff --git a/src/wrapper/standalone/wrapper.rs b/src/wrapper/standalone/wrapper.rs index 5480bcea..5682b950 100644 --- a/src/wrapper/standalone/wrapper.rs +++ b/src/wrapper/standalone/wrapper.rs @@ -181,7 +181,7 @@ impl> Wrapper { // the config itself. Right now clap doesn't support this. let audio_io_layout = config.audio_io_layout_or_exit::

(); - let plugin = P::default(); + let mut plugin = P::default(); let task_executor = Mutex::new(plugin.task_executor()); let params = plugin.params(); diff --git a/src/wrapper/vst3/inner.rs b/src/wrapper/vst3/inner.rs index f911d308..add0a1a1 100644 --- a/src/wrapper/vst3/inner.rs +++ b/src/wrapper/vst3/inner.rs @@ -188,7 +188,7 @@ pub enum ProcessEvent { impl WrapperInner

{ #[allow(unused_unsafe)] pub fn new() -> Arc { - let plugin = P::default(); + let mut plugin = P::default(); let task_executor = Mutex::new(plugin.task_executor()); // This is used to allow the plugin to restore preset data from its editor, see the comment