Add AsyncExecutor support to InitContext
This commit is contained in:
parent
0d90969566
commit
6ffa23971e
|
@ -6,8 +6,10 @@ new and what's changed, this document lists all breaking changes in reverse
|
||||||
chronological order. If a new feature did not require any changes to existing
|
chronological order. If a new feature did not require any changes to existing
|
||||||
code then it will not be listed here.
|
code then it will not be listed here.
|
||||||
|
|
||||||
## [2022-10-21]
|
## [2022-10-22]
|
||||||
|
|
||||||
|
- The `&mut impl InitContext` argument to `Plugin::initialize()` needs to be
|
||||||
|
changed to `&mut impl InitContext<Self>`.
|
||||||
- NIH-plug has gained support for asynchronously running background tasks in a
|
- NIH-plug has gained support for asynchronously running background tasks in a
|
||||||
simple, type-safe, and realtime-safe way. This sadly does mean that every
|
simple, type-safe, and realtime-safe way. This sadly does mean that every
|
||||||
`Plugin` instance now needs to define an `AsyncExecutor` type definition and
|
`Plugin` instance now needs to define an `AsyncExecutor` type definition and
|
||||||
|
|
|
@ -328,7 +328,7 @@ impl Plugin for Crisp {
|
||||||
&mut self,
|
&mut self,
|
||||||
bus_config: &BusConfig,
|
bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
nih_debug_assert_eq!(bus_config.num_input_channels, NUM_CHANNELS);
|
nih_debug_assert_eq!(bus_config.num_input_channels, NUM_CHANNELS);
|
||||||
nih_debug_assert_eq!(bus_config.num_output_channels, NUM_CHANNELS);
|
nih_debug_assert_eq!(bus_config.num_output_channels, NUM_CHANNELS);
|
||||||
|
|
|
@ -201,7 +201,7 @@ impl Plugin for Crossover {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
context: &mut impl InitContext,
|
context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.buffer_config = *buffer_config;
|
self.buffer_config = *buffer_config;
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ impl Plugin for Diopser {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.sample_rate = buffer_config.sample_rate;
|
self.sample_rate = buffer_config.sample_rate;
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ impl Plugin for Gain {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// After `PEAK_METER_DECAY_MS` milliseconds of pure silence, the peak meter's value should
|
// After `PEAK_METER_DECAY_MS` milliseconds of pure silence, the peak meter's value should
|
||||||
// have dropped by 12 dB
|
// have dropped by 12 dB
|
||||||
|
|
|
@ -104,7 +104,7 @@ impl Plugin for Gain {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// After `PEAK_METER_DECAY_MS` milliseconds of pure silence, the peak meter's value should
|
// After `PEAK_METER_DECAY_MS` milliseconds of pure silence, the peak meter's value should
|
||||||
// have dropped by 12 dB
|
// have dropped by 12 dB
|
||||||
|
|
|
@ -103,7 +103,7 @@ impl Plugin for Gain {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// After `PEAK_METER_DECAY_MS` milliseconds of pure silence, the peak meter's value should
|
// After `PEAK_METER_DECAY_MS` milliseconds of pure silence, the peak meter's value should
|
||||||
// have dropped by 12 dB
|
// have dropped by 12 dB
|
||||||
|
|
|
@ -127,7 +127,7 @@ impl Plugin for Sine {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.sample_rate = buffer_config.sample_rate;
|
self.sample_rate = buffer_config.sample_rate;
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ impl Plugin for Stft {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
_buffer_config: &BufferConfig,
|
_buffer_config: &BufferConfig,
|
||||||
context: &mut impl InitContext,
|
context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// The plugin's latency consists of the block size from the overlap-add procedure and half
|
// The plugin's latency consists of the block size from the overlap-add procedure and half
|
||||||
// of the filter kernel's size (since we're using a linear phase/symmetrical convolution
|
// of the filter kernel's size (since we're using a linear phase/symmetrical convolution
|
||||||
|
|
|
@ -138,7 +138,7 @@ impl Plugin for LoudnessWarWinner {
|
||||||
&mut self,
|
&mut self,
|
||||||
bus_config: &BusConfig,
|
bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.sample_rate = buffer_config.sample_rate;
|
self.sample_rate = buffer_config.sample_rate;
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ impl Plugin for PubertySimulator {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
_buffer_config: &BufferConfig,
|
_buffer_config: &BufferConfig,
|
||||||
context: &mut impl InitContext,
|
context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Planning with RustFFT is very fast, but it will still allocate we we'll plan all of the
|
// Planning with RustFFT is very fast, but it will still allocate we we'll plan all of the
|
||||||
// FFTs we might need in advance
|
// FFTs we might need in advance
|
||||||
|
|
|
@ -172,7 +172,7 @@ impl Plugin for SafetyLimiter {
|
||||||
&mut self,
|
&mut self,
|
||||||
_bus_config: &BusConfig,
|
_bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
_context: &mut impl InitContext,
|
_context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
self.buffer_config = *buffer_config;
|
self.buffer_config = *buffer_config;
|
||||||
self.morse_fadeout_samples_start =
|
self.morse_fadeout_samples_start =
|
||||||
|
|
|
@ -295,7 +295,7 @@ impl Plugin for SpectralCompressor {
|
||||||
&mut self,
|
&mut self,
|
||||||
bus_config: &BusConfig,
|
bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
context: &mut impl InitContext,
|
context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Needed to update the compressors later
|
// Needed to update the compressors later
|
||||||
self.buffer_config = *buffer_config;
|
self.buffer_config = *buffer_config;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
/// Something that can run tasks of type [`Task`][Self::Task]. This can be used to defer expensive
|
/// Something that can run tasks of type [`Task`][Self::Task]. This can be used to defer expensive
|
||||||
/// computations to a background thread. Tasks can be spawned through the methods on the various
|
/// computations to a background thread. Tasks can be spawned through the methods on the various
|
||||||
/// [`*Context`][crate::context] types.
|
/// [`*Context`][crate::context] types.
|
||||||
pub trait AsyncExecutor {
|
pub trait AsyncExecutor: Send + Sync {
|
||||||
/// The type of task this executor can execute. This is usually an enum type. The task type
|
/// The type of task this executor can execute. This is usually an enum type. The task type
|
||||||
/// should not contain any heap allocated data like [`Vec`]s and [`Box`]es.
|
/// should not contain any heap allocated data like [`Vec`]s and [`Box`]es.
|
||||||
type Task;
|
type Task;
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::fmt::Display;
|
||||||
use crate::midi::NoteEvent;
|
use crate::midi::NoteEvent;
|
||||||
use crate::params::internals::ParamPtr;
|
use crate::params::internals::ParamPtr;
|
||||||
use crate::params::Param;
|
use crate::params::Param;
|
||||||
|
use crate::prelude::{AsyncExecutor, Plugin};
|
||||||
use crate::wrapper::state::PluginState;
|
use crate::wrapper::state::PluginState;
|
||||||
|
|
||||||
/// Callbacks the plugin can make while it is being initialized. This is passed to the plugin during
|
/// Callbacks the plugin can make while it is being initialized. This is passed to the plugin during
|
||||||
|
@ -14,7 +15,16 @@ use crate::wrapper::state::PluginState;
|
||||||
//
|
//
|
||||||
// The implementing wrapper needs to be able to handle concurrent requests, and it should perform
|
// The implementing wrapper needs to be able to handle concurrent requests, and it should perform
|
||||||
// the actual callback within [MainThreadQueue::do_maybe_async].
|
// the actual callback within [MainThreadQueue::do_maybe_async].
|
||||||
pub trait InitContext {
|
pub trait InitContext<P: Plugin> {
|
||||||
|
/// Run a task directly on this thread. This ensures that the task has finished executing before
|
||||||
|
/// the plugin finishes initializing.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// There is no asynchronous alternative for this function as that may result in incorrect
|
||||||
|
/// behavior when doing offline rendering.
|
||||||
|
fn execute(&self, task: <P::AsyncExecutor as AsyncExecutor>::Task);
|
||||||
|
|
||||||
/// Get the current plugin API.
|
/// Get the current plugin API.
|
||||||
fn plugin_api(&self) -> PluginApi;
|
fn plugin_api(&self) -> PluginApi;
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,7 @@ pub trait Plugin: Default + Send + 'static {
|
||||||
&mut self,
|
&mut self,
|
||||||
bus_config: &BusConfig,
|
bus_config: &BusConfig,
|
||||||
buffer_config: &BufferConfig,
|
buffer_config: &BufferConfig,
|
||||||
context: &mut impl InitContext,
|
context: &mut impl InitContext<Self>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::collections::VecDeque;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::wrapper::{OutputParamEvent, Wrapper};
|
use super::wrapper::{OutputParamEvent, Wrapper};
|
||||||
|
use crate::async_executor::AsyncExecutor;
|
||||||
use crate::context::{GuiContext, InitContext, PluginApi, ProcessContext, Transport};
|
use crate::context::{GuiContext, InitContext, PluginApi, ProcessContext, Transport};
|
||||||
use crate::midi::NoteEvent;
|
use crate::midi::NoteEvent;
|
||||||
use crate::params::internals::ParamPtr;
|
use crate::params::internals::ParamPtr;
|
||||||
|
@ -112,7 +113,11 @@ impl<P: ClapPlugin> GuiContext for WrapperGuiContext<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: ClapPlugin> InitContext for WrapperInitContext<'_, P> {
|
impl<P: ClapPlugin> InitContext<P> for WrapperInitContext<'_, P> {
|
||||||
|
fn execute(&self, task: <P::AsyncExecutor as crate::prelude::AsyncExecutor>::Task) {
|
||||||
|
self.wrapper.async_executor.execute(task);
|
||||||
|
}
|
||||||
|
|
||||||
fn plugin_api(&self) -> PluginApi {
|
fn plugin_api(&self) -> PluginApi {
|
||||||
PluginApi::Clap
|
PluginApi::Clap
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,8 @@ pub struct Wrapper<P: ClapPlugin> {
|
||||||
|
|
||||||
/// The wrapped plugin instance.
|
/// The wrapped plugin instance.
|
||||||
plugin: Mutex<P>,
|
plugin: Mutex<P>,
|
||||||
|
/// The plugin's background task executor.
|
||||||
|
pub async_executor: P::AsyncExecutor,
|
||||||
/// The plugin's parameters. These are fetched once during initialization. That way the
|
/// The plugin's parameters. These are fetched once during initialization. That way the
|
||||||
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
||||||
/// the `Params` object without having to acquire a lock on `plugin`.
|
/// the `Params` object without having to acquire a lock on `plugin`.
|
||||||
|
@ -381,6 +383,7 @@ impl<P: ClapPlugin> MainThreadExecutor<Task> for Wrapper<P> {
|
||||||
impl<P: ClapPlugin> Wrapper<P> {
|
impl<P: ClapPlugin> Wrapper<P> {
|
||||||
pub fn new(host_callback: *const clap_host) -> Arc<Self> {
|
pub fn new(host_callback: *const clap_host) -> Arc<Self> {
|
||||||
let plugin = P::default();
|
let plugin = P::default();
|
||||||
|
let async_executor = plugin.async_executor();
|
||||||
let editor = plugin.editor().map(Mutex::new);
|
let editor = plugin.editor().map(Mutex::new);
|
||||||
|
|
||||||
// This is used to allow the plugin to restore preset data from its editor, see the comment
|
// This is used to allow the plugin to restore preset data from its editor, see the comment
|
||||||
|
@ -542,6 +545,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
||||||
this: AtomicRefCell::new(Weak::new()),
|
this: AtomicRefCell::new(Weak::new()),
|
||||||
|
|
||||||
plugin: Mutex::new(plugin),
|
plugin: Mutex::new(plugin),
|
||||||
|
async_executor,
|
||||||
params,
|
params,
|
||||||
editor,
|
editor,
|
||||||
editor_handle: Mutex::new(None),
|
editor_handle: Mutex::new(None),
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use super::backend::Backend;
|
use super::backend::Backend;
|
||||||
use super::wrapper::{GuiTask, Wrapper};
|
use super::wrapper::{GuiTask, Wrapper};
|
||||||
|
use crate::async_executor::AsyncExecutor;
|
||||||
use crate::context::{GuiContext, InitContext, PluginApi, ProcessContext, Transport};
|
use crate::context::{GuiContext, InitContext, PluginApi, ProcessContext, Transport};
|
||||||
use crate::midi::NoteEvent;
|
use crate::midi::NoteEvent;
|
||||||
use crate::params::internals::ParamPtr;
|
use crate::params::internals::ParamPtr;
|
||||||
|
@ -23,7 +24,6 @@ pub(crate) struct WrapperGuiContext<P: Plugin, B: Backend> {
|
||||||
/// can hold on to lock guards for event queues. Otherwise reading these events would require
|
/// can hold on to lock guards for event queues. Otherwise reading these events would require
|
||||||
/// constant unnecessary atomic operations to lock the uncontested RwLocks.
|
/// constant unnecessary atomic operations to lock the uncontested RwLocks.
|
||||||
pub(crate) struct WrapperInitContext<'a, P: Plugin, B: Backend> {
|
pub(crate) struct WrapperInitContext<'a, P: Plugin, B: Backend> {
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(super) wrapper: &'a Wrapper<P, B>,
|
pub(super) wrapper: &'a Wrapper<P, B>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,11 @@ impl<P: Plugin, B: Backend> GuiContext for WrapperGuiContext<P, B> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Plugin, B: Backend> InitContext for WrapperInitContext<'_, P, B> {
|
impl<P: Plugin, B: Backend> InitContext<P> for WrapperInitContext<'_, P, B> {
|
||||||
|
fn execute(&self, task: <<P as Plugin>::AsyncExecutor as crate::prelude::AsyncExecutor>::Task) {
|
||||||
|
self.wrapper.async_executor.execute(task);
|
||||||
|
}
|
||||||
|
|
||||||
fn plugin_api(&self) -> PluginApi {
|
fn plugin_api(&self) -> PluginApi {
|
||||||
PluginApi::Standalone
|
PluginApi::Standalone
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ pub struct Wrapper<P: Plugin, B: Backend> {
|
||||||
|
|
||||||
/// The wrapped plugin instance.
|
/// The wrapped plugin instance.
|
||||||
plugin: Mutex<P>,
|
plugin: Mutex<P>,
|
||||||
|
/// The plugin's background task executor.
|
||||||
|
pub async_executor: P::AsyncExecutor,
|
||||||
/// The plugin's parameters. These are fetched once during initialization. That way the
|
/// The plugin's parameters. These are fetched once during initialization. That way the
|
||||||
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
||||||
/// the `Params` object without having to acquire a lock on `plugin`.
|
/// the `Params` object without having to acquire a lock on `plugin`.
|
||||||
|
@ -132,6 +134,7 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
|
||||||
/// not accept the IO configuration from the wrapper config.
|
/// not accept the IO configuration from the wrapper config.
|
||||||
pub fn new(backend: B, config: WrapperConfig) -> Result<Arc<Self>, WrapperError> {
|
pub fn new(backend: B, config: WrapperConfig) -> Result<Arc<Self>, WrapperError> {
|
||||||
let plugin = P::default();
|
let plugin = P::default();
|
||||||
|
let async_executor = plugin.async_executor();
|
||||||
let params = plugin.params();
|
let params = plugin.params();
|
||||||
let editor = plugin.editor().map(|editor| Arc::new(Mutex::new(editor)));
|
let editor = plugin.editor().map(|editor| Arc::new(Mutex::new(editor)));
|
||||||
|
|
||||||
|
@ -178,6 +181,7 @@ impl<P: Plugin, B: Backend> Wrapper<P, B> {
|
||||||
backend: AtomicRefCell::new(backend),
|
backend: AtomicRefCell::new(backend),
|
||||||
|
|
||||||
plugin: Mutex::new(plugin),
|
plugin: Mutex::new(plugin),
|
||||||
|
async_executor,
|
||||||
params,
|
params,
|
||||||
known_parameters: param_map.iter().map(|(_, ptr, _)| *ptr).collect(),
|
known_parameters: param_map.iter().map(|(_, ptr, _)| *ptr).collect(),
|
||||||
param_map: param_map
|
param_map: param_map
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::sync::Arc;
|
||||||
use vst3_sys::vst::IComponentHandler;
|
use vst3_sys::vst::IComponentHandler;
|
||||||
|
|
||||||
use super::inner::{Task, WrapperInner};
|
use super::inner::{Task, WrapperInner};
|
||||||
|
use crate::async_executor::AsyncExecutor;
|
||||||
use crate::context::{GuiContext, InitContext, PluginApi, ProcessContext, Transport};
|
use crate::context::{GuiContext, InitContext, PluginApi, ProcessContext, Transport};
|
||||||
use crate::midi::NoteEvent;
|
use crate::midi::NoteEvent;
|
||||||
use crate::params::internals::ParamPtr;
|
use crate::params::internals::ParamPtr;
|
||||||
|
@ -115,7 +116,11 @@ impl<P: Vst3Plugin> GuiContext for WrapperGuiContext<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Vst3Plugin> InitContext for WrapperInitContext<'_, P> {
|
impl<P: Vst3Plugin> InitContext<P> for WrapperInitContext<'_, P> {
|
||||||
|
fn execute(&self, task: <P::AsyncExecutor as crate::prelude::AsyncExecutor>::Task) {
|
||||||
|
self.inner.async_executor.execute(task);
|
||||||
|
}
|
||||||
|
|
||||||
fn plugin_api(&self) -> PluginApi {
|
fn plugin_api(&self) -> PluginApi {
|
||||||
PluginApi::Vst3
|
PluginApi::Vst3
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ use crate::wrapper::util::{hash_param_id, process_wrapper};
|
||||||
pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
||||||
/// The wrapped plugin instance.
|
/// The wrapped plugin instance.
|
||||||
pub plugin: Mutex<P>,
|
pub plugin: Mutex<P>,
|
||||||
|
/// The plugin's background task executor.
|
||||||
|
pub async_executor: P::AsyncExecutor,
|
||||||
/// The plugin's parameters. These are fetched once during initialization. That way the
|
/// The plugin's parameters. These are fetched once during initialization. That way the
|
||||||
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
/// `ParamPtr`s are guaranteed to live at least as long as this object and we can interact with
|
||||||
/// the `Params` object without having to acquire a lock on `plugin`.
|
/// the `Params` object without having to acquire a lock on `plugin`.
|
||||||
|
@ -191,6 +193,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
||||||
#[allow(unused_unsafe)]
|
#[allow(unused_unsafe)]
|
||||||
pub fn new() -> Arc<Self> {
|
pub fn new() -> Arc<Self> {
|
||||||
let plugin = P::default();
|
let plugin = P::default();
|
||||||
|
let async_executor = plugin.async_executor();
|
||||||
let editor = plugin.editor().map(|editor| Arc::new(Mutex::new(editor)));
|
let editor = plugin.editor().map(|editor| Arc::new(Mutex::new(editor)));
|
||||||
|
|
||||||
// This is used to allow the plugin to restore preset data from its editor, see the comment
|
// This is used to allow the plugin to restore preset data from its editor, see the comment
|
||||||
|
@ -274,6 +277,7 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
||||||
|
|
||||||
let wrapper = Self {
|
let wrapper = Self {
|
||||||
plugin: Mutex::new(plugin),
|
plugin: Mutex::new(plugin),
|
||||||
|
async_executor,
|
||||||
params,
|
params,
|
||||||
editor,
|
editor,
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue