Also defer latency change for CLAP plugins
In case a future host does the same thing Ardour does right now for VST3 plugins.
This commit is contained in:
parent
5cbef6ec03
commit
069053ca50
|
@ -1,4 +1,5 @@
|
|||
use atomic_refcell::AtomicRefMut;
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -13,8 +14,22 @@ use crate::params::internals::ParamPtr;
|
|||
use crate::plugin::ClapPlugin;
|
||||
|
||||
/// An [`InitContext`] implementation for the wrapper.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// See the VST3 `WrapperInitContext` for an explanation of why we need this `pending_requests`
|
||||
/// field.
|
||||
pub(crate) struct WrapperInitContext<'a, P: ClapPlugin> {
|
||||
pub(super) wrapper: &'a Wrapper<P>,
|
||||
pub(super) pending_requests: PendingInitContextRequests,
|
||||
}
|
||||
|
||||
/// Any requests that should be sent out when the [`WrapperInitContext`] is dropped. See that
|
||||
/// struct's docstring for mroe information.
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct PendingInitContextRequests {
|
||||
/// The value of the last `.set_latency_samples()` call.
|
||||
latency_changed: Cell<Option<u32>>,
|
||||
}
|
||||
|
||||
/// A [`ProcessContext`] implementation for the wrapper. This is a separate object so it can hold on
|
||||
|
@ -34,6 +49,14 @@ pub(crate) struct WrapperGuiContext<P: ClapPlugin> {
|
|||
pub(super) wrapper: Arc<Wrapper<P>>,
|
||||
}
|
||||
|
||||
impl<P: ClapPlugin> Drop for WrapperInitContext<'_, P> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(samples) = self.pending_requests.latency_changed.take() {
|
||||
self.wrapper.set_latency_samples(samples)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: ClapPlugin> InitContext<P> for WrapperInitContext<'_, P> {
|
||||
fn plugin_api(&self) -> PluginApi {
|
||||
PluginApi::Clap
|
||||
|
@ -44,7 +67,8 @@ impl<P: ClapPlugin> InitContext<P> for WrapperInitContext<'_, P> {
|
|||
}
|
||||
|
||||
fn set_latency_samples(&self, samples: u32) {
|
||||
self.wrapper.set_latency_samples(samples)
|
||||
// See this struct's docstring
|
||||
self.pending_requests.latency_changed.set(Some(samples));
|
||||
}
|
||||
|
||||
fn set_current_voice_capacity(&self, capacity: u32) {
|
||||
|
|
|
@ -732,8 +732,15 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
Arc::new(WrapperGuiContext { wrapper: self })
|
||||
}
|
||||
|
||||
/// # Note
|
||||
///
|
||||
/// The lock on the plugin must be dropped before this object is dropped to avoid deadlocks
|
||||
/// caused by reentrant function calls.
|
||||
fn make_init_context(&self) -> WrapperInitContext<'_, P> {
|
||||
WrapperInitContext { wrapper: self }
|
||||
WrapperInitContext {
|
||||
wrapper: self,
|
||||
pending_requests: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_process_context(&self, transport: Transport) -> WrapperProcessContext<'_, P> {
|
||||
|
@ -1668,8 +1675,10 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
self.notify_param_values_changed();
|
||||
let bus_config = self.current_bus_config.load();
|
||||
if let Some(buffer_config) = self.current_buffer_config.load() {
|
||||
// NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks
|
||||
let mut init_context = self.make_init_context();
|
||||
let mut plugin = self.plugin.lock();
|
||||
plugin.initialize(&bus_config, &buffer_config, &mut self.make_init_context());
|
||||
plugin.initialize(&bus_config, &buffer_config, &mut init_context);
|
||||
process_wrapper(|| plugin.reset());
|
||||
}
|
||||
|
||||
|
@ -1767,12 +1776,10 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
param.update_smoother(buffer_config.sample_rate, true);
|
||||
}
|
||||
|
||||
// NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks
|
||||
let mut init_context = wrapper.make_init_context();
|
||||
let mut plugin = wrapper.plugin.lock();
|
||||
if plugin.initialize(
|
||||
&bus_config,
|
||||
&buffer_config,
|
||||
&mut wrapper.make_init_context(),
|
||||
) {
|
||||
if plugin.initialize(&bus_config, &buffer_config, &mut init_context) {
|
||||
// NOTE: `Plugin::reset()` is called in `clap_plugin::start_processing()` instead of in
|
||||
// this function
|
||||
|
||||
|
@ -2310,6 +2317,8 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
|
||||
wrapper.notify_param_values_changed();
|
||||
|
||||
// NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks
|
||||
let mut init_context = wrapper.make_init_context();
|
||||
let bus_config = wrapper.current_bus_config.load();
|
||||
let buffer_config = wrapper.current_buffer_config.load().unwrap();
|
||||
let mut plugin = wrapper.plugin.lock();
|
||||
|
@ -2317,13 +2326,7 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
// this could lead to inconsistencies. It's the plugin's responsibility to
|
||||
// not perform any realtime-unsafe work when the initialize function is
|
||||
// called a second time if it supports runtime preset loading.
|
||||
permit_alloc(|| {
|
||||
plugin.initialize(
|
||||
&bus_config,
|
||||
&buffer_config,
|
||||
&mut wrapper.make_init_context(),
|
||||
)
|
||||
});
|
||||
permit_alloc(|| plugin.initialize(&bus_config, &buffer_config, &mut init_context));
|
||||
plugin.reset();
|
||||
|
||||
// We'll pass the state object back to the GUI thread so deallocation can happen
|
||||
|
@ -3218,12 +3221,10 @@ impl<P: ClapPlugin> Wrapper<P> {
|
|||
|
||||
let bus_config = wrapper.current_bus_config.load();
|
||||
if let Some(buffer_config) = wrapper.current_buffer_config.load() {
|
||||
// NOTE: This needs to be dropped after the `plugin` lock to avoid deadlocks
|
||||
let mut init_context = wrapper.make_init_context();
|
||||
let mut plugin = wrapper.plugin.lock();
|
||||
plugin.initialize(
|
||||
&bus_config,
|
||||
&buffer_config,
|
||||
&mut wrapper.make_init_context(),
|
||||
);
|
||||
plugin.initialize(&bus_config, &buffer_config, &mut init_context);
|
||||
// TODO: This also goes for the VST3 version, but should we call reset here? Won't the
|
||||
// host always restart playback? Check this with a couple of hosts and remove the
|
||||
// duplicate reset if it's not needed.
|
||||
|
|
Loading…
Reference in a new issue