Use the host's run loop to handle VST3 tasks
This commit is contained in:
parent
37b62e4278
commit
98924a5728
|
@ -6,7 +6,6 @@ use vst3_sys::vst::{IComponentHandler, RestartFlags};
|
|||
|
||||
use super::inner::{Task, WrapperInner};
|
||||
use crate::context::{GuiContext, ProcessContext, Transport};
|
||||
use crate::event_loop::EventLoop;
|
||||
use crate::midi::NoteEvent;
|
||||
use crate::param::internals::ParamPtr;
|
||||
use crate::plugin::Vst3Plugin;
|
||||
|
@ -117,7 +116,8 @@ impl<P: Vst3Plugin> ProcessContext for WrapperProcessContext<'_, P> {
|
|||
// Only trigger a restart if it's actually needed
|
||||
let old_latency = self.inner.current_latency.swap(samples, Ordering::SeqCst);
|
||||
if old_latency != samples {
|
||||
let task_posted = unsafe { self.inner.event_loop.borrow().assume_init_ref() }
|
||||
let task_posted = self
|
||||
.inner
|
||||
.do_maybe_async(Task::TriggerRestart(RestartFlags::kLatencyChanged as i32));
|
||||
nih_debug_assert!(task_posted, "The task queue is full, dropping task...");
|
||||
}
|
||||
|
|
|
@ -49,7 +49,9 @@ pub(crate) struct WrapperInner<P: Vst3Plugin> {
|
|||
pub plug_view: RwLock<Option<ObjectPtr<WrapperView<P>>>>,
|
||||
|
||||
/// A realtime-safe task queue so the plugin can schedule tasks that need to be run later on the
|
||||
/// GUI thread.
|
||||
/// GUI thread. This field should not be used directly for posting tasks. This should be done
|
||||
/// through [`Self::do_maybe_async()`] instead. That method posts the task to the host's
|
||||
/// `IRunLoop` instead of it's available.
|
||||
///
|
||||
/// This RwLock is only needed because it has to be initialized late. There is no reason to
|
||||
/// mutably borrow the event loop, so reads will never be contested.
|
||||
|
@ -312,6 +314,34 @@ impl<P: Vst3Plugin> WrapperInner<P> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Either posts the function to the task queue using [`EventLoop::do_maybe_async()`] so it can
|
||||
/// be delegated to the main thread, executes the task directly if this is the main thread, or
|
||||
/// runs the task on the host's `IRunLoop` if the GUI is open and it exposes one. This function
|
||||
///
|
||||
/// If the task queue is full, then this will return false.
|
||||
#[must_use]
|
||||
pub fn do_maybe_async(&self, task: Task) -> bool {
|
||||
let event_loop = self.event_loop.borrow();
|
||||
let event_loop = unsafe { event_loop.assume_init_ref() };
|
||||
if event_loop.is_main_thread() {
|
||||
unsafe { self.execute(task) };
|
||||
true
|
||||
} else {
|
||||
// If the editor is open, and the host exposes the `IRunLoop` interface, then we'll run
|
||||
// the task on the host's GUI thread using that interface. Otherwise we'll use the
|
||||
// regular eent loop. If the editor gets dropped while there's still outstanding work
|
||||
// left in the run loop task queue, then those tasks will be posted to the regular event
|
||||
// loop so no work is lost.
|
||||
match &*self.plug_view.read() {
|
||||
Some(plug_view) => match plug_view.do_maybe_in_run_loop(task) {
|
||||
Ok(()) => true,
|
||||
Err(task) => event_loop.do_maybe_async(task),
|
||||
},
|
||||
None => event_loop.do_maybe_async(task),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If there's an editor open, let it know that parameter values have changed. This should be
|
||||
/// called whenever there's been a call or multiple calls to
|
||||
/// [`set_normalized_value_by_hash()[Self::set_normalized_value_by_hash()`].
|
||||
|
|
Loading…
Reference in a new issue